自己动手写操作系统-笔记一
一、CPU工作原理
CPU大体可以分为三个部分:控制单元、运算单元、存储单元
控制单元大致由指令寄存器IR(instruction register)、指令译码器ID(instruction decoder)、操作控制器OC(operation controller)组成。
控制单元取下一条指令,该指令地址在程序计数器PC中,在X86CPU中就是cs:ip。读取ip寄存器后将此地址送上地址总线,CPU根据此地址变得到了指令,存入IR中。
ID根据指令格式检查IR中的指令,先确定操作码,再检查操作数类型,若是在内存中,就将响应操作数从内存中取回放入到自己的存储单元中,若操作数在寄存器中
就直接使用了。下一步,OC给运算单元下指令开始工作,于是运算单元开始执行真正的指令。ip寄存器被加上当前指令大小,指向下一条指令。接着控制单元取下一条
指令,开始无休止的循环工作。
二、实模式下CPU寻址方式
1.寄存器寻址
mul dx
2.立即数寻址
mov ax, 0xff
3.内存寻址
内存寻址又分为:
3.1 直接寻址
mov ax, [ds:0x1234]
3.2 基址寻址
sub sp, 2
mov [sp], ax
3.3 变址寻址
mov [si + 0x1234], ax
3.4 基址变址寻址
mov [bx + di], ax
三、IO接口
IO接口是连接CPU和外部设备的逻辑控制部件。
输入输出控制中心(I/O control hub,ICH):CPU访问多个IO接口的逻辑需要ICH控制。
in和out指令的目的操作数和源操作数必须是dx,ax
in ax, dx
out dx, ax
根据操作数位数可以选择使用ax或者al。
1.显卡
把需要显示的内容写到显存中即可。
显卡各种模式内存分布:
起始 | 结束 | 大小 | 用途 |
C0000 | C7FFF | 32KB | 显示适配器BIOS |
B8000 | BFFFF | 32KB | 用于文本模式显示适配器 |
B0000 | B7FFF | 32KB | 用于黑白显示适配器 |
A0000 | AFFFF | 64KB | 用于彩色显示适配器 |
在文本模式下每个字符用连续的两个字节表示,高字节用于表示字符的属性(例如前景色、背景色等等)。
2.硬盘
磁头、盘片、磁道、柱面、扇区
扇区是硬盘存储数据的基本单位,固定为512字节。
各磁道内扇区都是以1为起始编号,并且仅限于本磁道内有效,所以各个磁道内的扇区编号都相同,
磁头号、磁道号、扇区号定位唯一扇区。
硬盘控制器端口:
IO端口 | 端口用途 | ||
primary通道 | secondary通道 | 读操作时 | 写操作时 |
0x1f0 | 0x170 | data | data |
0x1f1 | 0x171 | error | features |
0x1f2 | 0x172 | sector count | sector count |
0x1f3 | 0x173 | LBA low | LBA low |
ox1f4 | 0x174 | LBA mid | LBA mid |
0x1f5 | 0x175 | LBA high | LBA high |
0x1f6 | 0x176 | device | device |
0x1f7 | 0x177 | status | command |
LBA有两种:
一是LBA28使用28bit来描述一个扇区的地址
二是LBA48使用48bit来描述一个扇区的地址
LBA low、mid、high寄存器分别存储28位地址的0-7、8-15、16-23位,
device寄存器是个杂项,它的低4位用来存储LBA地址的24-27位。
device寄存器和status寄存器:
一般硬盘操作顺序:
最主要的顺序就是command寄存器一定要最后写,因为一旦command寄存器被写入后,硬盘就开始干活了。
①先选择通道,往该通道的sector count寄存器中写入带操作的扇区
②往该通道的三个LBA寄存器中写入扇区起始地址的低24位
③往device寄存器中写入LBA地址的24-27位,并置第6位为1,使其成为LBA模式,设置第4位选择操作的硬盘
④往该通道的command寄存器中写入操作命令
⑤读取该通道上的status寄存器,判断硬盘工作是否完成。
⑥如果以上步骤是读硬盘,进入下一步骤,否则,完工。
⑦将硬盘数据读出。
最后送上一段MBR程序中的一个操作硬盘片段,它的作用是将硬盘中的加载器程序读入内存中,首地址为0x900
1 mov eax, 0x2 2 mov bx, 0x900 3 mov cx, 1 4 call rd_disk_m_16 5 jmp 0x900 6 7 mov esi, eax 8 mov di, cx 9 ;设置要读取的扇区数 10 mov dx, 0x1f2 11 mov al, cl 12 out dx, al 13 14 mov eax, esi 15 16 ;将LBA地址存入0x1f3-0x1f6 17 mov dx, 0x1f3 18 out dx, al 19 20 mov cl, 8 21 shr eax, cl 22 mov dx, 0x1f4 23 out dx, al 24 25 shr eax, cl 26 mov dx, 0x1f5 27 out dx, al 28 29 shr eax, cl 30 and al, 0x0f 31 or al, 0xe0 32 mov dx, 0x1f6 33 out dx, al 34 35 ;向端口写入读命令 36 mov dx, 0x1f7 37 mov al, 0x20 38 out dx, al 39 40 ;检测硬盘状态 41 .not_ready: 42 nop 43 in al, dx 44 and al, 0x88 45 cmp al, 0x80 46 jnz .not_ready 47 48 ;从端口0x1f0读取数据 49 mov ax, di 50 mov dx, 256 51 mul dx 52 mov cx, ax 53 mov dx, 0x1f0 54 .go_on_read: 55 in ax, dx 56 mov [bx], ax 57 add bx. 2 58 loop .go_on_read 59 ret 60 times 510-($-$$) db 0 61 db 0x55, 0xaa