文章目录
- 一. 编写MBR
- 1 实模式下显示字符的基本工作原理
- 2. 代码 MBR Master Boot Record
- 3.CPU的特性
- 4 编译运行
一. 编写MBR
1 实模式下显示字符的基本工作原理
显卡都有自己的存储器,因为它位于显卡上,故称显示存储器(Video RAM: VRAM),简称显存,要显示的内容都预先写入显存。和其他半导体存储器一样,显存并没有 什么特殊的地方,也是一个按字节访问的存储器件
1.1 图形模式 原理
显卡的工作是周期性地从显存中取这些比特,并把它们按顺序显示在屏幕上。如果是比特“0”,则像素保持原来的状态不变,因为屏幕本来就是黑的;如果是比特“1”,则点亮对应的像素。
图形模式的问题
操作显存里的比特,使得屏幕上能显示出字符的形状,是非常麻烦、非常繁重的工作, 因为你必须计算该字符所对应的比特位于显存里的什么位置。
1.2 文本模式 原理
就像一个二进制数既可以是一个普通的数,也可以代表 一条处理器指令一样,他们认为每个字符也可以表示成一个数。比如,数字 0x4C 就代表字符“L”, 这个数被称为是字符“L”的 ASCII 代码
可以将字符的代码存放到显存里,第 1 个代码对应着屏幕左上角第 1 个字符, 第 2 个代码对应着屏幕左上角第 2 个字符,后面的依次类推。剩下的工作是如何用代码来控制屏幕 上的像素,使它们或明或暗以构成字符的轮廓,这是字符发生器和控制电路的事情
1.2.1 文本模式 为什么需要引入内存映射
处理器需要访问显存,把字符的 ASCII 码写进去,
显存是位于显卡上的,CPU访问显存需要和显卡这个外围设备打交道。同时,多一道手续自然是不好的,这当中最重要的考量是速度和效率
计算机系统的设计者们,这些拥有聪明脑瓜子的人,决定把显存映射到处理器可以直接访问的 地址空间里,也就是内存空间里
1.2.2 显存映射至内存的分布
F0000~FFFFF:属于ROM-BIOS 64kb
A0000~BFFFF:这段内存空间由特定的外围设备提供
B8000~BFFFF:显存映射至内存的空间
计算空间:
let biosMem=0xFFFFF-0xF0000+1;
let peripheralMem=0xEFFFF-0xA0000+1;
let videoMem=0xBFFFF-0xB8000+1;
console.log(`每个内存单元1Byte,BIOS占:${biosMem}个`)
console.log("BIOS:",biosMem/1024,"KB")
console.log("外围设备:",peripheralMem/1024,"KB")
console.log("外围设备显存映射:",videoMem/1024,"KB")
输出结果:
let biosMem=0xFFFFF-0xF0000+1;
let peripheralMem=0xEFFFF-0xA0000+1;
let videoMem=0xBFFFF-0xB8000+1;
console.log(`每个内存单元1Byte,BIOS占:${biosMem}个`)
console.log("BIOS:",biosMem/1024,"KB")
console.log("外围设备:",peripheralMem/1024,"KB")
console.log("外围设备显存映射:",videoMem/1024,"KB")
1.2.3 显卡加电自检后的文本模式
在加电自检之后都会把自己初始化到 80×25 的文本模式。在这种模式下,屏幕上可以显示 25 行,每行 80 个字符,每屏总共 2000 个 字符
这里应该是指的每屏显示2000个字符,而不是说的总共,根据计算:
//32kb的显存映射空间
console.log(32*1024/2)
最多显示字符:
16384个
1.2.4字符显示属性
字符的显示属性(1 字节)分为两部分,
低 4 位定义的是前景色,
高 4 位定 义的是背景色。
色彩主要由 R、G、B 这 3 位决定,
可以由红®、绿(G)、蓝 (B)三原色来配出其他所有颜色。
K 是闪烁位,为 0 时不闪烁,为 1 时闪烁;
I 是亮度位,为 0时正常亮度,为 1 时呈高亮
2. 代码 MBR Master Boot Record
;------------------------------- 显示字符 XXOS MBR Hi: ----------------------------
;访问内存可以使用段寄存器 DS,但这不是强制性的,也可以使用 ES。
;因为 DS 还有别的用处, 所以在这里我们使用 ES 来指向显存所在的段
;DS: Data Segment
;ES: Extend Segment
mov ax,0xb800 ;指向文本模式的显示缓冲区
mov es,ax ;设置附加段寄存器 ES为0xb800
; ?:为什么不直接mov es,0xb800
;以下显示字符串"Label offset:"
; ?:为什么要声明 byte
; ?:为什么是[es:0x00]而不是[0x00]
mov byte [es:0x00],'X' ;1.设置字符显示内容
mov byte [es:0x01],0x07 ;2.设备字符显示属性
mov byte [es:0x02],'X'
mov byte [es:0x03],0x07
mov byte [es:0x04],'O'
mov byte [es:0x05],0x07
mov byte [es:0x06],'S'
mov byte [es:0x07],0x07
mov byte [es:0x08],' '
mov byte [es:0x09],0x07
mov byte [es:0x0a],'M'
mov byte [es:0x0b],0x07
mov byte [es:0x0c],'B'
mov byte [es:0x0d],0x07
mov byte [es:0x0e],'R'
mov byte [es:0x0f],0x07
mov byte [es:0x10],''
mov byte [es:0x11],0x07
mov byte [es:0x12],'H'
mov byte [es:0x13],0x07
mov byte [es:0x14],'i'
mov byte [es:0x15],0x07
mov byte [es:0x16],'!'
mov byte [es:0x17],0x07
mov byte [es:0x18],''
mov byte [es:0x19],0x07
;-------------------------------显示字符 除法运算 显示结果--------------------------------
;被除数 ÷ 除数= 商 and 余数
mov ax,number ;取得标号number的偏移地址
mov bx,10 ;除数
;设置数据段的基地址
mov cx,cs ;?: mov cx,cs mov ds,cx这里的含义是什么?
mov ds,cx
;求个位上的数字
mov dx,0
div bx
mov [0x7c00+number+0x00],dl ;保存个位上的数字 ;?:为什么是mov [0x7c00+number+0x00],dl
;求十位上的数字
xor dx,dx ;?:xor dx,dx 这里的含义是什么?
div bx
mov [0x7c00+number+0x01],dl ;保存十位上的数字
;求百位上的数字
xor dx,dx
div bx
mov [0x7c00+number+0x02],dl ;保存百位上的数字
;求千位上的数字
xor dx,dx
div bx
mov [0x7c00+number+0x03],dl ;保存千位上的数字
;求万位上的数字
xor dx,dx
div bx
mov [0x7c00+number+0x04],dl ;保存万位上的数字
;以下用十进制显示标号的偏移地址
mov al,[0x7c00+number+0x04]
add al,0x30 ;:? 为什么需要 add al,0x30
mov [es:0x1a],al ;:? 为什么是 mov [es:0x1a],al
mov byte [es:0x1b],0x04
mov al,[0x7c00+number+0x03]
add al,0x30
mov [es:0x1c],al
mov byte [es:0x1d],0x04
mov al,[0x7c00+number+0x02]
add al,0x30
mov [es:0x1e],al
mov byte [es:0x1f],0x04
mov al,[0x7c00+number+0x01]
add al,0x30
mov [es:0x20],al
mov byte [es:0x21],0x04
mov al,[0x7c00+number+0x00]
add al,0x30
mov [es:0x22],al
mov byte [es:0x23],0x04
mov byte [es:0x24],'D'
mov byte [es:0x25],0x07
infi: jmp near infi ;无限循环 ;: infi: jmp near infi 为什么这里是无限循环
number db 0,0,0,0,0 ;?:number是什么意思 db是什么意思
times 203 db 0 ;times是什么意思
db 0x55,0xaa ;db 0x55,0xaa
3.CPU的特性
以下是总结的防坑指南,其实也就是CPU的一些规定,或者是一些小白容易犯错的地方,共勉
3.1 段寄存器赋值
Intel 的处理器不允许将一个立即数传送到段寄存器
错误:
mov ex,0xb800
正确:
mov 段寄存器,通用寄存器
mov 段寄存器,内存单元
3.3 为什么需要声明byte?
mov byte [es:0x01],0x07
因为在16bit的处理器下,0x07,即可以表示8位的立即数,也可以表示为16bit中的0x0007,因此需要指明传输的是byte
mov [0x00],AL ;按字节操作
mov AX,[0x02] ;按字操作
;这里就不用指明,byte还是word,因为AL为8bit,AX为16bit
3.4 为什么需要申明[es:0x01]?
mov byte [es:0x01],0x07
因为默认访问内存使用 DS 寄存器
访问内存可以使用段寄存器 DS,但这不是强制性的,也可以使用 ES。因为 DS 还有别的用处, 所以在这里我们使用 ES 来指向显存所在的段
mov [0x00],AL ;这种写法表明,使用DS段基址寄存器,DS:0000
3.5 为什么mov cx,cs mov ds,cx这里的含义是什么?
电脑开机-BIOS开机自检-加载MBR-跳转至0x0000:7c00处开始执行MBR代码
mov cx,cs
mov ds,cx
这里表示代码段基址和数据段基址为同一个段地址 0x0000
但代码段和数据段的偏移地址却不同,一个是0x00000000,一个是0x0000012E
3.6 为什么是mov [0x7c00+number+0x00],dl 为什么加0x7c00
nasm编译后,编译是从0x0000000开始编译的,可以理解为汇编地址/偏移地址,BIOS把MBR是加载到物理地址0x0000:7c000处的
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-d8hCcDpe-1624030116069)(/Users/software/Library/Application Support/typora-user-images/image-20210618224630428.png)]
ds为数据段0x0000:偏移地址0x7c00+0x012E+0x00,因此这里要加上物理地址
3.7 xor dx,dx 这里的含义是什么?
xor为异或,也就是 在 或运算
的基础上(有一个输入为真则为真),还要保证两个输入不同
这里表示把dx置为0,(可忽略部分–>:同时也表示被除数为32位的二进制,往下看)
in in out
0 0 = 0
1 0 = 1
0 1 = 1
1 1 = 0
3.8 汇编中的除法
16位二进制除法: ax ÷ cl =al…ah 除数可以由 8 位的通用寄存器或者内存单元供
div byte [0x0230]
32位二进制除法:dx:ax ÷ cx = ax…dx 除数可以由 8 位的通用寄存器或者内存单元供
div word [0x0230]
3.9 :? 为什么需要 add al,0x30
因为比如数字1+0x30,刚好对应ASCALL码 “1”:0x31
3.10 为什么是 mov [es:0x1a],al
为了接着XXOS MBR Hi: 继续填充显存映射内存的地址
3.11 infi: jmp near infi 为什么这里是无限循环
数字显示完成后,原则上整个程序就结束了,但对处理器来说,它并不知道。对它来说,取指令、执行是永无止境的
jmp 是转移指令,用于使处理器脱离当前的执行序列,转移到指定的地方执行,关键字 near 表 示目标位置依然在当前代码段内
也就是说,它将会不停地重复执行自己
如果这里不让CPU无限循环的话,CPU会继续执行到number db 0,0,0,0,0,CPU把数据当成指令执行,那么悲剧就发生了
3.12 number是什么意思
number为标号number db 0,0,0,0,0 代表 db 0,0,0,0,0的汇编地址,在nasm编译阶段会被替换为具体的汇编地址/偏移地址
3.13 db是什么意思
db—>Declare Byte:声明
在程序中声明并初始化数据, 为数据区
3.14 times是什么意思
times为伪指令,告诉nasm,在汇编器nasm编译阶段发生,填充剩余空间为0
重复执行次数,填充0
3.15 db 0x55,0xaa
根据规定512Byte,最后两个字节必须为0x55,0xaa,这样才能被识别被MBR程序
4 编译运行
nasm c05_mbr.asm -l c05_mbr.lst -o c05_mbr.bin
dd if=c05.bin of=a.img bs=512 count=1 conv=notrunc
bochs -f bochsout.txt
爽了一下,说明一下mac下的bochs,感觉有点不友好,在显存映射内存区域填充了其他信息,改天把它清除,看着确实不爽