2015-09-10 41 views
11

udało mi się stworzyć minimalny sektor startowy, który współpracuje z QEMU 2.0.0 Ubuntu 14.04:Jak stworzyć minimalny sektor rozruchowy boot world z GCC, który działa z pamięci USB na prawdziwym sprzęcie?

.code16 
.global _start 
_start: 
    cli 
    mov $msg, %si 
    mov $0x0e, %ah 
loop: 
    lodsb 
    or %al, %al 
    jz halt 
    int $0x10 
    jmp loop 
halt: 
    hlt 
msg: 
    .asciz "hello world" 
.org 510 
.word 0xaa55 

skompilowany z:

as -o main.o main.S 
ld --oformat binary -o main.img -Ttext 0x7C00 main.o 

Przykładem jest dostępny na tym repo: https://github.com/cirosantilli/x86-bare-metal-examples/tree/2b79ac21df801fbf4619d009411be6b9cd10e6e0/no-ld-script

Po:

qemu -hda main.img 

pokazuje hello world na ekranie emulatora zgodnie z oczekiwaniami.

Ale gdy próbuję nagrać na USB:

sudo dd if=main.img of=/dev/sdb 

następnie podłączyć urządzenie USB do ThinkPad T400 i T430, uderzył F12 i wybierz USB, co obserwuję to:

  • Niektóre komunikaty startowe pokazać się szybko
  • następnie ekran gaśnie, tylko z kursorem podkreślenia w górnym

Przetestowałem również ten sam port USB z obrazem Ubuntu 14.04, i uruchomiłem go poprawnie, więc USB działa.

Jak zmienić ten przykład, aby uruchamiał się na sprzęcie i wyświetlał komunikat "Cześć świat"?

Jaka jest różnica między obrazem systemu Ubuntu a tym, który utworzyłem?

Gdzie jest to udokumentowane?

Wysłałem wyjście sudo dmidecode na T400 do: https://gist.github.com/cirosantilli/d47d35bacc9be588009f#file-lenovo-t400

+6

Jako absolutne minimum należy wyzerować 'DS'. – Jester

+4

Oprócz ustawienia 'DS', powinieneś jawnie ustawić segment stosu (' SS'), szczególnie jeśli zaczniesz używać procedur BIOS. Masz też trochę szczęścia, ponieważ QEMU i inne emulatory są o wiele ładniejsze, gdy zadzwonią do twojego kodu startowego. Segment 'CS' niekoniecznie musi być równy 0, kiedy bios wywoła twój bootloader. Element _segment: offset_ będzie równoważny z 0x0000: 0x7c00, ale "CS" może być inne wartości, takie jak 0x07c0 (0x07c0: 0x0000). Aby ominąć to, powinieneś zrobić daleko jmp na etykiecie w kodzie z 'CS' ustawionym na 0x0000. Na prawdziwym sprzęcie może to stanowić problem. –

+0

@MichaelPetch dzięki za dalsze wskazówki! Czuję się bardziej nieszczęśliwy, że QEMU nie dokładnie emuluje mój sprzęt :-) Przeanalizuję segmenty rejestru, o których wspomniałeś bliżej. Nigdy wcześniej ich nie rozumiałem, ponieważ system operacyjny ukrył je przed mną. –

Odpowiedz

7

Jak wspomniano przez @Jester, miałem zero DS z:

@@ -4,2 +4,4 @@ _start: 
    cli 
+ xor %ax, %ax 
+ mov %ax, %ds 
    mov $msg, %si 

pamiętać, że nie jest możliwe mov immediates do ds: musimy przejść przez ax: 8086- why can't we move an immediate data into segment register?

Więc przyczyną problemu było differenc e między stanem początkowym QEMU a stanem rzeczywistym sprzętu.

Dodaję teraz następujący 16-bitowy kod inicjujący do wszystkich moich programów ładujących, aby zagwarantować czystszy stan początkowy. Nie wszystkie z nich są obowiązkowe, jak wspomniał Michael Petch o komentarzach.

.code16 
cli 
/* This sets %cs to 0. TODO Is that really needed? */ 
ljmp $0, $1f 
1: 
xor %ax, %ax 
/* We must zero %ds for any data access. */ 
mov %ax, %ds 
/* The other segments are not mandatory. TODO source */ 
mov %ax, %es 
mov %ax, %fs 
mov %ax, %gs 
/* 
TODO What to move into BP and SP? https://stackoverflow.com/questions/10598802/which-value-should-be-used-for-sp-for-booting-process 
Setting BP does not seem mandatory for BIOS. 
*/ 
mov %ax, %bp 
/* Automatically disables interrupts until the end of the next instruction. */ 
mov %ax, %ss 
/* We should set SP because BIOS calls may depend on that. TODO confirm. */ 
mov %bp, %sp 

Odkryłem także to ściśle związane pytanie: C Kernel - Works fine on VM but not actual computer?

Intel Manual Volume 3 System Programming Guide - 325384-056US September 2015 9.10.2 "STARTUP.ASM Zamieszczone " zawiera dużą przykład inicjalizacji.

+1

Wskazówka: Aby wyzerować rejestry, należy użyć 'xor% reg,% reg'. Zmniejsza to długość kodu maszynowego z trzech do jednego bajtu i jest szybszy w przypadku nowoczesnych 8086 kompatybilnych urządzeń. Po prostu użyj 'xor% ax,% ax' zamiast' mov $ 0,% ax'. – fuz

+0

@FUZxxl dzięki! Widziałem już to na http://stackoverflow.com/questions/1135679/does-using-xor-reg-reg-give-advantage-over-mov-reg-0, ale nie weszło w mój nałóg: -) Naprawiony. –

+2

Procedury BIOS nie wymagają ustawiania FS i GS. ES nie musi być ustawiony, chyba że określona procedura BIOSu wymaga tego jako części parametru przekazywanego. –