debian配置Bochs环境开发asm程序

1 .安装 bochs

apt install  bochs  bochs-x  bochsbios  vgabios

2. 创建硬盘映像

bximage -q -hd=16 -func=create -sectsize=512 -imgmode=flat main.img



========================================================================
                                bximage
  Disk Image Creation / Conversion / Resize and Commit Tool for Bochs
         $Id: bximage.cc 14091 2021-01-30 17:37:42Z sshwarts $
========================================================================

Creating hard disk image 'main.img' with CHS=32/16/63 (sector size = 512)

The following line should appear in your bochsrc:
  ata0-master: type=disk, path="main.img", mode=flat

创建一个 16M大小,扇区大小为512B 的硬盘

3. 生成配置模板

在shell里直接运行

bochs

会出现选项 界面

------------------------------
Bochs Configuration: Main Menu
------------------------------

This is the Bochs Configuration Interface, where you can describe the
machine that you want to simulate.  Bochs has already searched for a
configuration file (typically called bochsrc.txt) and loaded it if it
could be found.  When you are satisfied with the configuration, go
ahead and start the simulation.

You can also start bochs with the -q option to skip these menus.

1. Restore factory default configuration
2. Read options from...
3. Edit options
4. Save options to...
5. Restore the Bochs state from...
6. Begin simulation
7. Quit now

Please choose one: [2] 

输入 4, 也就是保存选项配置文件
然后输入配置文件名 softsimrc (默认是 bochsrc)
再输入 7 , 也就是选择退出。

这个时候,在命令运行的当前目录下就会有一个生成的配置文件 softsimrc

4. 修改配置文件
将 boot: floppy 改成 boot: disk 得以从硬盘启动
将 display_library: x 改成 display_library: x, options=”gui_debug” 支持GUI方式的调试
将 floppya: type=1_44 改成 # noflpyya
将 ata0-master: type=none 改成 ata0-master: type=disk, path=”main.img”, mode=flat

完整的配置文件如下

# configuration file generated by Bochs
plugin_ctrl: busmouse=false, iodebug=true, gameport=true, speaker=true, voodoo=false, sb16=false, usb_ohci=false, usb_ehci=false, usb_xhci=false, unmapped=true, usb_uhci=false, pcidev=false, serial=true, extfpuirq=true, ne2k=false, pcipnic=false, e1000=false, parallel=true, biosdev=true, es1370=false
config_interface: textconfig
display_library: x, options="gui_debug"
memory: host=32, guest=32
romimage: file="/usr/share/bochs/BIOS-bochs-latest", address=0x00000000, options=none
vgaromimage: file="/usr/share/bochs/VGABIOS-lgpl-latest"
boot: disk
floppy_bootsig_check: disabled=0
# noflpyya   floppya: type=1_44
# no floppyb
ata0: enabled=true, ioaddr1=0x1f0, ioaddr2=0x3f0, irq=14
ata0-master: type=disk, path="main.img", mode=flat
ata0-slave: type=none
ata1: enabled=true, ioaddr1=0x170, ioaddr2=0x370, irq=15
ata1-master: type=none
ata1-slave: type=none
ata2: enabled=false
ata3: enabled=false
optromimage1: file=none
optromimage2: file=none
optromimage3: file=none
optromimage4: file=none
optramimage1: file=none
optramimage2: file=none
optramimage3: file=none
optramimage4: file=none
pci: enabled=1, chipset=i440fx, slot1=none, slot2=none, slot3=none, slot4=none, slot5=none
vga: extension=vbe, update_freq=5, realtime=1, ddc=builtin
cpu: count=1:1:1, ips=4000000, quantum=16, model=bx_generic, reset_on_triple_fault=1, cpuid_limit_winnt=0, ignore_bad_msrs=1, mwait_is_nop=0
cpuid: level=6, stepping=3, model=3, family=6, vendor_string="AuthenticAMD", brand_string="AMD Athlon(tm) processor"
cpuid: mmx=true, apic=xapic, simd=sse2, sse4a=false, misaligned_sse=false, sep=true
cpuid: movbe=false, adx=false, aes=false, sha=false, xsave=false, xsaveopt=false, avx_f16c=false
cpuid: avx_fma=false, bmi=0, xop=false, fma4=false, tbm=false, x86_64=true, 1g_pages=false
cpuid: pcid=false, fsgsbase=false, smep=false, smap=false, mwait=true, vmx=1, svm=false
print_timestamps: enabled=0
debugger_log: -
magic_break: enabled=0
port_e9_hack: enabled=0
private_colormap: enabled=0
clock: sync=none, time0=local, rtc_sync=0
# no cmosimage
log: -
logprefix: %t%e%d
debug: action=ignore
info: action=report
error: action=report
panic: action=ask
keyboard: type=mf, serial_delay=250, paste_delay=100000, user_shortcut=none
mouse: type=ps2, enabled=false, toggle=ctrl+mbutton
sound: waveoutdrv=alsa, waveout=none, waveindrv=alsa, wavein=none, midioutdrv=alsa, midiout=none
speaker: enabled=true, mode=sound, volume=15
com1: enabled=true, mode=null
com2: enabled=false
com3: enabled=false
com4: enabled=false
parport1: enabled=true, file=none
parport2: enabled=false

