在bochs中测试从floppya.img启动系统

时间:2022-09-13 20:43:56

开发环境: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