Ядро не загружается по правильному адресу

Хорошо, я вырвал оставшиеся волосы у меня с этой проблемой...

По сути, я пытаюсь разработать очень простую хобби ОС. Операционная система будет работать на платформе X86 без дискеты FAT12. Прежде чем протестировать его на своем компьютере, я создаю образ диска для тестирования с помощью Bochs 2.6.2.

Как обычно, я поместил загрузчик на загрузочный сектор образа диска, затем добавил образ ядра (KERNEL.SYS) в виде обычного файла FAT12.

Загрузчик предназначен для поиска KERNEL.SYS, загрузки его по адресу 1000h:0000 и перехода к нему.

Однако, когда я тестирую образ диска с помощью Bochs, я получаю следующие результаты (начиная с перехода к 07C0:0000):

Результаты

Насколько я знаю, я знаю, что Bochs либо продолжает сбрасывать (тройной сбой?), Либо возвращается обратно в 0000:0000(A20 не включен). Есть бесконечный цикл (JMP $) при запуске ядра (для целей тестирования), поэтому я знаю, что оно не выполняется. Я также знаю, что 1000:000 не превышает 1 МБ, поэтому я не уверен.

Это та часть, которая действительно беспокоит меня: когда я получил дамп памяти от Bochs (32 МБ), я вижу, что KERNEL.SYS был загружен в 0980:0000 или 0000:9800. Я точно знаю, что никогда ничего там не загружал, так что происходит?

Код загрузчика:

[BITS 16]
[ORG 0x00]

JMP btldr_init
NOP

OEMName         DB 'MAGMAPRE'
BytesPerSector      DW 0x0200
SectorsPerCluster   DB 0x01
ReservedSectors     DW 0x0001
NumberOfFATS        DB 0x02
MaxRDirEntries      DW 0x00E0
TotalSectors        DW 0x0B40
MediaDescriptor     DB 0xF0
SectorsPerFAT       DW 0x0009
SectorsPerTrack     DW 0x0012
NumberOfHeads       DW 0x0002
HiddenSectors       DD 0x00000000
TotalSectorsL       DD 0x00000000

DriveNumber     DW 0x0000
Reserved        DB 0x00
VolumeID        DD 0xF00DCAFE
VolumeName      DB 'MAGMA DISK '
FileSysID       DB 'FAT12   '

btldr_init:

    MOV AX, 0x07C0
    MOV DS, AX
    MOV     ES, AX
    MOV SS, AX

    MOV SP, 0x7C00

    MOV DI, 0x03

read_rdir:

    MOV [driveNo], DL

    MOV AX, 0x13

    CALL    dos_to_bios


    MOV AX, 0x020E
    MOV BX, buffer

    CALL    reset_dsksys

    STC
    INT 0x13

    JNC search_rdir

    DEC DI
    JZ  fatal_error

    JMP read_rdir

search_rdir:

    MOV DI, buffer
    MOV SI, knlName
    MOV DX, [MaxRDirEntries]

.compare:

    PUSH    DI
    PUSH    SI

    CLD

    MOV CX, 0x0B

    REP CMPSB

    JE  load_disk_fath

    POP SI
    POP DI

.next_entry:

    DEC DX
    JZ  fatal_error

    ADD DI, 0x20
    JMP .compare

load_disk_fath:

    POP SI
    POP DI

    MOV AX, word [DS:DI+0x1A]
    MOV [cluster], AX
    MOV AX, word [DS:DI+0x1C]
    MOV [knlSize], AX

    MOV DI, 0x03

load_disk_fat:

    MOV AX, [ReservedSectors]
    CALL    dos_to_bios

    MOV AX, 0x0209

    MOV BX, buffer

    STC
    INT 0x13

    JNC load_file_clusterh

    DEC DI
    JZ  fatal_error

    JMP load_disk_fat

load_file_clusterh:

    MOV DI, 0x03

    MOV AX, 0x1000
    MOV ES, AX  

load_file_cluster:

    MOV AX, [cluster]
    ADD AX, 0x21

    CALL    dos_to_bios

    MOV AX, 0x0201

    MOV BX, [bufPos]
    CMP BX, [knlSize]
    JAE get_info

    STC
    INT 0x13

    JC  .try_again

    MOV BX, [bufPos]
    ADD BX, 0x200
    MOV [bufPos], BX
    JMP get_next_cluster

.try_again:

    DEC DI
    JZ  fatal_error

    JMP load_file_cluster

get_next_cluster:

    MOV AX, [cluster]
    MOV BX, [cluster]

    SHR BX, 0x01

    ADD BX, AX

    MOV DX, [DS:BX+buffer]

    TEST    BX, 0x01

    JNZ .even

.odd:

    SHR DX, 0x04
    JMP .check  

.even:

    AND DX, 0x0FFF

.check:

    CMP DX, 0xFF0
    JE  get_info

    MOV [cluster], DX

    ;JMP    load_file_cluster

get_info:

    MOV AX, 0x0BE0
    MOV ES, AX
    MOV DI, 0x02
    XOR SI, SI

.low_mem:

    XOR AX, AX
    INT 0x12

    JC  .low_mem_err

    TEST    AX, AX
    JZ  .low_mem_err

