目录
引用与说明
- 《操作系统真相还原》,作者:郑钢
- kanshanxd的博客:《操作系统真象还原》第二章 编写MBR主引导记录,让我们开始掌权_第2章 编写mbr主引导记录,让我们开始掌权-CSDN博客
- 除原书外其他引用均在段落末首尾标记“【引】”,再次感谢郑钢与kanshanxd的开源!
建议略读章节 |
---|
2.2.3、为什么是 0x7c00 |
2.3.1、神奇好用的 $ 和 $$,令人迷惑的 section |
2.3.2、NASM 简单用法 |
2.1、计算机的启动过程
1、“载入内存”的概念
2.2、软件接力第一棒,BIOS
1、BIOS的概念
BIOS,全称 Base Input & Output System,基本输入输出系统。这个 “基本” 体现在:BIOS 建立的功能是对硬件的输入输出操作,由于 BIOS 在实模式下的 1MB 内存布局中只分配到内存 0xF0000 ~ 0xFFFFF 共 64KB 大小的空间,不可能把所有硬件的 IO 操作实现得面面俱到,所以挑一些重要的、保证计算机能运行的那些硬件的基本 IO 操作,其他的在进入保护模式以后才开始。
2、BIOS是如何苏醒的
【A2.3】【A2.4】
BIOS是由只读存储器ROM硬件加载的。ROM 这种存储介质用来存储一成不变的数据,BIOS 代码所作的工作也是一成不变的,因此 BIOS 被写进此 ROM。ROM 是块内存,此 ROM 被映射到低端1MB 内存的顶部,即地址 0xF0000~0xFFFFF 处,参考表2-1。只要访问此处的地址就是访问BIOS,该映射是由硬件完成的。BIOS 本身是个程序,该程序执行时的入口地址便是 0xFFFF0。
【补充】
cs:ip 的概念
CS 和 IP 为两个寄存器,分别是代码段寄存器和指令指针寄存器,CS 寄存器用于存储当前代码段的起始地址,也就是段基址;IP 寄存器用于存储下一个要执行的指令在代码段中的偏移量,也就是段内偏移地址,这个偏移量与 CS 寄存器中的段基地址结合,计算出最终指令的物理地址。IP 会在每次执行完一条指令后自动更新,指向下一条要执行的指令。综合来看,CS 和 IP 共同作用,以确定当前正在执行的指令的完整地址。
【A2.5】
通过【A2.4】知道了 BIOS 在哪里后,CPU 如何去执行它,即 CPU 中的 cs:ip 值是如何组成 0xFFFF0 的?
在开机接电的一瞬间,CPU 的 cs:ip 寄存器被强制初始化为 0xF000:0xFFF0。由于开机的时候处于实模式,在实模式下的段基址要乘以16,也就是二进制左移4位(16进制左移1位),于是 0xF000:0xFFF0 的等效地址将是 0xFFFF0(0xF000 左移1位 + 0xFFF0)。0xFFFF0 便是 BIOS 的入口地址。
所以没有谁修改 BIOS 的 cs:ip,加电时强制初始化。
【Q2.6】:0xFFFF0 到 1MB 这么小的空间如何实现 BIOS 如此多的功能?
【A2.6】
BIOS 是在实模式下运行的,而实模式只能访问 1MB 空间(20位地址线,2的20次方是 1MB)。而 0xFFFF0 距 1MB 只有16个字节。这么小的空间当然是不能完成那么多功能的,所以 0xFFFF0 这个地址存放着一条指令,该指令内容是跳转至 BIOS 程序的入口(该指令由跳转指令与 BIOS 程序的入口地址组成,共16B)。【引】
3、BIOS 与 MBR 的功能
BIOS 有四个主要功能:1、硬件自检;2、建立一些需要用到的数据结构与中断向量表;3、校验启动盘中位于0盘0道1扇区(其实就是0扇区,只不过 CHS 方法用1开头)的内容,校验这里是不是放着主引导记录 MBR,校验方法是检测这个扇区最后两个字节是不是 0x55 与 0xaa(所以我们编写的主引导记录 MBR 最后两个字节应该是这两个);4、在3的基础上是,那么就将该扇区内容加载至 0x7c00 内存处,这个位置是由于历史遗留导致的兼容,由最初的操作系统本身所占内存大小与布局所决定(书p58)。加载完毕后,然后跳转过去执行。【引】
MBR 的任务是加载 loader(一般是内核加载器),由 loader 加载操作系统到指定位置,然后执行加载过来的操作系统。MBR 大小必须是512字节,这是为了占满硬盘0盘0道1扇区,保证最后两个字节恰好是0x55与0xaa。【引,改】
代码实现
p61代码mbr.S剖析
- 主要目的是编写一段独立于操作系统之外的程序,用来体验感受一下编写MBR。
- 实操过程推荐看见南山的视频:用《操作系统真象还原》写一个操作系统 第二章 编写MBR主引导记录,让我们开始掌权_哔哩哔哩_bilibili
【引】
;主引导程序
;------------------------------------------------------------
SECTION MBR vstart=0x7c00 ;起始地址编译为 0x7c00
mov ax,cs ;此时cs寄存器为0,自然可以用来将ax寄存器置0
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00
; 清屏 利用0x06号功能,上卷全部行,则可清屏。
; -----------------------------------------------------------
;INT 0x10 功能号:0x06 功能描述:上卷窗口
;------------------------------------------------------
;输入:
;AH 功能号= 0x06
;AL = 上卷的行数(如果为0,表示全部)
;BH = 上卷行属性
;(CL,CH) = 窗口左上角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值:
mov ax, 0x600 ;ah中输入功能号
mov bx, 0x700 ;设置上卷行属性,0x70表示用黑底白字的属性填充空白行
mov cx, 0 ;左上角: (0, 0)
mov dx, 0x184f ;右下角: (80,25),
;VGA文本模式中,一行只能容纳80个字符,共25行。
;下标从0开始,所以0x18=24,0x4f=79
int 0x10 ;int 0x10
;;;;;;;;; 下面这三行代码是获取光标位置 ;;;;;;;;;
;.get_cursor获取当前光标位置,在光标位置处打印字符。
mov ah, 3 ;输入: 3号子功能是获取光标位置,需要存入ah寄存器
mov bh, 0 ;bh寄存器存储的是待获取光标的页号
int 0x10 ;输出: ch=光标开始行,cl=光标结束行
;dh=光标所在行号,dl=光标所在列号
;;;;;;;;; 获取光标位置结束 ;;;;;;;;;;;;;;;;
;;;;;;;;; 打印字符串 ;;;;;;;;;;;
;还是用10h中断,不过这次是调用13号子功能打印字符串
mov ax, message
mov bp, ax ; es:bp 为串首地址, es此时同cs一致,
; 开头时已经为sreg初始化
; 光标位置要用到dx寄存器中内容,cx中的光标位置可忽略
mov cx, 5 ; cx 为串长度,不包括结束符0的字符个数
mov ax, 0x1301 ; 子功能号13是显示字符及属性,要存入ah寄存器,
; al设置写字符方式 ah=01: 显示字符串,光标跟随移动
mov bx, 0x2 ; bh存储要显示的页号,此处是第0页,
; bl中是字符属性, 属性黑底绿字(bl = 02h,07是黑底白字)
int 0x10 ; 执行BIOS 0x10 号中断
;;;;;;;;; 打字字符串结束 ;;;;;;;;;;;;;;;
jmp $ ; 使程序悬停在此
message db "1 MBR"
times 510-($-$$) db 0
db 0x55,0xaa
其他问题
【Q】在 CPU 眼里,为什么我们插在主板上的物理内存不是它眼里“全部的内存”?【P53】
【A】【P54】
【Q】CPU 为什么采用分段方式(段地址 + 偏移地址)访问内存?【P55】
【A】【P4】
【Q】为什么运行 MBR 需要跳转至地址 0x7c00?【P56】
【A】 【P56】
【Q】”0x55“、”0xaa“是魔数,什么是魔数?【P58】
【A】【P29】
【Q】”0xaa55“是x86平台的小端字节序表示,什么是”小端字节序“【P58】
【A】【P19】