Lowlevel
Lowlevel => Lowlevel-Coding => Thema gestartet von: openglfreak am 29. December 2014, 01:32
-
Ich habe versucht einen bootloader zu programmieren, doch der Sprung nach dem aktivieren des Protected Mode führt an Adresse 0xB866, obwohl er da nicht hin soll :-(.
Ich hab' den code bereits gefühlte 10000h mal gecheckt doch habe keinen Fehler gefunden :? :cry:
Wo ist der Fehler? :x
(Compiliert mit nasm, debuggt mit bochs und gdb)
[global main16]
[section .text]
[BITS 16]
main16:
cli
mov byte [bootdrive],dl
xor ax,ax
mov ds,ax
mov ss,ax
mov ebp,(main32-0xFF)
mov esp,(main32-0x01)
initdrive:
xor ah,ah
int 0x13
jc error16
load:
mov byte dl,[bootdrive]
mov ah,0x02
mov al,nsectors
xor dh,dh
xor ch,ch
mov cl,0x02
mov bx,(main32>>0x04)
mov es,bx
mov bx,(main32&0x0F)
int 0x13
jc error16
initgdt:
mov ecx,(gdt_template_end-gdt_template)
copytemplate:
dec ecx
mov byte bl,[gdt_template+ecx]
mov byte [gdt_start+ecx],bl
test ecx,ecx
jnz copytemplate
initgdtr:
mov word [gdtr],(gdt_template_end-gdt_template-1)
%line 20+1 loader.asm
lgdt [gdtr]
jmp switchpmode
error16:
jmp $
switchpmode:
mov eax,cr0
or eax,0x01
mov cr0,eax
%line 27+1 loader.asm
mov ax,codeseg
mov es,ax
jmp [es:b32]
[Bits 32]
b32:
mov ax,dataseg
mov ds,ax
mov ss,ax
mov ebp,(main32-0xFF)
mov esp,(main32-0x01)
jmp $
;Some stuff + jumping to main32
nsectors equ 0x08
main32 equ (0x10000-(nsectors*0x0200))
bootdrive equ 0x7BFF
gdt_start equ 0x9000
gdt_end equ 0xB000
gdtr:
dw gdt_end-gdt_start-1
dd gdt_start
gdt_template:
nullseg equ 0
dd 0x00000000, 0x00000000
codeseg equ $-gdt_template
dw 0xFFFF
dw 0x0000
db 0x00
db 0x9A
db 0xCF
db 0x00
dataseg equ $-gdt_template
dw 0xFFFF
dw 0x0000
db 0x00
db 0x92
db 0xCF
db 0x00
gdt_template_end:
times (0x01FE)-($-$$) db 0x00
db 0x55
db 0xAA
-
Moin!
jmp [es:b32]
[Bits 32]
b32:
mov ax,dataseg
Das mov ax,dataseg wird zu irgendwas assembliert, das mit den Bytes 0x66, 0xB8, ... beginnt. Der Sprung jmp [es:b32] ist ein indirekter Sprung, das heißt er liest den Speicher an Adresse b32 aus, anstatt nach b32 zu springen. Dort steht die eben genannte Instruktion, die als Adresse interpretiert wird, wodurch die CPU bei 0xB866 landet. (x86 ist Little Endian, deswegen sind die vertauscht.)
Bei einem far-jump kannst du kein Segmentregister angeben. Entweder du kodierst die Adresse hart, vermutlich sowas wie jmp 0x08:(0x7c00 + b32), falls der Assembler das schluckt Oder du machst das über den Stack:
push es
push b32 + 0x7c00
retf
Das 0x7c00 musst du vermutlich addieren, weil du annimmst, dass der Bootloader an Offset 0 (in Segment 0x7c0), geladen wird (statt 0x7c00 in Segment 0). (Das erkenne ich daran, dass du die ORG-Instruktion weggelassen hast, wodurch ORG 0 impliziert ist.) Übrigens heißt das auch, dass du beispielsweise die Variable bootdrive bei "load:" nicht korrekt ausliest, nachdem du ds auf 0 gesetzt hast. Vermutlich wird dadurch auch der restliche Code nicht funktionieren. Ich kann natürlich eine ewige Ausführung über Speicheradressierung im Real Mode schreiben, falls du das benötigst, aber ich würde vorschlagen du schlägst erstmal im NASM-Handbuch die ORG-Instruktion nach, und machst dir dann Gedanken, ob 1. du, 2. der Assembler, 3. die CPU alle dieselbe Vorstellung von dem Inhalt der Segmentregister haben, und ob diese korrekt ist.
-
Danke, das mit dem push und retf funktioniert (Das andere ist mir nicht so sympathisch).
Allerdings brauche ich das ORG 0x7C00 nicht, denn ich compiliere mit
nasm -f elf -g -o loader.o loader.asm
erstmal zu einer elf-i386 und dann mit
ld -melf_i386 -A i386 --oformat binary -o loader.bin loader.o -Ttext=0x7C00 -e main16
zu einer binary. Dadurch habe ich auch gleich die debug-infos.
-
Ah ich verstehe. Das sieht man auch nicht so oft.