Assembly BIOS读扇区
为了学习,我已经考虑过制作一个小型操作系统,现在正在使用引导加载程序。我希望能够使用Assembly BIOS读扇区,assembly,x86,nasm,boot,bios,Assembly,X86,Nasm,Boot,Bios,为了学习,我已经考虑过制作一个小型操作系统,现在正在使用引导加载程序。我希望能够使用int0x13从软盘驱动器读取扇区,将它们放入内存,然后跳转到该代码。以下是我到目前为止的情况: org 0x7c00 bits 16 main: call setup_segments mov ah, 2 ; function mov al, 1 ; num of sectors mov ch, 1 ; cylinder mov cl,
int0x13
从软盘驱动器读取扇区,将它们放入内存,然后跳转到该代码。以下是我到目前为止的情况:
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
org 0x7c00
第16位
主要内容:
呼叫设置\u段
mov-ah,2;功能
mov al,1;扇区数
mov-ch,1;圆柱
mov-cl,2;部门
mov-dh,0;头
movdl,0;开车
mov bx,0x1000;
mov-es,bx;目的地(段)
mov-bx,0;目的地(抵销)
int 0x13;BIOS驱动器中断
jmp 0x1000:0;跳转到加载的代码
乘以510-($-$$)db 0;将程序调整到510 B
dw 0xAA55;引导加载程序签名
加载目标:;打印消息、按键、重新启动
jmp新东区
问候语:db“您好,欢迎使用有史以来最好的引导加载程序!”,0
提示:db“按任意键重新启动…”,0
Println:
lodsb;al您应该用实际的操作说明替换第一个呼叫设置\u段
。正如Jester指出的,在更改SS寄存器时,始终更新SP寄存器
当前您正在读取气缸1的读数。它应该是0缸
linefeed的代码是10(而不是您编写的20)
PrintNwl中的两个BIOS调用都不需要BL寄存器,因为CR和LF都是不可显示的ascii。您使用的是ORG 0x7C00
这一事实意味着您希望CS:IP对或寄存器能够容纳0000h:7C00h。请记住,BIOS已经将1024字节长程序的前512字节放在线性地址00007C00h
设置其他段寄存器只是将CS复制到DS、ES和SS的问题。但非常重要的是,每次更改SS时,还必须更改SP以保持SS:SP寄存器对的一致性。在您的程序中,堆栈的方便位置将位于程序下方,因此我将SP寄存器设置为7C00h。您不能在子例程中摆弄SS:SP(就像您那样),因为最后的RET
不知道返回到哪里
从软盘加载第二个扇区时,它必须来自0号气缸。在CHS表示中,气缸和气缸盖从0开始,扇区从1开始。
如果您检查CF的操作是否成功,那就太好了
无法通过jmp 0x1000:0
跳转到加载的代码,因为现在位于那里的代码是使用ORG 0x7C00
指令编译的程序的一部分。你需要对此进行补偿
补偿ORG 0x7C00
指令。从段零件中减去07C0h,将7C00h添加到偏移零件中。=><代码>jmp 0840h:7C00h
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
既然
setup\u segments
已经是第二个扇区,如果它还没有加载,您希望它如何工作?另外,设置ss
而不设置sp
是一种非常糟糕的做法,您无法知道堆栈将位于何处。@Jester哦,是的,我没有想到;)。另外,我应该在哪里将sp
设置为?|哇,我简直不敢相信我把“\n”这个角色搞砸了!我知道是10,我不知道为什么我放了20。我也会修复其他的bug,谢谢!谢谢你的帮助,但它仍然显示一个空白屏幕。我正在Virtualbox上使用软盘。从使用角度看,这与真正的软盘有什么不同吗?对不起,我从未享受过使用Virtualbox的乐趣。没关系,我的程序现在可以运行了,它会重新启动,但不会显示任何内容。我认为这可能与sp
有关。我不知道我该设定什么。我是否应该将ss
复制到sp
中?@您是否已使用ORG
正确设置原点?第二阶段不应该是0
?
...
new_main:
push cs
pop ds
push cs
pop es
mov si,Greeting
call Println
...