代码之家  ›  专栏  ›  技术社区  ›  zero

保护模式寻址

  •  3
  • zero  · 技术社区  · 6 年前

    我正在试用引导加载程序开发教程。我能够使用FAT12约定阅读stage2引导加载程序。现在,我正在尝试以实模式加载内核,然后将其复制到0x0100000地址。

    复制+跳转到0x0100000时,我出现三重错误。 基本上,我不知道如何访问或跳转到0x0100000。

    当我使用

    IMAGE_PMODE_BASE equ 0x1000
    IMAGE_RMODE_BASE equ 0x1000
    
    krnl32.bin: boot/kernel_entry.o ${OBJ}
        i386-elf-ld -o $@ -Ttext 0x01000 $^ --oformat binary
    

    我错过了什么?我读到了关于描述符:保护模式下的偏移寻址,它说DESC:offset(16位)。此外,使用GDT中的粒度设置将偏移量乘以4KB。

    我已经这样设置了gdt:

    gdt_start: 
        dd 0                ; null descriptor
        dd 0 
    
    ; gdt code:             ; code descriptor
        dw 0FFFFh           ; limit low
        dw 0                ; base low
        db 0                ; base middle
        db 10011010b        ; access
        db 11001111b        ; granularity
        db 0                ; base high
    
    ; gdt data:             ; data descriptor
        dw 0FFFFh           ; limit low (Same as code)10:56 AM 7/8/2007
        dw 0                ; base low
        db 0                ; base middle
        db 10010010b        ; access
        db 11001111b        ; granularity
        db 0                ; base high
    
    end_of_gdt:
    toc: 
        dw end_of_gdt - gdt_start - 1   ; limit (Size of GDT)
        dd gdt_start            ; base of GDT
    
    ; give the descriptor offsets names
    
    NULL_DESC equ 0
    CODE_DESC equ 0x8
    DATA_DESC equ 0x10
    

    我正在链接内核,如下所示:

    krnl32.bin: boot/kernel_entry.o ${OBJ}
        i386-elf-ld -o $@ -Ttext 0x0100000 $^ --oformat binary
    

    阶段2引导加载程序

    [bits 16]
    [org 0x500]
    
    jmp main
    
    %include "boot/stage2/print16.s"
    %include "boot/stage2/print32.s"
    %include "boot/stage2/floppy16_driver.s"
    %include "boot/stage2/fat12.s"
    %include "boot/stage2/gdt.s"
    %include "boot/stage2/a20.s"
    
    ;*******************************************************
    ;   Data Section
    ;*******************************************************
    
    msgFailure db 0x0D, 0x0A, "Failed", 0x00
    welcomeMessage db 0x0D, 0x0A, "Landed in STAGE TWO...", 0x00
    enableA20Msg db 0x0D, 0x0A, "Enabled A20. Installed GDT", 0x00
    ImageName     db "KRNL32  BIN"
    ImageSize     db 0
    IMAGE_PMODE_BASE equ 0xffff
    IMAGE_RMODE_BASE equ 0x1000
    
    
    main:
        ;-------------------------------;
        ;   Setup segments and stack    ;
        ;-------------------------------;
    
        cli                    ; clear interrupts
        xor     ax, ax             ; null segments
        mov     ds, ax
        mov     es, ax
        mov     ax, 0x0000         ; stack begins at 0x9000-0xffff
        mov     ss, ax
        mov     sp, 0xFFFF
        sti                    ; enable interrupts
    
        mov si, welcomeMessage
        call Print16
    
        call    _EnableA20
        call    InstallGDT
        sti
        mov si, enableA20Msg
        call Print16
    
        call    LoadRoot
        mov     ebx, 0
        mov     ebp, IMAGE_RMODE_BASE
        mov     esi, ImageName
        call    LoadFile        ; load our file
        mov     dword [ImageSize], ecx
        cmp     ax, 0
        je      EnterStage3
        mov     si, msgFailure
        call    Print16
        mov     ah, 0
        int     0x16                    ; await keypress
        int     0x19                    ; warm boot computer
    
        jmp $;
    
    EnterStage3:
    
        cli   
        mov eax, cr0
        or  eax, 1
        mov cr0, eax
    
        jmp CODE_DESC:Stage3           
    
    
    [bits 32]
    Stage3:
        mov ax, DATA_DESC       ; set data segments to data selector (0x10)
        mov ds, ax
        mov ss, ax
        mov es, ax
        mov esp, 90000h     ; stack begins from 90000h
    
    CopyImage:
        mov eax, dword [ImageSize]
        movzx   ebx, word [bpbBytesPerSector]
        mul ebx
        mov ebx, 4
        div ebx
        cld
        mov    esi, IMAGE_RMODE_BASE
        mov edi, IMAGE_PMODE_BASE
        mov ecx, eax
        rep movsd                   ; copy image to its protected mode address
        jmp IMAGE_PMODE_BASE
        jmp $; 
    
    1 回复  |  直到 5 年前
        1
  •  4
  •   Michael Petch    6 年前

    您设置了一个GDT,该GDT具有32位代码描述符和32位数据描述符。在保护模式下,寄存器 CS/DS/ES/SS/FS/GS 不再是以实模式显示的段寄存器。在保护模式下,它们包含一个选择器,指向GDT(或LDT)中的条目。此代码加载数据寄存器:

    mov ax, DATA_DESC       ; set data segments to data selector (0x10)
    mov ds, ax
    mov ss, ax
    mov es, ax
    

    无法设置 反恐精英 像这样注册。A. jmp可以设置所需的代码段选择器,并在一条指令中设置偏移量。这就是本说明的作用:

    jmp CODE_DESC:Stage3
    

    你的 GDT公司 使用4gb平面内存模型的代码和数据描述符进行设置,其中基数为0x00000000,限制为0xFFFFFF。这意味着,一旦处于保护模式,并且使用指向这些描述符的选择器,就可以直接访问0x00000000到0xffffff之间的所有内存。这意味着你需要做的就是 jmp 0x100000 跳转到内存地址0x100000。在代码中,您不仅希望使用0x100000作为跳转位置,还希望使用内存副本使用的内存位置作为其基础。

    考虑到这一点,简单的解决方法是改变:

    IMAGE_PMODE_BASE equ 0x1000
    

    收件人:

    IMAGE_PMODE_BASE equ 0x100000