Постоянная перезагрузка после настройки Global Descriptor Table и защищенного режима

Должно быть, я сделал что-то не так с GDT setup и переключился на protected mode, потому что он постоянно перезагружается.

Вот мой kernel.asm, который должен настроить GDT и переключиться на protected mode:

    bits 16

    jmp main
    %include "gdt.inc"

    main:
        cli
        xor ax,ax
        mov ds,ax
        mov es,ax
        mov ax,0x9000
        mov ss,ax
        mov sp,0xffff
        sti

        call InstallGDT

        cli
        mov eax,cr0
        or eax,1
        jmp 08h:Stage3

    bits 32
    Stage3:

        mov ax,0x10
        mov ds,ax
        mov ss,ax
        mov es,ax
        mov esp,90000h

    Stop:

        mov byte [0xb8000],'A'
        cli
        hlt

и есть gdt.inc:

bits 16
InstallGDT:

    cli
    pusha
    lgdt   [toc]
    sti
    popa
    ret
gdt_data:
    dd 0
    dd 0

    dw 0ffffh
    dw 0
    db 0
    db 10011010b
    db 11001111b
    db 0

    dw 0ffffh
    dw 0
    db 0
    db 10010010b
    db 11001111b
    db 0
end_of_gdt:
toc:
    dw end_of_gdt - gdt_data -1
    dd gdt_data

Мой bootloader.asm загружает 10 секторов в 0x1000:0x000 и потом прыгает туда.

Я тестирую код с помощью команд:

nasm -f bin -o bootloader.bin bootloader.asm
nasm -f bin -o kernel.bin kernel.asm
cat bootloader.bin kernel.bin>OS.bin
qemu-system-i386 OS.bin

Где моя вина?


person Community    schedule 22.12.2016    source источник


Ответы (1)


Поскольку я могу только предположить, что вы правильно прочитали сектора в памяти по адресу 0x1000:0x0000, я могу указать только на потенциальные проблемы в kernel.asm и gdt.inc.


Проблемы с кодом

Если вы дошли до стадии ядра с jmp 0x1000:0x0000 (подозреваю, что это так), то в kernel.asm вы неправильно установили сегменты DS и ES к неправильному значению. В этом случае вам нужно будет установить для этих двух регистров значение 0x1000, а не 0x0000. Этот код:

    xor ax,ax
    mov ds,ax
    mov es,ax

необходимо изменить на:

    mov ax,0x1000
    mov ds,ax
    mov es,ax

Следующая серьезная проблема заключается в том, что GDT запись (внутри toc) принимает линейный адрес. Линейный адрес в реальном режиме — это то же самое, что и физический адрес. В инструкции по эксплуатации написано:

Исходный операнд указывает 6-байтовую ячейку памяти, содержащую базовый адрес (линейный адрес) и ограничение (размер таблицы в байтах) глобальной таблицы дескрипторов (GDT).

Вы использовали ORG 0x0000 (поскольку вы его не указали) для kernel.asm, поэтому NASM предполагает, что все сгенерированные смещения взяты из базы 0x0000, включая метку gdt_data. Итак, когда вы делаете это:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data

gdt_data будет небольшим смещением чуть выше 0x0000. В физической памяти ваша запись GDT фактически находится по адресу 0x1000:0x0000+(небольшое смещение). 0x1000:0x0000 в физической (линейной) памяти равно (0x1000‹‹4)+0x0000 = 0x10000, поэтому вам нужно добавить это к gdt_data. Ваш toc должен выглядеть так, чтобы компенсировать это:

toc:
dw end_of_gdt - gdt_data -1
dd gdt_data+0x10000

Следующая проблема заключается в том, что вы фактически не включаете флаг защищенного режима. У вас есть это:

    mov eax,cr0
    or eax,1

Так должно быть:

    mov eax,cr0
    or eax,1
    mov cr0, eax

Вам необходимо обновить бит защищенного режима в регистре CR0 после того, как вы установите этот бит в 1.


В связи с проблемой GDT вы создали записи GDT для сегмента кода со смещением 0x00000000, которые охватывают все адресное пространство размером 4 ГБ. Это правильно. Опять же, поскольку NASM создал смещение от 0x0000, а ваш код фактически загружается по адресу 0x1000:0x0000 (физический адрес 0x10000), вам нужно добавить 0x10000 к значению метки stage3 в JMP, который, наконец, устанавливает защищенный режим. Кроме того, поскольку мы кодируем значение выше 0xFFFF, нам нужно заставить NASM использовать 32-битный операнд, поэтому мы используем квалификатор dword для JMP. У вас есть это:

jmp 08h:Stage3

Это должно быть так:

jmp dword 08h:Stage3+0x10000
person Michael Petch    schedule 23.12.2016