好吧,我一直在用这个问题撕掉剩下的头发......
基本上,我正在尝试开发一个非常简单的业余爱好操作系统。操作系统将在FAT12软盘上的X86平台上运行。在我在我的机器上测试它之前,我创建了一个磁盘映像以使用Bochs 2.6.2进行测试。
像往常一样,我将bootloader放到磁盘映像的bootsector上,然后我将内核映像(KERNEL.SYS)添加为常规FAT12文件。
引导加载程序用于定位KERNEL.SYS,将其加载到地址1000h:0000,然后跳转到它。
但是,当我用Bochs测试磁盘映像时,我得到了这些结果(从跳转到07C0:0000开始):
据我所知,我知道Bochs要么继续重置(三重故障?),要么重新回到0000:0000(A20未启用)。在内核开始时有一个无限循环(JMP $
)(出于测试原因),所以我知道它没有被执行。我也知道1000:000不超过1 MB,所以我不确定。
这是让我困扰的部分:当我从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:
答案 0 :(得分:0)
嗯,一切似乎都没问题,所以问题可能就在其他地方。 (顺便说一下,在13h之前没有必要使用STC,但这不能成为所述问题的原因)。
所以,我建议尝试使用Bochs调试器并在源代码中的关键位置插入int3断点 - 例如在内核读取操作之前和远程跳转之前(在那里你可以检查1000美元上加载的内容) :0000
另一个注意事项,也不是很重要,是SP的价值。 7c00h在某种程度上不是SP的常用值,但无论如何它并不是明显的问题。
此外,必须再次检查内核代码。
答案 1 :(得分:0)
关于你的代码似乎有一点是你将堆栈段设置为07C0然后将堆栈指针设置为7C00,因此堆栈位于07C0:7C00或0000:F800这不是导致它的原因失败AFAIK。你应该考虑的一点是,bootrecord可以加载到0000:7C00或07C0:0000,具体取决于BIOS,为了安全起见,将远程跳转规范化代码段是一个好主意,还要记住它如果你在07C0:0000或0000:7C00发起它并不重要,只要它是一致的。
如前所述,您不需要在INT 13h之前使用STC并且可以省略这些以节省空间,更好的是您可以通过调用重置磁盘的子例程来清理,将LBA转换为CHS并读取所有扇区在一段代码中,而不是将磁盘读取代码分散在整个代码中。此外,当复位磁盘时,如果驱动器未就绪,则设置进位标志,并且在进位标志清零之前保持调用INT 13h AX = 0是完全安全的。
如果你查看你声称内核被加载的地址,将它转换为绝对地址,然后回到段偏移量,你将内核加载到07C0:1C00的07C00h段,如果问题可能更有意义是细分。