32-битный защищенный режим не работает для нескольких файлов сборки - PullRequest
0 голосов
/ 19 февраля 2019

Я пишу простой загрузочный сектор сборки NASM.Код должен печатать текст на экране в режиме реального времени 16 бит, затем переключаться в защищенный режим 32 бита и печатать текст на экране.

Я использую QEMU в качестве эмулятора процессора, и он печатает текст из 16-битного режима, как и должно быть.Однако текст, который должен быть напечатан в 32-битном режиме, не печатается.

Я бы предположил, что это проблема с моим кодом, но я также запустил этот аналогичный код , с той же проблемой работы только в 16-битном режиме.

Не правильно ли я использую QEMU, или я что-то еще напутал?

Спасибо

Редактировать: добавлен код

boot_sector.asm

; Boot sector that enters 32 bit protected mode
[org 0x7c00]

mov bp, 0x9000          ; Set stack
mov sp, bp

mov bx, MSG_REAL_MODE
call print_string

call switch_to_pm       ; We will never return to here

jmp $

%include "print_string.asm"
%include "gdt.asm"
%include "print_string_pm.asm"
%include "switch_to_pm.asm"

[bits 32]
;Where we arrive after switching to PM
BEGIN_PM:
    mov ebx, MSG_PROTECTED_MODE
    call print_string_pm        ; 32 bit routine to print string

    jmp $                       ; Hang


; Global variables
MSG_REAL_MODE: db "Started in 16-bit real mode.", 0
MSG_PROTECTED_MODE: db "Successfully landed in 32-bit protected mode.", 0

; Boot sector padding
times 510-($-$$) db 0
dw 0xaa55

switch_to_pm.asm

[bits 16]
; Switch to protected mode
switch_to_pm:

    mov bx, MSG_SWITCHING       ; Log
    call print_string

    cli                         ; Clear interrupts

    lgdt [gdt_descriptor]       ; Load GDT

    mov eax, cr0                ; Set the first bit of cr0 to move to protected mode, cr0 can't be set directly
    or eax, 0x1                 ; Set first bit only
    mov cr0, eax

    jmp CODE_SEG:init_pm        ; Make far jump to to 32 bit code. Forces CPU to clear cache

[bits 32]
; Initialize registers and the stack once in PM
init_pm:

    mov ax, DATA_SEG            ; Now in PM, our old segments are meaningless
    mov ds, ax                  ; so we point our segment registers to the data selector defined GDT
    mov ss, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ebp, 0x90000            ; Move stack
    mov esp, ebp

    call BEGIN_PM               ; Call 32 bit PM code


; Global variables
MSG_SWITCHING: db "Switching to 32-bit protected mode...", 0

gdt.asm

gdt_start:

gdt_null:           ; The mandatory null descriptor
    dd 0x0          ; dd = define double word (4 bytes)
    dd 0x0

gdt_code:           ; Code segment descriptor
    dw 0xffff       ; Limit (bites 0-15)
    dw 0x0          ; Base (bits 0-15)
    db 0x0          ; Base (bits 16-23)
    db 10011010b    ; 1st flags, type flags
    db 11001111b    ; 2nd flags, limit (bits 16-19)

gdt_data:
    dw 0xffff       ; Limit (bites 0-15)
    dw 0x0          ; Base (bits 0-15)
    db 0x0          ; Base (bits 16-23)
    db 10010010b    ; 1st flags, type flags
    db 11001111b    ; 2nd flags, limit (bits 16-19)
    db 0x0

gdt_end:            ; necessary so assembler can calculate gdt size below

gdt_descriptor:
    dw gdt_end - gdt_start - 1  ; GDT size

    dd gdt_start                ; Start adress of GDT

CODE_SEG equ gdt_code - gdt_start
DATA_SEG equ gdt_data - gdt_start

print_string_pm.asm

[bits 32]

VIDEO_MEMORY equ 0xb8000
WHITE_ON_BLACK equ 0x0f

