gpt4 book ai didi

assembly - 引导加载程序不会跳转到内核代码

转载 作者:行者123 更新时间:2023-12-02 16:57:52 30 4
gpt4 key购买 nike

我正在写小型操作系统-用于练习。我从引导加载程序开始。我想创建一个以16位实模式运行的小型命令系统(目前)。
我已经创建了引导加载程序,用于重置驱动器,然后在引导加载程序之后加载扇区。
问题是因为在jmp函数之后实际上什么也没发生。

我没有尝试在下一个扇区加载0x7E00(我不完全确定如何使用es:bx指向地址,所以可能是个问题,我相信它的Address:offset)只是在引导加载程序之后。

这是代码:

;
; SECTOR 0x0
;

;dl is number of harddrive where is bootloader
org 0x7C00
bits 16

;reset hard drive
xor ah,ah
int 0x13
;read sectors
clc
mov bx,0x7E00
mov es,bx
xor bx,bx
mov ah,0x02 ;function
mov al,0x1 ;sectors to read
mov ch,0x0 ;tracks
mov cl,0x1 ;sector
mov dh,0x0 ;head
int 0x13
;if not readed jmp to error
jc error
;jump to 0x7E00 - executed only if loaded
jmp 0x7E00
error:
mov si,MSGError
.loop:
lodsb
or al,al
jz .end
mov ah,0x0E
int 0x10
jmp .loop
.end:
hlt
MSGError db "Error while booting", 0x0
times 0x1FE - ($ - $$) db 0x0
db 0x55
db 0xAA

;
; SECTOR 0x1
;

jmp printtest
;definitions
MSGLoaded db "Execution successful", 0x0
;
; Print function
; si - message to pring (NEED TO BE FINISHED WITH 0x0)

printtest:
mov si,MSGLoaded
.loop:
lodsb
or al,al
jz .end
mov ah,0x0E
int 0x10
jmp .loop
.end:
hlt

times 0x400 - ($-$$) db 0x0


我一直在使用VirtualBox测试此代码,但实际上没有任何反应,没有显示读取错误以及应打印的消息。

最佳答案

此代码的主要问题是:


ES:BX指向错误的segment:offset以将内核加载到
加载了错误的扇区,因此内核不是预期的


第一个在此代码中:

mov bx,0x7E00
mov es,bx
xor bx,bx


该问题想将扇区从磁盘加载到 0x0000:0x7E00(ES:BX)。此代码将ES:BX设置为 0x7E00:0x0000,该解析为物理地址 0x7E000((0x7E00 << 4)+ 0x0000)。我认为其目的是将 0x07E0加载到ES中,这将产生 0x7E00的物理地址((0x07E0 << 4)+ 0x0000)。您可以了解有关16:16内存寻址计算 here的更多信息。将段乘以16等于将其左移4位。

代码中的第二个问题在这里:

mov ah,0x02 ;function
mov al,0x1 ;sectors to read
mov ch,0x0 ;tracks
mov cl,0x2 ;sector number
mov dh,0x0 ;head
int 0x13


磁盘上第二个512块扇区的编号是2,而不是1。因此,要修复上述代码,您需要相应地设置CL:

mov cl,0x2  ;sector number


Bootloader开发的一般提示

其他可能导致各种仿真器,虚拟机和实际物理硬件上的运行代码崩溃的问题是:


