Bochs: сборка дальнего прыжка потерялась в фиктивной области памяти (неверная ошибка кода операции)

Я начал разрабатывать небольшую игрушечную операционную систему (NASM) для развлечения. Я написал загрузчик, который загружает первый (и только один) файл из файловой системы FAT12 под названием "kernel.sys" в память по смещению 0x7E00, В реальном режиме ядро ​​только устанавливает соответствующий режим видео через BIOS и входит в 32-битный (защищенный) режим. И это точка, где моя проблема может быть найдена.

Прежде всего, я установил GDT с 3 дескрипторами (ноль, код звонка 0, данные звонка 0) и загружаю его прямо в область памяти 0x0500, Тогда я использую LGDT инструкция, чтобы сказать это процессору, то я установил PE немного в CR0 зарегистрироваться, и я хочу войти в защищенный режим с дальним переходом, чтобы установить соответствующий сегмент (0x08 - сегмент кода в GDT) и указатель инструкции.

Первая версия этого работала в QEMU, но не в Bochs. Bochs нужно было установить сегменты перед дальним переходом, поэтому я изменил это в своем коде: непосредственно перед дальним переходом я загружаю селекторы с сегментом данных из моего GDT. Но Bochs по-прежнему не может войти в защищенный режим из-за ошибки "недопустимый код операции".

Пожалуйста, помогите мне решить эту ошибку!

Вот мой код ядра: (Обратите внимание, что метка b32 никогда не доходил!)

;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
;;                                                                  ;;
;;                           16-BIT ENTRY                           ;;
;;                                                                  ;;
;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;

use16
org 0x7e00
jmp start

sys_gdt        equ 0x00000500
sys_gdt_ring0c equ 0x00000508
sys_gdt_ring0d equ 0x00000510
sys_gdtr       equ 0x00000518

start:
    cli

    mov ax, 0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov sp, 0x1000
    sti

    mov ax, 3
    int 0x10

set_a20:
    in al, 0x64
    test al, 2
    jnz set_a20

    mov al, 0xd1
    out 0x64, al

test_a20:
    in al, 0x64
    test al, 2
    jnz test_a20

    mov al, 0xdf
    out 0x60, al

    mov dword [sys_gdt+0], 0
    mov dword [sys_gdt+4], 0

    mov word [sys_gdt_ring0c+0], 0xffff
    mov word [sys_gdt_ring0c+2], 0
    mov byte [sys_gdt_ring0c+4], 0
    mov byte [sys_gdt_ring0c+5], 10011010b
    mov byte [sys_gdt_ring0c+6], 01001111b
    mov byte [sys_gdt_ring0c+7], 0

    mov word [sys_gdt_ring0d+0], 0xffff
    mov word [sys_gdt_ring0d+2], 0
    mov byte [sys_gdt_ring0d+4], 0
    mov byte [sys_gdt_ring0d+5], 10010010b
    mov byte [sys_gdt_ring0d+6], 01001111b
    mov byte [sys_gdt_ring0d+7], 0

    mov word  [sys_gdtr+0], sys_gdtr-sys_gdt-1
    mov dword [sys_gdtr+2], sys_gdt

    cli
    lgdt [sys_gdtr] ;; :96

    mov eax, cr0
    or eax, 0x1
    mov cr0, eax

    mov ax, 0x10
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax
    mov ss, ax
    mov esp, 0x90000

    jmp 0x08:b32

use32

b32:
    mov cx, 5
    jmp $

Вот журнал Bochs:

