8086 地址位长度是20,1M的寻址空间。这1M的空间是按如下进行分配的:
起始 | 结束 | 大小 | 作用 |
---|---|---|---|
FFFF0 | FFFFF | 16B | BIOS的入口地址,此地址也属于BIOS代码,同样属于顶部的640K字节。此处16字节的内容是跳转指令jmp f0000:e05b |
F0000 | FFFEF | 64K-16B | 系统BIOS范围是F0000~FFFFF共640K |
C8000 | EFFFF | 160K | 映射硬件适配器的ROM或内存映射式I/O |
C0000 | C7FFF | 32K | 显示适配器BIOS |
B8000 | BFFFF | 32K | 用于文本模式显示适配器 |
B0000 | B7FFFF | 32K | 用于黑白显示适配器 |
A0000 | AFFFF | 64K | 用于彩色显示适配器 |
9FC00 | 9FFFF | 1K | EBDA扩展BIOS数据区 |
7E00 | 9FBFF | 622080B 约608K | 可用区域 |
7C00 | 7DFF | 512B | MBR被BIOS加载到此处 |
500 | 7BFF | 30464B约30K | 可用区域 |
400 | 4FF | 256B | BIOS 数据区 |
000 | 3FF | 1K | 中断向量表 |
高于 1M的是高位内存区和扩展内存。80386,80486,奔腾等最高寻址4G空间。
jmp 0:7c00
。下面就写一段程序加载到7c00,让计算机来引导看是否能启动。
org 07c00h ; 告诉编译器程序加载到7c00处
mov ax, cs
mov ds, ax
mov es, ax
call DispStr ; 调用显示字符串例程
jmp $ ; 无限循环,$代表当前汇编行的地址
DispStr:
mov ax, BootMessage ; 把BootMessage的首地址传给寄存器ax
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, MY OS!" ; 想要开机后在屏幕上显示的字符串
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节 $$表示一个section的开始处汇编后地址
dw 0xaa55 ; 结束标志
把代码保存到nasm的目录,编译:
nasm boot.asm -o boot.bin
选择Write File to Image
提示选择文件先选择Boot.bin,第二次弹窗选择MYOS.IMG
修改上面代码,把org 07c00h
改成 org 0100h
, 就可以编译成一个.com文件在DosBox下运行。
下面使用nasm的预编译宏切换org语句加载的地址:
;%define _BOOT_DEBUG_ ; 做Boot Sector时把这行注释掉
; 启用这行就用nasm Boot.asm -o Boot.com生成.com文件用于调试
%ifdef _BOOT_DEBUG_
org 0100h
%else
org 07c00h
%endif
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, MY OS!" ; 想要开机后在屏幕上显示的字符串
times 510-($-$$) db 0 ; 填充剩下的空间,使生成的二进制代码恰好为512字节
dw 0xaa55 ; 结束标志
VsCode安装 HexDump插件后,在要查看的文件点击键,选择ShowHexdump就可以来查看磁盘镜像的内容:
这里可以看到前512字节就是自己写的汇编程序,以55AA结束。
本文学习资源来自《自己动手写操作系统》于渊 电子工业出版社。