内核没有加载到正确的地址



好吧,我已经把这个问题剩下的头发都扯掉了。。。

基本上,我正在尝试开发一个非常简单的业余操作系统。操作系统将在X86平台上运行,使用FAT12软盘。在我的机器上测试它之前,我创建了一个磁盘映像,用Bochs 2.6.2进行测试。

像往常一样,我将引导加载程序放在磁盘映像的引导扇区上,然后将内核映像(kernel.SYS)添加为常规FAT12文件。

引导加载程序旨在定位KERNEL.SYS,将其加载到地址1000h:0000,然后跳转到它。

然而,当我用Bochs测试磁盘映像时,我得到了以下结果(从跳转到07C0:0000开始):

结果

据我所知,我知道Bochs要么保持重置(三重故障?),要么返回0000:0000(A20未启用)。内核开始时有一个无限循环(JMP $)(出于测试原因),所以我知道它没有被执行。我也知道1000:000不超过1MB,所以我不确定。

这是真正困扰我的部分:当我从Bochs(32 MB)中提取内存转储时,我看到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:

好吧,一切似乎都很好,所以问题可能出在其他地方。(顺便说一句,在int 13h之前不需要STC,但这不能成为所述问题的原因)。

因此,我建议尝试使用Bochs调试器,并在源代码的关键位置插入int3断点,例如在内核读取操作之前和远跳之前(在那里你可以检查$100:0000 上加载了什么

另一个不太重要的注意事项是SP的值。7c00h在某种程度上不是SP的常用值,但无论如何,这并不是明显的问题。

此外,还必须再次检查内核代码。

您的代码似乎有一点不对劲,那就是您将Stack段设置为07C0,然后将堆栈指针设置为7C00,因此堆栈位于07C0:7C00或0000:F800,这并不是导致它失败AFAIK的原因。不过,你应该考虑的是,根据BIOS的不同,引导记录可以加载到0000:7C00或07C0:0000,为了安全起见,最好用一个远跳来规范代码段,也要记住,只要它是一致的,你是在07C0:000还是0000:7C000发起它都没关系。

如前所述,在INT 13h之前您不需要STC,您可以省略这些以节省空间,更好的是,您可以通过调用一个子例程来清理问题,该子例程重置磁盘,将LBA转换为CHS,并在一段代码中读取所有扇区,而不是将磁盘读取代码分散在代码的其余部分。此外,当重置磁盘时,如果驱动器未准备好,它会设置进位标志,并且在进位标志清除之前,继续调用INT 13h AX=0是完全安全的。

如果你查看你声称内核加载的地址,将其转换为一个绝对地址,然后返回到段偏移07C00h,你将内核加载到07C0:1C00,如果问题是分段,这可能更有意义。

相关内容

  • 没有找到相关文章