5. 测试运行

bochs -q -f softsimrc

如果没有报错,说明配置成功

6. 测试一段汇编代码

mov ax, 0xb800
mov ds, ax

mov byte [0], 'T'

halt:
    jmp halt

times 510 - ($ - $$) db 0
db 0x55, 0xaa

启动后死循环的代码, 将上面的内容保存为 hello.asm文件

将其汇编 成bin, 不过默认就是bin格式

 -f format     select output file format
       bin                  Flat raw binary (MS-DOS, embedded, ...)  default
       aout                 Linux a.out
       elf32                ELF32 (i386) (Linux, most Unix variants)
       elf64                ELF64 (x86-64) (Linux, most Unix variants)
       elfx32               ELFx32 (ELF32 for x86-64) (Linux)
       win32                Microsoft extended COFF for Win32 (i386)
       win64                Microsoft extended COFF for Win64 (x86-64)
....
nasm -f bin    hello.asm -o    hello.bin

将bin代码写入到硬盘的 mbr, 也就是第1个扇区

dd if=hello.bin of=main.img bs=512 count=1 conv=notrunc

再次启动 bochs

bochs -q -f softsimrc

另外一段死循环代码

; 死循环,CPU一直停留在此行
jmp $

; $     表示当前指令所在地址
; $$     表示当前段的起始地址
; times 表示重复某个指令n次
; 一个扇区的大小一般是512KB
; 当你的代码不足512KB时剩下的就需要0来填充
; db 0就是写入一个字节的0x0
; 为什么不是512而是510呢?
; 因为MBR程序最后需要留两个字节来写入魔数0xaa55
times 510-($-$$) db 0

; MBR程序最后两个字节必须为0xaa55,由于Linux下为小端序,因此先写55
db 0x55, 0xaa

7.启动过程

处理器加电或者复位之后,如果硬盘是首选的启动设备,那么 ROM-BIOS 将试图读取硬盘的第一个扇区(编号从0开始),这个扇区就是主引导扇区 (MBR, Main Boot Sector)。

读取的主引导扇区数据有 512 字节,ROM-BIOS 程序将它加载到逻辑地址 0x0000:0x7c00 处,也就是物理地址 0x07c00 处,然后判断它是否有效。

一个有效的主引导扇区,其最后两个字节应该是 0x55 和 0xAA。ROM-BIOS 程序首先检测这两个标志,如果主引导扇区有效,则以一个段间转义指令 jmp 0x0000:0x7c00 跳转到那里继续执行。

一般主引导扇区程序用于加载操作系统内核,可能会有多级加载,毕竟 512 字节的代码可以实现的功能有限。

8. 实模式下的内存布局

