开发环境:winxp+sp2
必须安装Bochs-2.3,nasm,WinImage,UltraEdit.
下载nasm后,添加nasm所在目录到到path目录,建议直接将nasm放到windows或system32目录,方便从命令行调用.
用WinImage建一个1.44M的floppya.img(请确保floppya.img文件的大小是:1,474,560 字节).
打开cmd,运行"nasm boot.asm",编译出的boot应该为512Byte,
用UltraEdit打开boot,全选,复制.
用UltraEdit打开floppya.img,选中前512字节内容,将从boot里复制的内容粘贴进来,覆盖floopya.img中的原有内容,然后保存floppya.img.
(注意:确保floppya.img文件仍为1,474,560Byte,否则Bochs将认为此floppya.img是无效的软盘,也将不能从此floppy启动).
建一个10M的HardDisk Image,写一个最简单的test.bxrc:
# how much memory the emulated machine will have
megs: 32
# filename of ROM images
romimage: file=../BIOS-bochs-latest, address=0xf0000
vgaromimage: file=../VGABIOS-lgpl-latest
# what disk images will be used
floppya: 1_44=floppya.img, status=inserted
#floppyb: 1_44=floppyb.img, status=inserted
# hard disk
ata0: enabled=1, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="test.img", mode=flat, cylinders=20, heads=16, spt=63
# choose the boot disk.
#boot: c
boot: floppy
# where do we send log messages?
log: test.log
# disable the mouse
mouse: enabled=0
设置一test.bxrc文件从floppya.img启动:
floppya: 1_44=floppya.img, status=inserted
boot: floppy
双击test.bxrc,启动
注意:
.慎用在VC6.0中采用__asm{...}的方式嵌入汇编来得到对应的二进制数据
VC6.0用的不是8086实模式,所以生成的代码不能直接用在floppy boot code中.
应该用debug中的U和A命令.
示例boot.asm内容如下:
org 0x07c00; 起始地址是0000:7c00
jmp short begin_boot ; 跳过其它的数据,跳转到引导程序的开始处
bootmesg db "Our OS boot sector loading ......"
pm_mesg db "Switching to protected mode ...."
dw 512 ; 每一扇区的字节数
db 1 ; 每一簇的扇区数
dw 1 ; 保留的扇区号
db 2
dw 0x00e0
dw 0x0b40
db 0x0f0
dw 9
dw 18
dw 2 ; 读写扇区号
dw 0 ; 隐藏扇区号
print_mesg :
mov ah,0x13 ; 使用中断10h的功能13,在屏幕上写一个字符串
mov al,0x00 ; 决定调用函数后光标所处的位置
mov bx,0x0007 ; 设置显示属性
mov cx,0x20 ; 在此字符串长度为32
mov dx,0x0000 ; 光标的起始行和列
int 0x10 ; 调用BIOS的中断10h
ret ; 返回调用程序
get_key :
mov ah,0x00
int 0x16 ; Get_key使用中断16h的功能0,读取下一个字符
ret
clrscr :
mov ax,0x0600 ; 使用中断10h的功能6,实现卷屏,如果al=0则清屏
mov cx,0x0000 ; 清屏
mov dx,0x174f ; 卷屏至23,79
mov bh,0 ; 使用颜色0来填充
int 0x10 ; 调用10h中断
ret
begin_boot :
call clrscr ; 先清屏
mov bp,bootmesg ; 提供串地址
call print_mesg ; 输出信息
call get_key ; 等待用户按下任一键
bits 16
call clrscr ; 清屏
mov ax,0xb800 ; 使gs指向显示内存
mov gs,ax ; 在实模式下显示一个棕色的A
mov word [gs:0],0x641 ; 显示
call get_key ; 调用Get_key等待用户按下任一键
mov bp,pm_mesg ; 设置串指针
call print_mesg ; 调用print_mesg子程序
call get_key ; 等待按键
call clrscr ; 清屏
cli ; 关中断
lgdt[gdtr] ; 加载GDT
mov eax,cr0
or al,0x01 ; 设置保护模式位
mov cr0,eax ; 将更改后的字送至控制寄存器中
jmp codesel:go_pm
bits 32
go_pm :
mov ax,datasel
mov ds,ax ; 初始化ds和es,使其指向数据段
mov es,ax
mov ax,videosel ; 初始化gs,使其指向显示内存
mov gs,ax
mov word [gs:0],0x741 ; 在保护模式下显示一个白色的字符A
spin : jmp spin ; 循环
bits 16
gdtr :
dw gdt_end-gdt-1 ; gdt的长度
dd gdt ; gdt的物理地址
gdt
nullsel equ $-gdt ; $指向当前位置,所以nullsel = 0h
gdt0 ; 空描述符
dd 0
dd 0 ; 所有的段描述符都是64位的
codesel equ $-gdt ; 这是8h也就是gdt的第二个描述符
code_gdt
dw 0x0ffff ; 段描述符的界限是4Gb
dw 0x0000
db 0x00
db 0x09a
db 0x0cf
db 0x00
datasel equ $-gdt
data_gdt
dw 0x0ffff
dw 0x0000
db 0x00
db 0x092
db 0x0cf
db 0x00
videosel equ $-gdt
dw 3999
dw 0x8000 ; 基址是0xb8000
db 0x0b
db 0x92
db 0x00
db 0x00
gdt_end
times 510-($-$$) db 0
dw 0x0aa55