00014041550i[BIOS ] Booting from 0000:7c00
00015625085e[CPU0 ] write_virtual_checks(): write beyond limit, r/w
00015625085i[CPU0 ] CPU is in protected mode (active)
00015625085i[CPU0 ] CS.d_b = 32 bit
00015625085i[CPU0 ] SS.d_b = 32 bit
00015625085i[CPU0 ] EFER   = 0x00000000
00015625085i[CPU0 ] | RAX=0000000060000010  RBX=0000000000000204
00015625085i[CPU0 ] | RCX=0000000000090000  RDX=0000000000000fff
00015625085i[CPU0 ] | RSP=0000000000090000  RBP=0000000000000000
00015625085i[CPU0 ] | RSI=00000000000e018e  RDI=0000000000008000
00015625085i[CPU0 ] |  R8=0000000000000000   R9=0000000000000000
00015625085i[CPU0 ] | R10=0000000000000000  R11=0000000000000000
00015625085i[CPU0 ] | R12=0000000000000000  R13=0000000000000000
00015625085i[CPU0 ] | R14=0000000000000000  R15=0000000000000000
00015625085i[CPU0 ] | IOPL=0 id vip vif ac vm rf nt of df if tf sf zf af PF cf
00015625085i[CPU0 ] | SEG selector     base    limit G D
00015625085i[CPU0 ] | SEG sltr(index|ti|rpl)     base    limit G D
00015625085i[CPU0 ] |  CS:0008( 0001| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  DS:0010( 0002| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  SS:0010( 0002| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  ES:0010( 0002| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  FS:0010( 0002| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  GS:0010( 0002| 0|  0) 00000000 000fffff 0 1
00015625085i[CPU0 ] |  MSR_FS_BASE:0000000000000000
00015625085i[CPU0 ] |  MSR_GS_BASE:0000000000000000
00015625085i[CPU0 ] | RIP=0000000000007ebb (0000000000007eb9)
00015625085i[CPU0 ] | CR0=0x60000011 CR2=0x0000000000000000
00015625085i[CPU0 ] | CR3=0x00000000 CR4=0x00000000
00015625085i[CPU0 ] 0x0000000000007eb9>> add byte ptr ds:[eax], al : 0000
00015625085i[CMOS ] Last time is 1459506108 (Fri Apr  1 12:21:48 2016)
00015625085i[     ] restoring default signal behavior
00015625085i[CTRL ] quit_sim called with exit code 1

Вот мой загрузчик:

use16
jmp start

    OEMLabel          db 'SYRACUSE'
    BytesPerSector    dw 512
    SectorsPerCluster db 1
    ReservedForBoot   dw 1
    NumberOfFats      db 2
    RootDirEntries    dw 224
    LogicalSectors    dw 2880
    MediumByte        db 0xf0
    SectorsPerFat     dw 9
    SectorsPerTrack   dw 18
    Heads             dw 2
    HiddenSectors     dd 0
    LargeSectors      dd 0
    DriveNo           dw 0
    Signature         db 41
    VolumeID          dd 0
    VolumeLabel       db 'Syracuse1.0'
    FileSystem        db 'FAT12   '

chs_lba:
    sub ax, 2
    xor cx, cx
    mov cl, byte [SectorsPerCluster]
    mul cx
    add ax, word [datasector]
    ret

lba_chs:
    xor dx, dx
    div word [SectorsPerTrack]
    inc dl
    mov byte [absoluteSector], dl
    xor dx, dx
    div word [Heads]
    mov byte [absoluteHead], dl
    mov byte [absoluteTrack], al
    ret

print:
    pusha
    mov ah, 0xe
.repeat:
    lodsb
    cmp al, 0
    je .done
    int 0x10
    jmp short .repeat
.done:
    popa
    ret

read_sectors:
    mov di, 5
.loop:
    pusha

    call lba_chs
    mov ah, 2
    mov al, 1
    mov ch, byte [absoluteTrack]
    mov cl, byte [absoluteSector]
    mov dh, byte [absoluteHead]
    mov dl, byte [DriveNo]
    int 0x13
    jnc .done

    xor ax, ax
    int 0x13

    dec di
    popa
    jnz .loop
    int 0x18
.done:
    popa

    inc ax
    add bx, word [BytesPerSector]
    loop read_sectors
    ret

start:
    cli
    mov ax, 0x07c0
    mov ds, ax
    mov es, ax
    mov fs, ax
    mov gs, ax

    mov ax, 0
    mov ss, ax
    mov sp, 0xffff
    sti

load_root:
    xor cx, cx
    xor dx, dx
    mov ax, 32
    mul word [RootDirEntries]
    div word [BytesPerSector]
    xchg ax, cx

    mov al, byte [NumberOfFats]
    mul word [SectorsPerFat]
    add ax, word [ReservedForBoot]
    mov word [datasector], ax
    add word [datasector], cx

    mov bx, 0x0200
    call read_sectors

    mov cx, word [RootDirEntries]
    mov di, 0x0200

.loop:
    push cx

    mov cx, 11
    mov si, kernel

    push di
    rep cmpsb
    pop di
    je load_fat

    pop cx
    add di, 32
    loop .loop

    jmp failure

load_fat:
    mov dx, word [di+0x001a]
    mov word [cluster], dx

    xor ax, ax
    mov al, byte [NumberOfFats]
    mul word [SectorsPerFat]
    mov cx, ax

    mov ax, word [ReservedForBoot]

    mov bx, 0x0200
    call read_sectors

    mov ax, 0x7e00
    mov es, ax
    mov bx, 0x0000

load_kernel:
    mov ax, word [cluster]
    call chs_lba
    xor cx, cx
    mov cl, byte [SectorsPerCluster]
    call read_sectors

    mov ax, word [cluster]
    mov cx, ax
    mov dx, ax
    shr dx, 1
    add cx, dx
    mov bx, 0x0200
    add bx, cx
    mov dx, word [bx]
    test ax, 1
    jnz .odd

.even:
    and dx, 0000111111111111b
    jmp .done

.odd:
    shr dx, 4

.done:
    mov word [cluster], dx
    cmp dx, 0x0ff0
    jb load_kernel

    pusha
    mov di, 0x7e00
    xor ax, ax
    mov cx, 512
    rep stosb


execute_kernel:
    ;push word 0x7e00
    ;push word 0x0000
    ;retf

    jmp 0x7e00:0x0000

failure:
    mov si, msg
    call print

    mov ah, 0
    int 0x16
    int 0x19

absoluteSector db 0
absoluteHead   db 0
absoluteTrack  db 0

datasector dw 0
cluster    dw 0

kernel db 'KERNEL  SYS'
msg    db 'MISSING KERNEL. Press any key to reboot...', 0xA, 0xD, 0

times 510-($-$$) db 0
dw 0xAA55

1 ответ

Вы знаете, что адресация в реальном режиме использует 16*segment+offset как физический адрес, верно? Вы загружаете код на 0x7E00:0000 который, таким образом, является физическим адресом 0x7E000 (обратите внимание, 3 ноля). Но ваше ядро ​​ожидает адрес 0x7E00 (обратите внимание, 2 ноля).

Ваш код неверен вдвойне. Во-первых, вы на самом деле прыгаете в смещение 0 так что вы должны использовать org 0 (который используется по умолчанию). Во-вторых, физический адрес должен быть скорректирован для сегмента реального режима, то есть jmp dword 0x8:b32+0x7e000, Это исправит текущий код, но 32-битная часть будет использовать неправильно org снова.

Вы делаете свою собственную жизнь излишне сложной. Обычно рекомендуется загружать код по адресу в пределах первых 64 КБ, где можно использовать смещения сегмента 0 и 16 бит, которые отображаются непосредственно в физическую память как в реальном, так и в защищенном режиме. В качестве такового я предлагаю загрузить, скажем, 0:0x8000,

Другие вопросы по тегам