Songqian Li's Blog

去历史上留点故事

先了解 CPU 的两种工作模式:实模式和保护模式

实模式(英语:Real mode)是 Intel 80286 和之后的 x86 兼容 CPU 的操作模式。实模式的特性是一个 20 比特的区段存储器地址空间(意思为只有 1MB 的存储器可以被寻址),可以直接软件访问 BIOS 程序以及周边硬件,没有任何硬件等级的存储器保护观念或多任务。
保护模式:寻址采用 32 位段和偏移量,最大寻址空间 4GB,最大分段 4GB (Pentium Pre 及以后为 64GB)。在保护模式下 CPU 可以进入虚拟 8086 方式,这是在保护模式下的实模式程序运行环境。
image.png
实模式的寻址方式是:cs<4+ip
MBR 的大小必须是 512 字节,这是为了保证魔数 0x55 和 0xaa 恰好出现在该扇区的最后两个字节处。由于 bochs 模拟的是 x86 平台,所以是小端字节序,故最后两个字节的内容是 0xaa55.

编写 MBR:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
;主引导程序
;-----------------------------------------------------
SECTION MBR vstart=0x7c00
mov ax,cs
mov ds,ax
mov es,ax
mov ss,ax
mov fs,ax
mov sp,0x7c00

; 清屏利用0x06号功能,上卷全部行,则可清屏
; -----------------------------------------------------
; INT 0x10 功能号:0x06 功能描述:上卷窗口
;输入:
;AH 功能号=0x06
;AL = 上卷的行数
;BH = 上卷行属性
;(CL,CH) = 窗口左下角的(X,Y)位置
;(DL,DH) = 窗口右下角的(X,Y)位置
;无返回值
mov ax,0x600
mov bx,0x700
mov cx,0 ; 左上角: (0,0)
mov dx,0x184f ; 右下角:(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=光标开始行,c1=光标结束行
; dh=光标所在行号,dl=光标所在列号

;;;;;;;; 获取光标位置结束 ;;;;;;;;

;;;;;;;; 打印字符串 ;;;;;;;;
; 还是用10h中断,不过这次调用13号子功能打印字符串
mov ax, message
mov bp,ax ; es:bp 为串首地址,es此时同cs一致,
; 开头时已经为sreg初始化

; 光标位置要用到dx寄存器中内容,cx中的光标位置可忽略
mov cx,11 ; cx为串长度,不包括结束符0的字符个数
mov ax, 0x1301 ; 子功能号13显示字符及属性,要存入ah寄存器,
; al 设置写字符方式 ah=01:显示字符串,光标跟随移动
mov bx, 0x2 ; bh存储要显示的页号,此处是第0页,
; bl中是字符属性,属性黑底绿字(bl= 02h)
int 0x10 ; 执行BIOS 0x10号中断
;;;;;;;; 打印字符串结束 ;;;;;;;;

jmp $ ; 程序悬停在此

message db "Hello World"
times 510-($-$$) db 0
db 0x55,0xaa

编译

nasm mbr.S -o mbr.bin

将 MBR 写入磁盘

dd if=./mbr.bin of=./hd60M.img bs=512 count=1 conv=notrunc
输出下述结果,证明写入成功。

1
2
3
1+0 records in
1+0 records out
512 bytes copied, 0.000183707 s, 2.8 MB/s

启动 bochs,在命令行输入 c 回车,此时窗口中显示出打印的字符。

附 1:dd 命令参数解释

1
2
3
4
5
6
if=FILE					#指定要读取的文件
of=FILE #指定要输出到的文件
bs=BYTES #指定块的大小,dd是以块为单位来进行IO操作的,此项是同时配置了输入块大小ibs和输出块大小obs
count=BLOCKS #指定拷贝的块数
seek=BLOCKS #指定当把块输出到文件时想跳过多少块
conv=CONVS #指定如何转换文件

参考文章

  1. 《操作系统真象还原》第 2 章
相关文章
评论
分享
  • 《操作系统真象还原》:第八章 内存管理系统

    8.1 makefile 简介 这部分可参考阮一峰的讲解:https://www.ruanyifeng.com/blog/2015/02/make.html 8.1.1 makefile 是什么 makefile 是 Linu...

    《操作系统真象还原》:第八章 内存管理系统
  • 《操作系统真象还原》:第七章 中断

    7.1 中断是什么,为什么要有中断 运用中断能够显著提升并发,从而大幅提升效率。 7.2 操作系统是中断驱动的 略 7.3 中断分类 把中断按事件来源分类,来自 CPU 外部的中断就称为外部中断,来自 CPU 内部的中断称为内部...

    《操作系统真象还原》:第七章 中断
  • 《操作系统真象还原》:第六章 完善内核

    6.1 函数调用约定简介 咱们实验使用cdecl。这里提一下stdcall,cdecl与stdcall的区别在于由谁来回收栈空间。 stdcall是被调用者清理参数所占的栈空间。 举例来说: 12int subtract(int ...

    《操作系统真象还原》:第六章 完善内核
  • 《操作系统真象还原》:第五章 保护模式进阶——加载内核

    5.3 加载内核 5.3.1 用 C 语言写内核 第一个 C 语言代码: 1234int main(void) { while(1); return 0;} 这个内核文件什么都没做,通过while(1)这个死循...

    《操作系统真象还原》:第五章 保护模式进阶——加载内核
  • 《操作系统真象还原》:第五章 保护模式进阶——内存分页机制

    从这一刻起,我们才算开始了真正的操作系统学习之旅 5.1 获取物理内存容量 5.1.1 Linux 获取内存的方法 在 Linux 2.6 内核总是用detect_memory函数来获取内存容量的。其函数本质上是通过调用 BI...

    《操作系统真象还原》:第五章 保护模式进阶——内存分页机制
  • 《操作系统真象还原》:第四章 保护模式入门

    4.1 保护模式概述 在本章大家会见到全局描述符表、中断描述符表、各种门结构,这是 CPU 提供给应用的,咱们用好就行。 保护模式强调的是“保护”,它是在 Intel 80286 CPU 中首次出现,这是继 8086 之后,Inte...

    《操作系统真象还原》:第四章 保护模式入门
  • 《操作系统真象还原》:第三章 完善MBR——I/O接口

    3.3 让我们对显示器说点什么吧 3.3.1 CPU 如何与外设通信——IO 接口 IO 接口功能: 设置数据缓冲,解决 CPU 与外设的速度不匹配 设置信号电平转换电路 设置数据格式转换 设置时序控制电路来同步 CPU 和外部...

    《操作系统真象还原》:第三章 完善MBR——I/O接口
  • 《操作系统真象还原》:第三章 完善MBR——CPU的实模式

    针对汇编 几个知识点: 第 1 行和第 4 行的 mov 操作,机器码第 1 个宇节都是B8,而另外第 2、3 行同样是 mov 指令,机器码却有天壤之别,似乎找不到共性。原因是机器码是由很多部分组成的,比如指令前缀、主操作码字...

    《操作系统真象还原》:第三章 完善MBR——CPU的实模式
  • 《操作系统真象还原》:第一章 环境配置

    第 0 章:一些你可能正感到迷惑的问题 摘记 0.28 MBR、EBR、DBR 和 OBR 各是什么 MBR 位于整个硬盘最开始的块, EBR 位于每个子扩展分区,各子扩展分区中只有一个逻辑分区。 MBR 和 EBR 位于分...

    《操作系统真象还原》:第一章 环境配置
  • 6月阅读总结

    “零拷贝”技术 Sogou C++ Workflow:搜狗公司的 C++服务器引擎,支持 500k QPS Reducing CPU scheduler latency in Linux:CPU 调度算法 BMQ 和 CFS 的对比...

    6月阅读总结