目录
本文是笔者学习《操作系统真象还原》的读书笔记,若有侵权,请联系删除。笔者也是处于学习阶段,所陈述的内容如有错误,欢迎指正!
实模式下的内存布局
起始 | 结束 | 大小 | 用途 |
FFFF0 | FFFFF | 16B | BIOS 入口地址,内容是跳转指令 |
F0000 | FFFEF | 64KB-16B | 系统BIOS范围 |
C8000 | EFFFF | 160KB | 映射硬件适配器的ROM或者内存映射式I/O |
C0000 | C7FFF | 32KB | 显示适配器BIOS |
B8000 | BFFFF | 32KB | 文本模式显示适配器 |
B0000 | B7FFF | 32KB | 黑白显示适配器 |
A0000 | AFFFF | 64KB | 彩色显示适配器 |
9FC00 | 9FFFF | 1KB | EBDA扩展BIOS数据区 |
7E00 | 9FBFF | 约608KB | 可用区域 |
7C00 | 7DFF | 512B | MBR被BIOS加载到此处 |
500 | 7BFF | 约30KB | 可用区域 |
400 | 4FF | 256KB | BIOS数据区 |
000 | 3FF | 1KB | 中断向量表 |
一、BIOS
BIOS全称叫Base Input & Output System,即基本输入输出系统
1、BIOS的工作
由实模式下的内存分布可知,0xF0000~0xFFFFF,这64KB的内存是ROM,里面存的是BIOS的代码。BIOS的主要工作就是检测、初始化硬件。硬件自己提供了初始化的功能调用,BIOS直接调用即可完成初始化硬件。BIOS还建立了中断向量表,这样一来就可以通过“int 中断号”来实现硬件的相关调用,这些功能是对硬件的IO操作,在实模式下,不需要把所有硬件的IO操作都面面俱到,只需要实现一些重要的、保证计算机能运行的那些硬件的基本IO操作即可。
2、BIOS的启动
BIOS是计算机上第一个运行的软件,所以它不可能由自身加载,只能由硬件加载。BIOS存储于只读存储器ROM,所以BIOS一直在里面不动的。BIOS本身是程序,程序要执行,其入口地址为0xFFFF0。CPU中的cs:ip如何组合出该地址呢?这是由硬件在接电瞬间将cs:ip强制初始化为0xF000:0xFFF0。其实,0xFFFF0处,仅仅有一个跳转指令,由该跳转指令跳转到BIOS代码开始的地方。
二、为什么插在主板上的内存不是CPU眼中的“全部内存”?
内存地址0~0x9FFFF的空间范围是640KB,这片地址对应到了DRAM,也就是插在主板上的内存条。DRAM由于其本身的电气元件特性,需要定时刷新,否则会因为电容漏电而丢失数据。
然而,我们的内存条并不是CPU可访问的全部内存。
地址总线宽度决定了可以访问的内存空间大小,比如16位机的地址总线为20位,其地址范围是1MB。但是,以上的地址范围是指地址总线能够触及到的边界,指计算机在寻址上可以达到的疆域,并不是说1MB的地址范围必须全部都是内存条。
插在主板上的内存条需要通过地址总线来访问,但是还有一些外部设备需要通过地址总线来访问。我们需要预留一些地址空间来给外设使用。地址总线决定我们访问哪里、访问什么,以及访问范围。
内存条多大都无济于事,要看地址总线的宽度和地址总线的分配情况。这就是安装了4GB内存,但是可能只显示3.8GB左右的原因。
CPU能够访问的地址,这是地址总线给做的映射,相当于给该地址分配了一个存储单元,而该存储单元要么落在某个rom中,要么落在某个外设的内存中,要么落在物理内存条中。
三、MBR
1、MBR的位置
BIOS的最后一项工作是校验启动盘中位于0盘0道1扇区的内容(也就是MBR,此处描述扇区的方法是CHS,第一个扇区是1而不是0)。若扇区的最后两个字节是魔数0x55和0xaa,BIOS便认为扇区确实存在可执行的程序,便会将其加载到0x7c00,然后跳转到该地址,完成了控制权交接。
2、$、$$、section
$和$$是编译器预留的关键字,用来表示当前行和本section的地址,起到标号的作用,是伪指令。默认情况下,$和$$的值是相对于本文件的偏移量。但是如果该section使用了vstart = ***修饰,那么$$的值则是此section的虚拟起始地址***,$的值则是以***为起始地址的顺延。当想获得本section在文件中的真实偏移地址时,可使用“section.节名.start”
标号的介绍
- 标号由字母、数字、"_"、"$"、"#"、"@"、"~"、"."、"?"组成,但必须由字母、"."、"_"和"?"中的任意一个打头
- 标号的作用是提供当前位置的汇编(相对于本文件开头的偏移)地址,供其他指令使用。当不需要引用该地址时,标号可以省略
section称为节,就是程序中的一小块。用section就是在程序中圈出一块地,并和编译器说,这块地我要做些规划,倒是后编译器再合理规划。但是,当不同的节性质相同时,编译器就会将这些节合并,此处就体现了编译器的规划。section可以将我们的代码分成逻辑上的一个个段,实际上编译出来的程序还是完整一体的。逻辑上划分成段可以方便我们梳理代码和管理。
3、MBR的内容
本次实验目的:在实模式下,我们通过调用中断向量表中的相关中断来实现往屏幕上输出“Real MBR”
先导知识点
- 本次涉及中断向量0x10的三个子功能号:清屏(0x06)、获取光标位置(0x03)和打印字符(0x13)
- 在调用自动能前,需将子功能号送入ah寄存器。然后执行“int 0x10”,即可使用子功能
- 对于子功能0x06,需要提前设置好上卷行数、上卷属性、左下角和右上角的坐标
- 对于子功能0x03,需要提前设置好待获取光标的页号。本功能有输出ch、cl分别表示光标开始行、结束行,dh、dl分别表示光标所在行、列
- 对于子功能0x13,需要提前设置好字符串长度、字符属性
实验源码:
section mbr vstart=0x7c00
;initialize sreg
mov ax, cs
mov ds, ax
mov es, ax
mov fs, ax
mov gs, ax
mov sp, 0x7c00
;;;;;;;;;;clear screen;;;;;;;;;;
;ah = function number:0x06-->ah = 0x06
;al = number of rows to roll(0 means all)
;bh = scroll line properties
;(cl,ch) = the (x,y) position in the bottom left corner of the window
;(dl,dh) = the (x,y) position in the top right corner of the window
mov ax, 0x600;
mov bx, 0x700
mov cx, 0
mov dx, 0x184f ;the default screen has 25row*80column
int 0x10
;;;;;;;;;;get cursor position;;;;;;;;;;
;ah = function number:0x03-->ah = 0x03
;bh = the page number of the cursor to be obtained(0)
mov ah, 0x3
mov bh, 0x0
int 0x10
mov bp, message ;let bp get string option
;;;;;;;;;;print string;;;;;;;;;;
;ah = function number;0x13-->ah = 0x13
;al = the way string are written
;cx = string's length
;bh = the page number of the page used to display string(0)
;bl = string's properties
mov ax, 0x1301
mov cx, 0x8
mov bx, 0x02
int 0x10
jmp $ ;let the program hover
message db "Real MBR" ;define the string
times 510-($-$$) db 0 ;fill the program to 510 bytes size
dw 0xaa55 ;fill in the magic number
编译:nasm -o mbr.bin mbr.s
写入磁盘:dd if=/home/oskiller/bochs/mylab/lab1/mbr.bin of=/home/oskiller/bochs/mylab/lab1/hd60M.img bs=512 count=1 conv=notrunc
(我是将bochs放置在主目录了。bochs中新建了mylab来装本书的所有实验,里面有份文件lab1、lab2……,为了在做到前面的实验结果不被后面的实验覆盖掉,我在每个分实验文件中创建磁盘和编写配置文件)
运行:/home/oskiller/bochs/bin/bochs -f bochsrc.disk
运行结果: