为了学习,我研究了制作一个小型操作系统,现在我正在使用引导加载程序。我希望能够使用int 0x13从软盘驱动器读取扇区,将它们放入内存,然后跳转到该代码中。以下是我到目前为止所拥有的:
org 0x7c00
bits 16
main:
call setup_segments
mov ah, 2 ; function
mov al, 1 ; num of sectors
mov ch, 1 ; cylinder
mov cl, 2 ; sector
mov dh, 0 ; head
mov dl, 0 ; drive
mov bx, 0x1000 ;
mov es, bx ; dest (segment)
mov bx, 0 ; dest (offset)
int 0x13 ; BIOS Drive Interrupt
jmp 0x1000:0 ; jump to loaded code
times 510 - ($-$$) db 0 ; fluff up program to 510 B
dw 0xAA55 ; boot loader signature
LoadTarget: ; Print Message, Get Key Press, Reboot
jmp new_main
Greeting: db "Hello, welcome to the bestest bootloader there ever was!", 0
Prompt: db "Press any key to reboot...", 0
Println:
lodsb ; al <-- [ds:si], si++
or al, al ; needed for jump ?
jz PrintNwl ; if null is found print '\r\n'
mov ah, 0x0e ; function
mov bh, 0 ; page number ?
mov bl, 7 ; text attribute ?
int 0x10 ; BIOS Interrupt
jmp Println
PrintNwl: ; print \r\n
; print \r
mov ah, 0x0e ; function
mov al, 13 ; char (carriage return)
mov bh, 0 ; page number ?
mov bl, 7 ; text attribute ?
int 0x10
; print \n
mov ah, 0x0e ; function
mov al, 20 ; char (line feed)
mov bh, 0 ; page number ?
mov bl, 7 ; text attribute ?
int 0x10
ret ; return
GetKeyPress:
mov si, Prompt ; load prompt
call Println ; print prompt
xor ah, ah ; clear ah
int 0x16 ; BIOS Keyboard Service
ret ; return
setup_segments:
cli ;Clear interrupts
;Setup stack segments
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
sti ;Enable interrupts
ret
new_main:
call setup_segments
mov si, Greeting ; load greeting
call Println ; print greeting
call GetKeyPress ; wait for key press
jmp 0xffff:0 ; jump to reboot address
times 1024 - ($-$$) db 0 ; fluff up sector我想在LoadTarget之后将扇区加载到address 0x1000:0中,然后跳转到它。到目前为止我只得到了一个空白的屏幕。我觉得这个bug介于main和行times 510 - ($-$$) db 0之间。也许我只是没有得到寄存器的值对吧?请帮帮我!谢谢
发布于 2015-07-10 16:32:05
您应该将第一个call setup_segments替换为执行任务的实际指令。此外,正如Jester指出的,在更改SS寄存器时,始终更新SP寄存器。
目前,您正在从第一缸阅读。应该是圆柱0。
linefeed的代码是10 (不是您写的20 )。
PrintNwl中的两个BIOS调用都不需要BL寄存器,因为CR和LF都是不可显示的ascii。
发布于 2015-07-12 15:54:15
您使用的是ORG 0x7C00,这意味着您期望CS:IP对或寄存器持有0000h:7C00h。请记住,BIOS已经将1024字节长程序的前512字节放置在线性地址00007C00h。
设置其他段寄存器只是将CS复制到DS、ES和SS的问题。但是非常重要的是,每次你改变党卫军,你也必须改变SP,以保持一个连贯的SS:SP对寄存器。在您的程序中,堆栈的一个方便位置应该在程序下面,所以我用7C00h设置了SP寄存器。您不能在子程序中摆弄SS:SP (就像您所做的那样),因为最后的RET将不知道返回到哪里!
当你从软盘加载第二扇区时,它必须来自气缸0。在CHS中,代表缸和头从0开始,扇区从1开始。
如果您检查CF以获得成功的操作,那就太好了。
跳到加载的代码不能通过jmp 0x1000:0完成,因为现在位于那里的代码是使用ORG 0x7C00指令编译的程序的一部分。你需要补偿这一切!
ORG 0x7C00指令。从段部分减去07C0h,将7C00h添加到偏移部分。=> jmp 0840h:7C00hjmp 0820h:7E00h下面是初始代码的样子
org 7C00h
bits 16
main:
mov ax,cs
mov ds,ax <-- Not necessary at this stage in this program
mov es,ax <-- (keep them should you display a message on error)
cli
mov ss,ax
mov sp,7C00h
sti
mov ax,0201h
mov cx,0002h
mov dx,0000h
mov bx,1000h
mov es,bx
mov bx,0000h
int 13h
jc Error
jmp 0820h:7E00h
Error:
hlt一旦第二阶段运行,您只需要设置DS和ES寄存器。CS:IP是通过JMP设置的,SS:SP只是继续。
...
new_main:
push cs
pop ds
push cs
pop es
mov si,Greeting
call Println
...https://stackoverflow.com/questions/31344628
复制相似问题