Ich entwickle einen Bootloader, der nach dem Wechsel in den geschützten Modus in einen einfachen Kernel booten wird. Ich habe this paper als Tutorial irgendwo in Kapitel vier oder fünf verwendet. Theoretisch sollte es im 16-Bit-Real-Modus starten, den Kernel in den Speicher laden, in den 32-Bit-Protected-Modus wechseln und den Kernel-Code starten.Dreifacher Fehler beim Sprung in den geschützten Modus
Wenn ich jedoch in geschützten Modus und weit springen oder zu einem anderen Segment springen, es dreifach Fehler. Hier ist die Hauptbootsektor-Code:
[org 0x7c00]
KERNEL_OFFSET equ 0x1000
mov [BOOT_DRIVE], dl ;Get the current boot drive from the BIOS
mov bp, 0x9000 ;Set up stack, with enough room to grow downwards
mov sp, bp
mov bx, REAL_MODE_MSG
call print_string
call load_kernel
call switch_to_pm
jmp $ ;Jump to current position and loop forever
%include "boot/util/print_string.asm"
%include "boot/util/disk.asm"
%include "boot/gdt/gdt.asm"
%include "boot/util/print_string_pm.asm"
%include "boot/switch_to_pm.asm"
[bits 16]
load_kernel:
mov bx, LOAD_KERNEL_MSG ;Print a message saying we are loading the kernel
call print_string
mov bx, KERNEL_OFFSET ;Set up disk_load routine parameters
mov dh, 15
mov dl, [BOOT_DRIVE]
call disk_load ;Call disk_load
ret
[bits 32]
BEGIN_PM:
mov ebx, PROT_MODE_MSG
call print_string_pm
call KERNEL_OFFSET
jmp $
; Data
BOOT_DRIVE: db 0
REAL_MODE_MSG: db "Started in real mode.", 0
PROT_MODE_MSG: db "Successfully entered 32-bit protected mode.", 0
LOAD_KERNEL_MSG: db "Loading Kernel into memory", 0
; Bootsector padding
times 510-($-$$) db 0
dw 0xaa55
Hier ist die GDT:
;Global Descriptor Table
gdt_start:
gdt_null: ; We need a null descriptor at the start (8 bytes)
dd 0x0
dd 0x0
gdt_code: ; Code segment descriptor
; Base=0x0, Limit=0xfffff
; 1st flags : (present)1 (privilege)00 (descriptor type)1 -> 1001b
; type flags : (code)1 (conforming)0 (readable)1 (accessed)0 -> 1010b
; 2nd flags : (granularity)1 (32 - bit default)1 (64 - bit seg)0 (AVL)0 -> 1100b
dw 0xffff ; Limit (bits 0-15)
dw 0x0 ; Base (0-15)
dw 0x0 ; Base (16-23)
db 10011010b ; 1st flags and type flags
db 11001111b ; 2nd flags and Limit (16-19)
db 0x0 ; Base (24-31)
gdt_data: ; Data segment descriptor
;Same as CSD except for type flags
; (code)0 (expand down)0 (writable)1 (accessed)0 -> 0010b
dw 0xffff ; Limit (bits 0-15)
dw 0x0 ; Base (0-15)
dw 0x0 ; Base (16-23)
db 10010010b ; 1st flags and type flags
db 11001111b ; 2nd flags and Limit (16-19)
db 0x0 ; Base (24-31)
gdt_end:
;GDT Descriptor
gdt_descriptor:
dw gdt_end - gdt_start - 1
dd gdt_start
;Some Constants
CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start
Hier ist der Code für die in den geschützten Modus schalten, wo es triple Störungen:
[bits 16]
switch_to_pm:
cli
lgdt [gdt_descriptor] ; load the gdt
mov eax, cr0 ; turn pm on
or eax, 0x1
mov cr0, eax
jmp CODE_SEG:init_pm ; THIS IS WHERE THE PROBLEM IS!
[bits 32]
init_pm:
mov ax, DATA_SEG ; Point segment registers to the data
mov ds, ax ; selector defined in the gdt
mov ss, ax
mov es, ax
mov fs, ax
mov gs, ax
mov ebp, 0x90000 ; Update our stack
mov esp, ebp
call BEGIN_PM ;Move on
Bei Ich setze eine jmp $
Anweisung in den Leerlauf an einer bestimmten Stelle, direkt vor der jmp CODE_SEG:init_pm
Anweisung, es im Leerlauf und nicht dreifacher Fehler. Wenn ich es nach dieser Anweisung innerhalb des Labels init_pm
platziere, macht es einen Dreifachfehler. Ich bin mir ziemlich sicher, dass dies der Grund ist. Ich bin nicht sicher, warum, vielleicht ist es ein Problem mit der GDT. Ich bin neu in der Entwicklung von Betriebssystemen und Bootloadern. Irgendwelche Vorschläge, wie man dieses Problem löst?
Sind Sie sicher, dass Ihre GDT korrekt ist? Ich denke, die Sache, die bei einem flüchtigen Blick auffällt, ist, dass jeder Ihrer Einträge 9 Byte (72 Bit) ist.Ein GDT-Eintrag ist 8 Bytes (64 Bits). es scheint, dass Sie vielleicht 'db 0x0; Basis (16-23) 'anstelle von' dw 0x0; Basis (16-23) '? Beachten Sie, dass "dw" in "db" geändert wird. Falsche GDT-Einträge würden einen Dreifachfehler erzeugen. –
Ich würde auch empfehlen, auf meine [allgemeine Bootloader-Tipps] (http://stackoverflow.com/questions/32701854/boot-loader-doesnt-jump-to-kernel-code/32705076#32705076) zu schauen. Sie nehmen an, dass das DS (Datensegment) -Register bei der Eingabe Null ist (da Sie org 0x7c00 verwenden). Sie sollten es explizit auf Null setzen. Sie legen den Stapel auch auf eine seltsame Weise fest. Sie setzen SP auf 9000, aber Sie setzen _SS_ nicht, was bedeutet, dass Sie nicht wirklich wissen, wo Sie den Stapel im Speicher ablegen. Sie sollten das Register _SS_ einstellen, gefolgt von der Einstellung des Registers _SP_. Meine Bootloader Tipps bieten ein Beispiel. –
@Michael Petch: Stellt sich heraus, SS ist garantiert, um Null zu sein. – Joshua