起始地址 	结束地址 	大小 	用途
0x000 	       0x3FF 	     1KB 	          中断向量表
0x400 	       0x4FF 	   256B 	BIOS 数据区
0x500 	       0x7BFF 	    29.75 KB 	可用区域
0x7C00 	       0x7DFF 	    512B 	MBR 加载区域
0x7E00 	        0x9FBFF 	607.6KB 	可用区域
0x9FC00 	0x9FFFF 	1KB 	扩展 BIOS 数据区
0xA0000 	0xAFFFF 	64KB 	用于彩色显示适配器
0xB0000 	0xB7FFF 	32KB 	用于黑白显示适配器
0xB8000 	0xBFFFF 	32KB 	用于文本显示适配器
0xC0000 	0xC7FFF 	32KB 	显示适配器 BIOS
0xC8000 	0xEFFFF 	160KB 	映射内存
0xF0000 	0xFFFEF 	64KB-16B 	系统 BIOS
0xFFFF0 	0xFFFFF 	16B 	系统 BIOS 入口地址

中断向量表 (IVT Interrupt Vector Table)
映射内存表示:映射硬件适配器 ROM 或者 内存映射式 I/O
BIOS 入口地址,此处的 16 字节的内容是跳转指令 jmp f000:e05b

可以看到,我们能够使用的内存区域只有两块,0x500 ~ 0x7BFF 和 0x7E00 ~ 0x9FBFF,这两个内存区域是一定可用的,如果要使用超过 1M 内存区域之外的内存,这样每个机器的内存大小可能都不一样,所以后面的内存就不一定有了。

显存—-
可以看到 0xb8000 开始的 32KB 用于文本显示适配器,也就是说这 32K 的内存区域是用来操作显示器的,一般而言,操作硬件都需要输入和输出操作,但是显示器对于计算机来说太重要了。所以就把这块内存映射到了显示器,用来显示字符。0xb8000 – 0xbffff 是留给显卡的,由显卡来提供。

由于历史原因,所有在个人计算机上使用的显卡,在加电自检后都会把自己初始化到 80×25 的文本模式,在这种模式下可以显示 25 行,每行 80 个字符,每屏总共 2000 个字符。

起始地址—-
0x7c00 最早出现在 IBM 公司出产的个人电脑 PC 5150 ROM BIOS 的INT19H 中断处理程序中,通电开机之后,BIOS 处理程序开始自检,随后,调用 BIOS 中断 0x19h ,即 call int 19h。在此中断处理函数中, BIOS 要检测这台计算机有多少硬盘或软盘,如果检测到了任何可用的磁盘, BIOS 就把它的第一个扇区加载到 0x7c00。它是属于 BIOS 中的规范。既然是 BIOS 中的规范,那肯定是 IBM PC 5150 BIOS 开发团队规定的这个数。

8086 CPU 要求物理地址。0x0~Ox3FF 存放中断向量表,所以此处不能动了,再选新的地方看看。

按 DOS 1.0 要求的最小内存 32KB 来说, MBR 希望给人家尽可能多的预留空间,这样也是保全自己的作法,免得过早被覆盖。所以MBR 只能放在 32KB 的末尾。

MBR 本身也是程序,是程序就要用到栈,栈也是在内存中的,MBR 虽然本身只有 512 字节,但还要为其所用的栈分配点空间,所以其实际所用的内存空间要大于 512 字节,当时估计 1KB 内存够用了。

结合以上三点,选择 32KB 中的最后 1KB 最为合适,那此地址是多少呢? 32KB 换算为十六进制为 0x8000, 减去 1KB(0x400) 的话,等于 0x7c00。这就是倍受质疑的 0x7c00 的由来。
———
9. 显示英文 hello,world


mov ax, 3
int 0x10 ; 设置显示模式为文本模式(清屏)

mov ax, 0xb800
mov ds, ax

mov byte [0], 'h'
mov byte [2], 'e'
mov byte [4], 'l'
mov byte [6], 'l'
mov byte [8], 'o'
mov byte [10], ','
mov byte [12], ' '
mov byte [14], 'w'
mov byte [16], 'o'
mov byte [18], 'r'
mov byte [20], 'l'
mov byte [22], 'd'


halt:
    jmp halt

times 510 - ($ - $$) db 0
db 0x55, 0xaa

debian配置Bochs环境开发asm程序》有一个想法

  1. Pingback引用通告: bochs dos6.22 nasm 2.16 | 软sim卡

发表回复

您的电子邮箱地址不会被公开。 必填项已用*标注