print_string_pm:
    pusha
    mov edx, VIDEO_MEMORY

print_str_pm_loop:
    mov al, [ebx]
    mov ah, WHITE_ON_BLACK

    cmp al, 0
    je print_str_pm_return

    mov [edx], ax

    add ebx, 1
    add edx, 2

    jmp print_str_pm_loop

print_str_pm_return:
    popa
    ret

print_string.asm

print_string:
    pusha
    mov ah, 0x0e

_print_str_loop:
    mov al, [bx]
    cmp al, 0
    je _print_str_return
    int 0x10
    inc bx
    jmp _print_str_loop

_print_str_return:
    popa
    ret

Команды: Для сборки:

nasm -f bin boot_sector.asm -o boot_sector.bin

Qemu:

qemu-system-x86_64 boot_sector.bin --nographic

Ответы [ 2 ]

0 голосов
/ 19 февраля 2019

Хорошо, я понял это.При простом запуске qemu-system-x86_64 boot_sector.bin в macO он ничего не отображает, даже в реальном 16-битном режиме.Где-то в Интернете я обнаружил, что добавление -nographic будет работать, и это работает для 16-битного реального режима.В 32-битном PM удалите тег -nographic и добавьте -curses.Это сработало отлично.Спасибо Майклу Петчу также за то, что он показал мне мою плохую запись GDT.

0 голосов
/ 19 февраля 2019

Вы неправильно установили указатель стека реального режима и регистры сегментов.Указатель стека реального режима состоит из SS: SP.Вы не знаете, где в памяти находится стек, поскольку вы только изменили SP.Начало вашего загрузчика должно выглядеть примерно так:

xor ax, ax              ; Set ES=DS=0 since an ORG of 0x7c00 is used
mov es, ax              ;     0x0000<<4+0x7c00 = physical address 0x07c00
mov ds, ax

mov bp, 0x9000
mov ss, ax              ; Set stack to 0x0000:0x9000
mov sp, bp

Ваш код не полагается на BP , поэтому его не нужно устанавливать, хотя это ничего не повредитТаким образом.


Основная проблема при входе в защищенный режим - ошибка в вашем GDT.Каждая запись дескриптора имеет длину 8 байт, а схема каждого дескриптора выглядит следующим образом:

enter image description here

В вашем коде вы, кажется,пропущен байт в дескрипторе 32-битного кода:

gdt_code:           ; Code segment descriptor
    dw 0xffff       ; Limit (bites 0-15)
    dw 0x0          ; Base (bits 0-15)
    db 0x0          ; Base (bits 16-23)
    db 10011010b    ; 1st flags, type flags
    db 11001111b    ; 2nd flags, limit (bits 16-19)

Длина этой записи составляет всего 7 байтов.Похоже, вам не хватает последнего байта, который должен быть 0 для завершения 32-битного базового адреса.Он должен выглядеть следующим образом:

gdt_code:           ; Code segment descriptor
    dw 0xffff       ; Limit (bites 0-15)
    dw 0x0          ; Base (bits 0-15)
    db 0x0          ; Base (bits 16-23)
    db 10011010b    ; 1st flags, type flags
    db 11001111b    ; 2nd flags, limit (bits 16-19)
    db 0x0          ; Base (bits 24-31)

При запуске в QEMU с командой qemu-system-x86_64 boot_sector.bin он должен выглядеть следующим образом:

enter image description here

Iвыделил текст, напечатанный в защищенном режиме, красным цветом.


Если вы хотите запустить код вне графического дисплея в режиме консоли, скажите QEMU использовать curses.

    -curses
       Normally, if QEMU is compiled with graphical window support, it
       displays output such as guest graphics, guest console, and the QEMU
       monitor in a window. With this option, QEMU can display the VGA
       output when in text mode using a curses/ncurses interface. Nothing
       is displayed in graphical mode.

Используйте командную строку:

qemu-system-x86_64 boot_sector.bin -curses
...