Assembly 引导加载程序没有';不要跳转到内核代码
我正在写一个小的操作系统-用于实践。我从引导加载程序开始。Assembly 引导加载程序没有';不要跳转到内核代码,assembly,virtualbox,nasm,x86-16,bootloader,Assembly,Virtualbox,Nasm,X86 16,Bootloader,我正在写一个小的操作系统-用于实践。我从引导加载程序开始。我想创建以16位实模式运行的小型命令系统(目前)。 我创建了一个引导加载程序,它重置驱动器,然后在引导加载程序之后加载扇区。 问题是因为在jmp函数之后,实际上什么都没有发生 我并没有尝试在0x7E00加载下一个扇区(我不完全确定如何使用es:bx指向地址,所以这可能是个问题,我相信它的地址是偏移量),只是在引导加载程序之后 代码如下: ; ; SECTOR 0x0 ; ;dl is number of harddrive where
我想创建以16位实模式运行的小型命令系统(目前)。
我创建了一个引导加载程序,它重置驱动器,然后在引导加载程序之后加载扇区。
问题是因为在
jmp
函数之后,实际上什么都没有发生
我并没有尝试在0x7E00加载下一个扇区(我不完全确定如何使用es:bx指向地址,所以这可能是个问题,我相信它的地址是偏移量),只是在引导加载程序之后
代码如下:
;
; 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测试这段代码,但实际上什么都没有发生,读取错误没有显示,以及应该打印的消息。这段代码的主要问题是:
mov bx,0x7E00
mov es,bx
xor bx,bx
问题是要将扇区从磁盘加载到
0x0000:0x7E00
(ES:BX)。此代码将ES:BX设置为0x7E00:0x0000
,解析为0x7E000
(在发出任何BIOS中断之前,您需要设置堆栈(SS
和SP
寄存器)。在使用lodsb和相关函数之前,您还需要调用CLD
或STD
。在设置堆栈调用CLD
之后,您的代码假定为自动递增。您似乎也没有使用适当的段设置DS
寄存器(否则lodsb可能无法工作)。从您所展示的内容来看,还不清楚内核映像的原点设置为什么。您用来链接、编译和创建磁盘映像的makefile或命令可能对您的问题有帮助。mov-bx,0x7E00
;mov-es,bx
,xor-bx,bx
似乎有误。您的代码表明您打算拒绝d磁盘上的扇区位于0x0000:0x7E00
=物理地址0x7E00
,但您将ES
:BX
段设置为0x7E00
并将BX
设置为零,从而产生0x7E00的物理地址。我的内核起始点是扇区0x1。我正在使用nasm bootloader.asm-o bootloader.img>编译(bootloader.asm是主线程中的代码)。然后在VirtualBox中将bootloader.img设置为软盘。关于
lodsb`它在jc
时起作用,我使用jnc
在读取实际成功完成时显示错误消息。您说什么也不打印,我认为这主要是因为您没有设置lodsb
所需的DS
寄存器。a启动引导加载程序时,您应该手动设置DS
,在这种情况下,它应该设置为0。因此xor ax,ax
和mov DS,ax
(或任何等效于将0移动到DS的操作)肯定会有所帮助。我相信,您看到的任何打印内容都可能是因为DS错误(未设置)。你不能依靠BIOS跳转到你的引导加载程序,并为DS、ES、SS和SPS设置正确的值。你的扇区号是对的,我已经更改了,内核正常打印了消息。我不知道为什么会打印“Ä”┼╝" 以前是,但现在可以了。我真的很感激。当一个人在x86上使用GNU汇编程序时,它看起来像是。英特尔语法noprefix
jmp 0x07E0:0x0000
,您在这里写了“解析此代码的第一项和第二项”",代码段初始化了寄存器DS、ES、SS和SP。那么CS寄存器呢,我们应该保持这个寄存器不变吗?或者您建议做什么更改?@supmethods:这是一个好问题。关于这个主题,我在这里有一个问题和答案:。如果引导加载程序使用指令at是相对于CS的。很多引导加载程序代码并不要求CS是一个特定的值。Q&A链接显示了一些可能出现这种情况的场景。如果您编写引导加载程序来避免它们,那么就可以了。如果您不确定,您可以在引导加载程序的开始处进行JMP来设置CS。抱歉,我没有阅读注释和surro当我发表评论的时候,我会发短信。是的,这是一个坏习惯。
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
mov cl,0x2 ;sector number
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
jmp 0x07E0:0x0000
db 0x0ea ; Far Jump instruction
dw 0x0000 ; Offset
dw 0x07E0 ; Segment
ljmpw $0x07E0,$0x0000