当BIOS跳转到您的代码时,您不能依赖具有有效或预期值的CS,DS,ES,SS,SP寄存器。引导加载程序启动时,应适当设置它们。您只能保证将引导加载程序从物理地址0x00007c00加载并运行,并且将引导驱动器号加载到DL寄存器中。
将SS:SP设置为您知道不会与自己的代码操作冲突的内存。 BIOS可能已将其默认堆栈指针放在了可用和可寻址RAM的第一个兆字节中的任何位置。不能保证它在哪里以及它是否适合您编写的代码。
lodsbmovsb等使用的方向标志可以设置或清除。如果方向标志设置不正确,SI / DI寄存器的方向可能会调整错误。使用 STD / CLD将其设置为所需的方向(CLD =前进/ STD =后退)。在这种情况下,代码假定向前移动,因此应使用 CLD。有关更多信息,请参见 instruction set reference
跳转到内核时,通常最好将FAR JMP设置为内核,以便将CS:IP正确设置为期望值。这样可以避免内核代码出现问题,这些问题可能在同一段中的JMP和CALL附近产生绝对影响。
如果将引导加载程序用于可在8086/8088处理器(及更高版本)上运行的16位代码,请避免在汇编代码中使用32位寄存器。使用AX / BX / CX / DX / SI / DI / SP / BP代替EAX / EBX / ECX / EDX / ESI / EDI / ESP / EBP。尽管不是这个问题的问题,但对于其他寻求帮助的人来说却是一个问题。 32位处理器可以在16位实模式下使用32位寄存器,但是8086/8088/80286不能使用,因为它们是16位处理器,无法访问扩展的32位寄存器。
FS和GS段寄存器已添加到80386+ CPU。如果要定位8086/8088/80286,请避免使用它们。


要解决第一项和第二项,可以在引导加载程序的开头附近使用此代码:

xor ax,ax      ; We want a segment of 0 for DS for this question
mov ds,ax ; Set AX to appropriate segment value for your situation
mov es,ax ; In this case we'll default to ES=DS
mov bx,0x8000 ; Stack segment can be any usable memory

cli ; Disable interrupts to circumvent bug on early 8088 CPUs
mov ss,bx ; This places it with the top of the stack @ 0x80000.
mov sp,ax ; Set SP=0 so the bottom of stack will be @ 0x8FFFF
sti ; Re-enable interrupts

cld ; Set the direction flag to be positive direction


需要注意的几件事。当更改SS寄存器的值(在这种情况下,通过 MOV更改)时,处理器应该关闭该指令的中断,并保持中断状态直到下一条指令之后。通常,如果您在更新SS之后立即更新SP,则无需担心禁用中断。在早期的8888处理器中存在一个错误,此错误没有兑现,因此,如果您瞄准的是最广泛的环境,则可以肯定地禁用并重新启用它们。如果您不想使用越野车8088,则可以在上面的代码中删除 CLI / STI指令。我在80年代中期在家用PC上所做的第一手资料就知道该错误。

要注意的第二件事是我如何设置堆栈。对于8088/8086 16位汇编的新手来说,可以采用多种方式设置堆栈。在这种情况下,我将堆栈的顶部(内存中的最低部分)设置为 0x8000(SS)。然后,将堆栈指针(SP)设置为 0。当您在16位实模式下 push something on the stack时,处理器首先将堆栈指针减2,然后在该位置放置一个16位WORD。因此,第一次压入堆栈的位置为0x0000-2 = 0xFFFE(-2)。然后,您将拥有一个 0x8000:0xFFFE的SS:SP。在这种情况下,堆栈从 0x8000:0x0000运行到 0x8000:0xFFFF

处理运行在8086上的堆栈(不适用于80286、80386+处理器)时,最好将堆栈指针(SP)设置为偶数。在原始8086上,如果将SP设置为奇数,则每次访问堆栈空间都将产生 4 clock cycle penalty。由于8088具有8位数据总线,因此不存在这种损失,但是在8086上加载16位字需要4个时钟周期,而在8088上则需要8个时钟周期(两个8位存储器读取)。

最后,如果要显式设置CS:IP,以便在JMP完成(到内核)时正确设置CS,则建议执行 FAR JMP(请参阅影响段寄存器/ FAR跳转的操作) 。在NASM语法中, JMP看起来像这样:

jmp 0x07E0:0x0000


一些(即MASM / MASM32)汇编程序不直接支持对FAR Jmp进行编码,因此可以通过以下方式手动完成:

db 0x0ea     ; Far Jump instruction
dw 0x0000 ; Offset
dw 0x07E0 ; Segment


如果使用GNU汇编程序,它将看起来像:

ljmpw $0x07E0,$0x0000

关于assembly - 引导加载程序不会跳转到内核代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/32701854/

30 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com