我需要一些帮助来理解使用BrokenThorn的bootloader加载内核的逻辑。
代码:
LOAD_IMAGE:
mov ax, WORD [cluster] ; cluster to read
pop bx ; buffer to read into
call ClusterLBA ; convert cluster to LBA
;xor cx, cx
;mov cl, BYTE [bpbSectorsPerCluster] ; sectors to read (commenting out has same result?
call ReadSectors ;(ES:BX from above)
push bx
; compute next cluster
mov ax, WORD [cluster] ; identify current cluster
mov cx, ax ; copy current cluster
mov dx, ax ; copy current cluster
shr dx, 0x0001 ; divide by two
add cx, dx ; sum for (3/2)
mov bx, 0x0200 ; location of FAT in memory
add bx, cx ; index into FAT
mov dx, WORD [bx] ; read two bytes from FAT
test ax, 0x0001
jnz .ODD_CLUSTER
.EVEN_CLUSTER:
and dx, 0000111111111111b ; take low twelve bits
jmp .DONE
.ODD_CLUSTER:
shr dx, 0x0004 ; take high twelve bits
.DONE:
mov WORD [cluster], dx ; store new cluster
cmp dx, 0x0FF0 ; test for end of file
jb LOAD_IMAGE
DONE:
mov si, msgCRLF
call Print
push WORD 0x0050
push WORD 0x0000
retf
为什么我需要将CHS转换为LBA?在该函数中,似乎LBA存储在AX寄存器中。但它没有在ReadSectors
中使用?然后,将当前群集复制到AX中。
ClusterLBA:
sub ax, 0x0002 ; zero base cluster number
xor cx, cx
mov cl, BYTE [bpbSectorsPerCluster] ; convert byte to word
mul cx
add ax, WORD [datasector] ; base data sector
ret
此外,引导加载程序将内核加载到内存位置0x0050:0x0000
为什么我不能jmp 0x0050:0x0000
并开始执行代码?什么
push WORD 0x0050
push WORD 0x0000
做什么?这在教程中没有解释。
答案 0 :(得分:2)
ClusterLBA将群集#(在AX中)转换为扇区#(在AX中),以便能够通过int 13h读取这些扇区。
ReadSectors似乎将AX,ES:BX作为参数
推,推,retf相当于jmp远。两种变体都是5个字节长。没有区别。
答案 1 :(得分:1)
为什么我需要将CHS转换为LBA?
你没有,代码在我能看到的任何地方都没有这样做。我假设代码所做的是将(FAT)“簇号”转换为LBA号。请注意,FAT文件系统使用群集(可能是512字节,1024字节......),其中群集编号相对于分区的开头(而不是磁盘的开头)。
在该函数中,好像LBA存储在AX寄存器中。但它没有在ReadSectors中使用?
您没有发布ReadSectors
的代码,也没有提供该代码可能位于何处的链接。我只能假设你错了,并且ReadSectors
确实在AX中使用了LBA(例如在使用int0x13
加载扇区之前立即进行快速LBA到CHS转换。)
为什么我不能jmp 0x0050:0x0000并开始执行代码?
你可以。
遗憾的是,很多编写汇编语言代码的人都不是汇编语言程序员(例如他们可能是熟悉汇编语言的C程序员)。更可悲的是,一些陈旧的装配工并不是很好,让人们很难弄清楚如何做得很远。基本上,“推;推; retf”就在那里,因为无论谁编写它都没有或无法弄清楚如何正确地做到这一点。