Ich versuche, von meinem Bootloader zu meinem geladenen Kernel nach dem Umschalten in den geschützten Modus zu springen.Assembly Anruf auf falsche Adresse
Der Kernel lädt gut und ist an der richtigen Stelle, aber wenn die zweite Stufe des Loader ruft die Hauptfunktion des Kernels ruft es die falsche Adresse. Hier
ist die zweite Stufe des Laders (loader.asm
):
global load_kern
extern main
[bits 32]
load_kern:
call main
cli
hlt
ich dann montieren und diese Verbindung mit ac Objektdatei eine Elf ausführbare Datei zu erstellen:
nasm -f elf32 loader.asm -o loader.o
ld -melf_i386 -n -Tos.lds loader.o os.o -o kernel.elf
Ich benutze diese Datei sie verlinken:
ENTRY(load_kern);
PHDRS
{
headers PT_PHDR FILEHDR PHDRS;
code PT_LOAD;
}
SECTIONS
{
.text 0x500: ALIGN(0x100) { *(.text) } :code
.data : { *(.data) }
.bss : { *(.bss) }
/DISCARD/ : { *(.eh_frame) }
}
ich stelle dann diese kernel.elf
im 2n d Sektor meines Disketten-Images (nach dem Bootsektor).
Wenn ich kernel.elf
objdump die Ausgabe korrekt ist:
os/kernel.elf: file format elf32-i386
Disassembly of section .text:
00000500 <load_kern>:
500: e8 43 00 00 00 call 548 <main>
505: fa cli
506: f4 hlt
...
00000548 <main>:
548: 55 push %ebp
549: 89 e5 mov %esp,%ebp
54b: 68 5c 05 00 00 push $0x55c
550: 6a 05 push $0x5
552: e8 b0 ff ff ff call 507 <write_string>
557: 83 c4 08 add $0x8,%esp
55a: eb fe jmp 55a <main+0x12>
Die Adresse der Haupt fein abgebildet zu werden scheint, aber wenn ich meinen Kernel Sektor laden und es springen das ist, was gdb zeigt:
┌─────────────────────────────────────────────────────────────────┐
>│0x600 call 0x646 │
│0x603 add BYTE PTR [bx+si],al │
│0x605 cli │
│0x606 hlt
...
│0x646 leave │
│0x647 ret │
│0x648 push bp │
│0x649 mov bp,sp │
│0x64b push 0x55c |
Der Kernel wird um 0x500 geladen, aber der Textabschnitt der Datei hat eine Ausrichtung von 0x100, so dass der Code bei 0x600 (nach dem Elf-Header) statt 0x500 beginnt. Der Code wird geladen, aber der Aufruf in loader.asm
verwendet 0x646 anstelle von 0x648, wo main startet.
Beachten Sie, dass es bei 0x603 eine zusätzliche Zeile der Baugruppe gibt, die nicht dort sein soll. Es sieht wie eine Junk-Instruktion aus und ich denke, es könnte sein, was es ablegt. Es sieht aus wie die der Aufrufbefehl
500: e8 43 00 00 00 call 548 <main>
richtig interpretiert wird, sondern die Nullen auf die nächste Anweisung tragen irgendwie den zusätzlichen unerwarteten Befehl zu erstellen. Nicht sicher, ob das eine Möglichkeit ist.
Ich kann nicht herausfinden, warum es eine Adresse verwendet, die 2 off ist, geschieht dies auch in anderen Teilen des Kernel-Codes.
Fühlen Sie sich frei, um irgendwelche anderen Fehler, die ich gemacht habe, aufzuzeigen, ich lerne, wie ich gehe. Ich bin mir nicht sicher, ob das damit zu tun hat, wie ich sie verbinde, welches Format ich verwende oder etwas anderes.
EDIT:
Also, es scheint dies tatsächlich ein Problem mit meinem Bootloader ist:
global start
[bits 16]
[org 0x7c00]
start: jmp boot
boot:
cli ; clear interrupts
cld ; clear direction flag
mov ax, 0
mov es, ax
mov bx, 0x500 ; set bx to where we load the kernel
mov al, 0x12 ; set lower byte of ax to read 18 sectors
mov ch, 0 ; set higher byte of cx to read track 0 (first track)
mov cl, 2 ; set lower byte of cx to read sector 2 (bootloader is sec1)
mov dh, 0 ; set higher byte of dx to read head 0 (top side of disk)
mov dl, 0 ; set lower byte of dx to read drive 0 (floppy drive)
mov ah, 0x02 ; read
int 0x13 ; call BIOS interrupt 13 to read drive
int 0x10 ; clear screen
jmp pm_switch
hlt ; this instruction should not execute
pm_switch:
xor ax, ax ; clear ds (used by lgdt)
mov ds, ax
cli
lgdt [gdt_desc]
mov eax, cr0
or eax, 1 ; switch to protected mode
mov cr0, eax
jmp 08h:select_jump
select_jump:
xor eax, eax
mov ax, 0x10 ; set data segments to data selector (0x10)
mov ds, ax
mov ss, ax
mov esp, 09000h
mov ax, 0
mov es, ax
; do a far jump to set cs and go to kernel code
jmp 08h:0x600
gdt: ; Address for the GDT
gdt_null: ; Null Segment
dd 0
dd 0
;KERNEL_CODE equ $-gdt
gdt_kernel_code:
dw 0FFFFh ; Limit 0xFFFF
dw 0 ; Base 0:15
db 0 ; Base 16:23
db 09Ah ; Present, Ring 0, Code, Non-conforming, Readable
db 00Fh ; Page-granular
db 0 ; Base 24:31
;KERNEL_DATA equ $-gdt
gdt_kernel_data:
dw 0FFFFh ; Limit 0xFFFF
dw 0 ; Base 0:15
db 0 ; Base 16:23
db 092h ; Present, Ring 0, Data, Expand-up, Writable
db 00Fh ; Page-granular
db 0 ; Base 24:32
gdt_end: ; Used to calculate the size of the GDT
gdt_desc: ; The GDT descriptor
dw gdt_end - gdt - 1 ; Limit (size)
dd gdt ; Address of the GDT
; pad the file to file the rest of the sector (512 bytes) and add boot sig
times 510 - ($-$$) db 0
dw 0xAA55
LÖSUNG:
stellt sich heraus, meine GDT Codesegment war s et zu 16-Bit. Ich änderte es zu 32 und fügte eine [bits 32]
Anweisung direkt hinzu, nachdem ich den Schalter zu geschütztem mache (direkt vor select jump
).
Das habe ich vermutet. Bedeutet das, dass ich nicht korrekt in den geschützten Modus meines Bootloaders umschalte? – Serial
Wahrscheinlich nicht. Wo versuchen Sie den geschützten Modus zu aktivieren? Wie richten Sie die Seitentabellen ein? – duskwuff
In meinem Bootloader. Ich benutze einen sehr einfachen GDT, indem ich auf protected umstelle, indem ich cr0 setze, setze die Segmentregister und springe dann weit zum Kernel-Code. Bootloader-Code: http://pastebin.com/RLWC7KkA – Serial