我看的是于渊的《Orange's一个操作系统的实现》,有如下代码
org 07c00h ; 告诉编译器程序加载到7c00处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 16 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h 号中断
ret
BootMessage: db "Hello, OS world!"
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
nasm编译后bin文件,在做成img文件,用vpc,bochs,vbox,vmware启动都是没问题的.
现在想,如果能用U盘启动就好了,插上U盘,用bin文件写到U盘第一扇区,
重启计算机,进入bios,设置U盘模式为HDD硬盘模式,再把首启动改成U盘,重启
结果发现.启动失败,是的他失败了,而os其他的几个例子也会失败.为什么呢?????
开始以为是int中断的问题,改字符,改页号,改颜色,改模式....
第一种解决办法,是对比MBR,最后发现:
软盘的es=0,ds=0,ss=0,cs=00,而硬盘加载时es=0,ds=0,ss=0,cs=7c0h.
那么用上面的中断 ES:BP将访问不到0000:7c00处的字符串地址,显然只需要清零es就行了.
org 07c00h ; 告诉编译器程序加载到7c00处
xor ax, ax ;>>>>>>>>>>>>>>>>>>>清零es
mov ds, ax
mov es, ax ;>>>>>>>>>>>>>>>>>>>清零es
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 25 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h 号中断
ret
BootMessage: db "The test is the best way."
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
第二种解决办法,是在考虑BootMessage的实际地址,最后发现:
真实为es:bp=es:7c00+offset=es:org+offset
那么修改方式也就出来了,就是去掉org 07c00h就行了.
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环
DispStr:
mov ax, BootMessage
mov bp, ax ; ES:BP = 串地址
mov cx, 25 ; CX = 串长度
mov ax, 01301h ; AH = 13, AL = 01h
mov bx, 000ch ; 页号为0(BH = 0) 黑底红字(BL = 0Ch,高亮)
mov dl, 0
int 10h ; 10h 号中断
ret
BootMessage: db "The test is the best way."
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
用nasm编译.两种方法都可以在U盘执行....
见下表
(在硬盘)
第一种,保留org 7c00h,把es,ds清零 es:bp= 0:7c00+BootMessage "OK"
第二种,去掉org 7c00h,cs赋值给es,ds es:bp= 07c0:BootMessage "OK"
(在软盘)
第一种,保留org 7c00h,把es,ds清零 es:bp= 0:7c00+BootMessage "OK" ;Orange用的方法
第二种,去掉org 7c00h,cs赋值给es,ds es:bp= 0:BootMessage "Error" ;这样,地址错
这四种结论 都经过实验,结论全正确
归根结底,就是对 ES:org+offset 位置的访问