操作系统真象还原——1&2.初见MBR

第1章 部署工作环境

  1. CPU所能理解的指令格式是其在硬件上已经规定的,原则上只要按照IA-32 指令格式往二进制文件中写指令,就能够直接同CPU 对话了

  2. 虚拟机只是一个普通的进程,该进程模拟了硬件资源,在虚拟机中运行的程序其所做出的任何行为都先被虚拟机检查,由虚拟机分析后,代为向操作系统申请。

  3. 实验环境:virualBox + Ubuntu21.04(前提安装gcc、gdb、make、libgtk2.0-dev、xorg-dev、g++、build-essential) + bochs

    • 推荐文章:
      [1]https://blog.csdn.net/weixin_30751947/article/details/94875872?spm=1001.2101.3001.6650.1&utm_medium=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_paycolumn_v2&depth_1-utm_source=distribute.pc_relevant.none-task-blog-2%7Edefault%7ECTRLIST%7Edefault-1.pc_relevant_paycolumn_v2&utm_relevant_index=2
      [2]https://blog.csdn.net/aurorayqz/article/details/80310954
    • 真相还原中的配置自己的bochs安装路径要注意,不要写错了
    • 使用keyboard: keymap=BOCHSPATH/share/bochs/kemaps/x11-pc-us.map,可能版本问题,如果未报此行错误可以不用管
    • 报错dLopen failed for module ‘x’ (libbx_ x.so): file not found(https://blog.csdn.net/weixin_30363981/article/details/97344363)

    操作系统真象还原——1&2.初见MBR_第1张图片

  4. 安装bochs其中最后一个命令是x11不是xll,\是换行符不用写在命令行

第2章 编写MBR主引导记录

  1. 程序载入内存

    • 程序被加载器加载到内存的某个区域
    • CPU的cs : ip 寄存器被指向这个程序的起始地址
  2. 实模式下的内存布局
    操作系统真象还原——1&2.初见MBR_第2张图片

  3. 基本输入输出系统BIOS建立的中断向量表可以使用“int中断号”来实现相关的硬件调用

  4. 地址映射:CPU提交要访问的地址给MMU(内存管理单元),MMU将虚拟地址转化为物理地址去访问ROM、显存或内存(32位系统指的地址总线是32位,这32位的地址不完全是用来访问内存的)

  5. 计算机从加电启动到运行

    • 在计算机POST加电的一瞬间, 计算机主板和其他设备供电,BIOS的控制芯片组会向CPU发出并保持一个RESET(重置)信号,重置CPU内部状态,直到芯片组检测到电源已经开始稳定供电后,便撤去RESET信号
    • CPU 的cs : ip 寄存器被强制初始化为0xF00 : 0xFFF0 。由于开机的时候处于实模式,段基址要左移4 位,于是0xF00 : 0xFFF0 转换地址为BIOS 的入口地址0xFFFF0 (Shadow技术:由于ROM的执行速度远比RAM要低,所以加电后在ROM中的BIOS会被装载到Shadow RAM中的指定区域里。由于Shadow RAM的物理编址与对应的ROM相同,所以当需要访问BIOS时,只需访问Shadow RAM而不必再访问ROM,这就能大大加快计算机系统的运算时间)
    • CPU到地址0xFFFF0处取出跳转指令jmp far f000:e05b,即再跳向0xfe05b处执行BIOS代码,检测外设并进行初始化,完成后在内存中0x000 ~0x3FF 处建立中断向量表并填写中断例程
    • BIOS最后会校验启动盘的0 盘0 道1 扇区(CHS 方式中扇区的编号是从1 开始的,LBA从0开始的),如果此扇区末尾的两个字节分别是魔数0x55 和0xaa, BIOS 便认为此扇区中确实存在可执行的主引导记录MBR ,便加载到物理地址0x7c00 ,随后跳转到此地址继续执行,此时,CPU控制权由BIOS交给MBR。这里有个小细节, BIOS 跳转到0x7c00 是用jmp 0: 0x7c00实现的,这是jmp 指令的直接绝对远转移用法,段寄存器cs 会被替换,这里的段基址 由之前的0xf00 变成了0
  6. 0x7c00的由来

    512字节大小的MBR 被BIOS加载到0x7C00到0x7DFF 处,MBR 是一段程序,程序的运行需要栈的支持,栈也是在内存中的,大约1KB。结合以上三点,选择32KB 中的最后1KB 最为合适,那此地址是多少呢? 32KB 换算为十六进制为0x8000,减去1kb(0x400)的话,即为0x7c00

  7. .bin文件是纯二进制文件,不含伪指令

  8. 当显示器工作在80*25的文本模式(80行25列共2000字符),一个字符用两个字节表示,低位字节是字符的ASCII码,高位字节是字符属性,所以显示一屏字符需要4KB

; 主引导程序MBR
; SECTION是伪指令,cpu不运行,只是方便程序员规划程序分段使用
; `vstart=0x7c00`表示在程序编译时将起始地址编译为0x7c00
; SS存放栈顶的段地址,SP存放栈顶的偏移地址。在任何时刻 ,SS:SP都是指向栈顶元素 
; CS存放内存中代码段入口的段基址,CS:IP表示下一条要运行的指令内存地址   
    
; 初始化部分
SECTION MBR vstart=0x7c00 ; =前后不能有空格
	mov ax,cs			; 由于BIOS是通过`jmp 0:Ox7c00`转到MBR的,故cs此时为0
    mov ds,ax			; 段寄存器不能使用立即数进行赋值,可以使用通用寄存器ax
    mov es,ax
    mov ss,ax
    mov fs,ax
	mov sp,0x7c00
        
; 使用10号中断的0x06功能号,进行窗口上卷清屏,避免BIOS检测信息影响显示
	mov ax,0x600		; ah存放将要调用的中断子功能号
    mov bx,0x700
    mov cx,0			; (CL,CH)=窗口左上角的(X,Y)位置
    mov dx,0x184f		; (DL,DH)=窗口右下角的(X,Y)位置(80,25)
    int 0x10			; 调用中断
  
; 使用10号中断的0x03功能号,获取光标位置 
	mov ah,3			; 将中断子功能号存入ah寄存器等待被调用
    mov bh,0			; 存放待获取光标的页号
    int 0x10			
 ; 调用中断后,ch=光标开始行,cl=光标结束行,dh=光标所在行号,dl=光标所在列号
 
 ; 打印字符串
	mov ax,message		
    mov bp,ax			; es:bp为串首地址
    mov cx,5			; cx存放串长度,不包括结束符0的字符个数
    mov ax,0x1301		; ah表示调用13号子功能,al表示写字符方式01(光标跟随显示)
    mov bx,0x2			; bh存储要显示的页号,bl是字符属性(02h表示黑底绿字)
    int 0x10

; $表示本行指令所在的地址,$$表示本section的起始地址,$-$$表示执行代码行到段首的偏移量
	jmp $					; 在本行代码死循环
    message db "ws MBR"
    times 510-($-$$) db 0	; 将剩余字节用0进行填充
    db 0x55,0xaa			; 最后两个字节填充MBR的标识
  1. 安装nasm命令sudo apt-get install nasm

  2. dd命令是linux自带的,不需要安装

  3. 将mbr汇编文件放到bochs文件夹下的运行脚本

#!/bin/bash
rm -rf ./hd.img
bin/bximage -hd -mode=“flat” -size=60 -q hd.img
echo “disk creat success!!”
nasm mbr.s -o mbr.bin
dd if=mbr.bin of=hd.img bs=512 count=1 conv=notrunc
echo “disk write success!!”
bin/bochs -f bochsrc

你可能感兴趣的:(深入理解操作系统,linux,运维,服务器)