.low_mem_success:

    MOV [ES:DI], AX
    JMP .upper_memE801

.low_mem_err:

    XOR DI, DI
    OR  SI, 0x0001
    MOV [ES:DI], SI

.upper_memE801:

    XOR     CX, CX
    XOR     DX, DX
    MOV     AX, 0xE801
    INT     0x15        
    JC  SHORT .upper_mem_err
    CMP     AH, 0x86    
    JE  SHORT .upper_mem_err
    CMP     AH, 0x80    
    JE  SHORT .upper_mem_err
    JCXZ    .useax      

    MOV     AX, CX
    MOV     BX, DX
    JMP .useax

.upper_mem_err:

    JMP .upper_mem88

.useax:

    MOV DI, 0x04
    MOV [ES:DI], AX
    ADD DI, 0x02
    MOV [ES:DI], BX
    JMP goto_kernel

.upper_mem88:

    MOV AH, 0x88
    INT     0x15        
    JC  SHORT .upper_mem_err88
    TEST    AX, AX      
    JE  SHORT .upper_mem_err88
    CMP     AH, 0x86        
    JE  SHORT .upper_mem_err88
    CMP     AH, 0x80        
    JE  SHORT .upper_mem_err88

.success:

    MOV DI, 0x08
    MOV [ES:DI], AX
    JMP goto_kernel

.upper_mem_err88:

    OR  SI, 0x0002

goto_kernel:


    JMP 1000h:0000  

reset_dsksys:

    PUSHA

    XOR AX, AX
    MOV DL, [driveNo]

    INT 0x13

    JC  fatal_error

    POPA
    RET

fatal_error:

.repeat:

    MOV AL, [DS:SI]
    OR  AL, AL
    JZ  .end

    MOV AH, 0x0E
    INT 0x10

    INC SI
    JMP .repeat

.end:

    CLI
    HLT

dos_to_bios:

    PUSH    BX
    PUSH    AX

    MOV     BX, AX          ; SAVE LOGICAL SECTOR

    MOV     DX, 0           ; FIRST THE SECTOR
    DIV WORD [SectorsPerTrack]
    ADD     DL, 01H         ; PHYSICAL SECTORS START AT 1
    MOV     CL, DL          ; SECTORS BELONG IN CL FOR INT 13H
    MOV AX, BX

    MOV     DX, 0           ; NOW CALCULATE THE HEAD
    DIV     WORD [SectorsPerTrack]
    MOV     DX, 0
    DIV     WORD [NumberOfHeads]
    MOV     DH, DL          ; HEAD/SIDE
    MOV     CH, AL          ; TRACK

    POP AX
    POP     BX

    MOV     DL, BYTE [driveNo]      ; SET CORRECT DEVICE


    RET

knlName     DB 'KERNEL  SYS'

knlSize     DW 0x0000

err     DB 'Could not load Magma.', 0x00

driveNo     DB 0x00

cluster     DW 0x0000
cOffset     DW 0x0000
bufPos      DW 0x0000

TIMES   510 - ($ - $$) DB 0x00

DB  0x55
DB  0xAA

buffer:

2 ответа

Одна вещь, которая кажется неприличной в вашем коде, это то, что вы устанавливаете сегмент стека на 07C0, а затем указатель стека на 7C00, так что стек расположен в 07C0:7C00 или 0000:F800, что не является причиной сбоя AFAIK. Однако следует учитывать, что загрузочная запись может быть загружена либо в 0000:7C00, либо в 07C0:0000 в зависимости от BIOS, и было бы неплохо нормализовать сегмент кода с помощью дальнего перехода, просто чтобы быть в безопасности, также помните, что это не имеет значения, если вы создаете его в 07C0:0000 или 0000:7C00, если это не противоречит.

Как упоминалось ранее, вам не нужно STC до INT 13h, и вы можете опустить их, чтобы сэкономить место, еще лучше, если вы можете очистить вещи, вызвав подпрограмму, которая сбрасывает диск, преобразует LBA в CHS и считывает сектора целиком кода, который имеет код чтения диска, разбросанный по всей остальной части кода. Также при сбросе диска он устанавливает флаг переноса, если накопитель не готов, и совершенно безопасно продолжать вызывать INT 13h AX=0, пока флаг переноса не сбросится.

Если вы посмотрите на адрес, по которому вы утверждаете, что ядро ​​было загружено, преобразуйте его в абсолютный адрес, а затем вернитесь к смещению сегмента с сегментом 07C00h, в котором вы загрузили ядро ​​в 07C0:1C00, что может иметь больше смысла, если проблема заключается в сегментации.

Что ж, похоже, все в порядке, так что проблема может быть где-то еще. (Кстати, STC не требуется до 13 часов, но это не может быть причиной описанной проблемы).

Итак, я бы предложил попробовать использовать отладчик Bochs и вставить точки останова int3 на ключевые позиции в вашем источнике - например, перед операциями чтения ядра и непосредственно перед дальним переходом (где вы можете проверить, что загружено на $1000:0000

Еще одно замечание, также не очень важное, это значение SP. 7c00h как-то не обычное значение для SP, но в любом случае это не очевидная проблема.

Кроме того, код ядра должен быть проверен еще раз.

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