真象还原操作系统_第三章_完善MBR

一、地址、section、vstart的浅尝辄止

1.地址访问

  • 程序中各种数据结构的访问,本质上是“该数据结构的起始地址+该数据结构所占内存的大小”来实现的。
  • 地址访问策略是程序中给出的地址,你去那里拿东西,那里必须提前准备好才行。
  • 程序最终是要被加载到物理内存上的,因此该地址对应的物理内存一定是你想要的。这就是程序加载器要做的事情,根据你给出的地址,将程序加载到对应内存地址上。

2.vstart

  • vstart没有改变数据本身在文件中的地址。
  • vstart是虚拟起始地址,它给出了一个起始地址来规定后续的数据结构的地址(起始地址+偏移地址),然后编译器据此进行编译,加载器根据编译出的内容加载到物理内存上。
  • vstart的时机:我预先知道我的程序要被加载到某地址处。程序只有被加载到非0地址处时vstart才有用,程序的默认起始地址是0。
  • 编译器的好处是利于重定位。
    在这里插入图片描述

二、CPU实模式

1.实模式与CPU构成

  • 实模式是指8086 CPU的寻址方式、寄存器大小、指令用法等,用来反映CPU在该环境下如何工作的。
  • 实模式的“实”体现在:程序用到的地址都是真实的物理地址。
  • CPU的组成:运算单元、控制单元、存储单元

2. 控制单元

  • 控制单元:CPU的核心,告诉CPU下一步该做什么。由指令寄存器IR(Instruction Register)、指令译码器ID(Instruction Decoder)、操作控制器OC(Operation Controller)组成。
  • CPU工作流程:
    1. 程序被加载到内存(指令都在内存中了)
    2. 指令指针寄存器IP指向下一条待读取的指令的地址,控制单元根据IP的指向,将该指令加载到IR中。(但CPU不知道指令什么意思)
    3. 指令译码器ID将位于IR中的指令按照指令格式进行解码,分析出操作码、操作数等等。
      在这里插入图片描述

3.存储单元

  • 指令存储在指令寄存器IR中,那指令中用到的数据存储在哪里呢?——存储单元
  • 存储单元构成:CPU内部的L1、L2缓存及寄存器
  • 为什么要把内存中的操作数放到缓存中?
    • 因为缓存基本采用SRAM(Static RAM)寄存器,静态存取寄存器,与DRAM不同,它无需刷新电路。
    • SRAM性能强劲,但集成度低,比DRAM体积大很多。
  • 寄存器分类:
    1. 程序员可见寄存器:通用寄存器、段寄存器
    2. 程序员不可见寄存器

4.运算单元

  • 操作码、操作数都有了,就差执行指令了,随后操作控制器OC便向运算单元发送信号。
  • 运算单元:负责算数运算和逻辑运算,它从控制单元那里接受信号并执行,无自主意识,只是个执行部件。

总结:控制单元要取下一条指令。读取IP寄存器的值,将指令放入IR中,然后ID对指令进行解码,先确定操作数,然后是操作码。若操作码在内存中,便将其取到存储单元中,若在寄存器中就直接用。最后控制单元向运算单元发送信号,由运算单元进行计算。然后IP寄存器再指向下一条指令,循环往复。
在这里插入图片描述

三、实模式下的寄存器

1.寄存器

  • 寄存器:位于CPU内部的存储元件,速度快。
  • CPU中的缓存L1、L2等SRAM是用寄存器来存储数据的。
  • CPU中的寄存器分类:
    1. 内部使用寄存器,对程序员不可见:全局描述符表寄存器GDTR、中断描述符表寄存器IDTR、局部描述符表寄存器LDTR、任务寄存器TR、控制寄存器CR0~3、标志寄存器flags、调试寄存器DR0 ~7
    2. 对程序员可见寄存器:通用寄存器和段寄存器。
  • 程序员可以对内部寄存器进行初始化:
    1. GDTR:用lgdt指令为其指定全局描述符表以及偏移量。
    2. IDTR:用lidt指令为其指定中断描述符表的地址。
    3. LDTR:用lldt为其指定局部描述符表ldt。
    4. TR:用ltr为其指定一个任务状体段tss。
    5. flags:pushf和popf指令,分别用于将flags寄存器的内容压入栈和将栈中内容弹到flags寄存器中。
  • 在实模式下,用到的寄存器都是16位宽。

2.各种寄存器

  • 段寄存器——代码段、数据段和栈段寄存器:
    1. 代码段是把所有指令连续排放在一起,里面存储的是指令的操作码及寻址方式。该区域可以在硬件上的文件中,也可以是被加载后的内存中,总之是一段指令区域。而代码段寄存器CS则指向这段区域(代码段)的起始地址。
    2. 数据段是代码段类似,里面存储的是数据。数据段寄存器DS指向该区域的起始地址。
    3. 因为栈段是操作系统分配的,所以是被加载到内存中才有的。因此栈段只在内存中,硬盘文件中没有。栈段寄存器SS用来指向栈段的起始地址。
    4. 附加寄存器:给大家多提供几个寄存器用。在16位CPU中,只有ES一个附加寄存器,FS和GS都是32位寄存器。
      在这里插入图片描述
  • 不可见寄存器
    1. CS是可见寄存器、IP是不可见寄存器,它们在一起组成了CPU的罗盘。
    2. flags中存储着一些标志位,有些指令的执行需要一定的条件,这些条件便存储在flags中。
      在这里插入图片描述
  • 通用寄存器
    1. 无论实模式还是保护模式,通用寄存器只有8个:AX、BX、CX、DX、SI、DI、BP、SP
    2. 拿AX举例:AX是16位,低8位为AL(A Low)、高8位为AH(A High)。AX可高位拓展为32位,即EAX。
    3. 因此虽然实模式下操作数是16位,但仍然可以用32位寄存器,因为EAX也是由AX,AH,AL构成的。
    4. 通用寄存器可以用来保存任何数据和地址。
    5. 惯用法:CX寄存器用作循环的次数控制,BX寄存器用于存储起始地址。
      在这里插入图片描述
    6. 通用寄存器的特定功能:一些指令已经固定用一些特定的寄存器作为参数了:ESI作为很多有关数据复制指令的源地址,EDI为目的地址。
      在这里插入图片描述

3. 实模式下的内存分段由来

  • 实模式的“实”体现在:程序用到的地址都是真实的物理地址。“段基址:段内偏移地址”产生的逻辑地址就是真实的物理地址。
  • x86代指所有…86的CPU体系,8086成为里程碑是因为它开创了段机制。
  • 8086的地址总线是20位宽,寻址范围为2^20=1MB,寄存器为16位。
  • 通过将16位的段基址左移4位+16位的段内偏移地址得到20位最终地址
  • 通过“段基址+段内偏移地址”的寻址方式,我们可以寻址到的最大内存位0x10FFEF,但是这部分不存在,因为8086只有20条地址线。这时采用“回卷”方式进行处理,即把地址对1MB进行取模。
    在这里插入图片描述
    在这里插入图片描述
  • 这引出了保护模式需要打开A20地址线的问题。

四、实模式下的CPU寻址方式

1.寄存器寻址

  • 当数在寄存器中时,可以直接从寄存器拿数。
//用mul进行乘法:
mov ax,0x10  //立即数寻址
mov bx,0x9   //立即数寻址
mul bx       //寄存器寻址

虽然乘数和被乘数都是8位,但是它们使用的寄存器是16位,因此看作是两个16位的数字相乘。
因此mul指令的被乘数默认放在ax中,乘数要保存在寄存器/内存中,结果默认保存在DS:AX(高16位:低16位)中。

2.立即数寻址

  • 立即数就是常数
mov ax,0x18  //立即数寻址
mov ds,ax     //寄存器寻址
mov ax,macro_selector  //立即数寻址
mov ax,label_start  	    //立即数寻址

macro_selector是个宏,label_start是个标号,这两个数在编译阶段会转换成数字,最终在可执行文件中是立即数。

3.内存寻址

  • 寄存器寻址和立即数寻址都不在内存中,操作数在内存中的寻址被称为内存寻址。
  • 内存寻址的方式:“段基址:段内偏移地址”这种寻址方式只能用在内存中。默认状态下的数据段寄存器是DS,即段基址已经有了,只要给出段内偏移地址即可访问内存。
  • 因此,段内偏移地址也被称为有效地址。
  • CPU的寻址方式看上去死板,因为一种寻址方式就对应一种电路实现。
  1. 直接寻址

    • 直接给出内存地址,告诉CPU取这里的地址中的内容为操作数
    mov ax,[0x1234]  //直接寻址,取DS:0x1234中的数存入AX中
    mov ax,[fs:0x5678]  //段跨越前缀fs表示段基址变为gs,取gs:0x5678处的值存入AX中
    
  2. 基址寻址

    • 实模式下:在操作数中用bx/bp寄存器作为基址寄存器(地址的起始)
    • 保护模式:基址寄存器可以是任意通用寄存器
    • bx的默认段寄存器是ds;bp的默认段寄存器是ss
    • SS——堆栈段寄存器(Stack Segment Register),其值为堆栈段的段值。

    为什么ss段寄存器已经有sp寄存器了,还需要bp寄存器呢?
    因为sp只是栈顶指针,是专门给push和pop指令开设的指针寄存器。

    //push ax:
    sub sp,2
    mov sp.ax
    
    //pop ax
    mov ax,[sp]
    add sp,2
    
    • 通过ss:bp的方式,可以将栈当作普通数据段来访问
    • 举例:当用栈来保存局部变量和函数参数时,函数头入栈作为“基址”,以上为返回值和形参,以下为局部变量。在这里插入图片描述
  3. 变址寻址

    • 和基址寻址类似,只是寄存器由bx,bp变为si和di。
    • si是源索引寄存器,di是目的索引寄存器,两个的默认段寄存器都是ds。
    mov [di],ax				 //将寄存器ax中的值存入ds:di的内存中
    mov [si+0x1234],ax 		 //变址也可加多个偏移量
    
  4. 基址变址寻址

    • 基址与变址的结合
    mov [bx+di],ax		//将ax的值存入 ds:bx+di 中
    add [bx+si],ax		//将ax的值加上 ds:bx+si 后存入 ds:bx+si 中
    
  • 在基址寻址中,有效地址(即偏移地址)由两部分组成。一部分存放在基址寄存器中,另一部分为常量 。
  • 在变址寻址中,有效地址(即偏移地址)由两部分组成。一部分存放在变址寄存器中(可能这部分还要乘以一个系数),另一部分为常量 。

变址寻址与基址寻址的不同,就在于偏移地址的计算更复杂了点。此时 CPU 不去基址寄存器,而是去变址寄存器。

4.栈

  1. 寄存器:栈段寄存器ss和栈指针寄存器sp
  2. 数据存取方法:push和pop
    //push ax:
    sub sp,2
    mov sp.ax
    
    //pop ax
    mov ax,[sp]
    add sp,2
    
  3. 字长:CPU一次可处理的数据的长度,在实模式下是16位。
  4. 虽然栈是向下发展的,但栈也是内存,访问内存仍然是从低地址到高地址。

五.实模式下的call和ret

1.前言

  • 因为指令都在内存中,所以CPU也要访问内存才能拿到要执行的代码。
  • IP寄存器是不可见寄存器,不可以直接赋值。
  • 无条件转移:call、ret、jmp指令在原理上都是通过修改cs和ip寄存器的值,将CPU导向新的位置。
    • jmp:一去不复返地执行新代码,使用环境——交接
    • call:执行一段代码,通过ret返回,不跨段,近调用的call在栈中留下段内偏移地址。
    • call far:远调用,通过retf返回,跨段,远调用的call far在栈中留下了段基址和段内偏移地址

2. call

  1. 16位相对近调用
    • 相对:由于在同一个代码段中,所以只需要给出目标函数的相对地址即可
    • 指令格式:call near 立即数地址
    • 立即数可以是被调用的函数名、标号.
    • 近调用必须是相对地址,因为CPU是根据地址的相对量来推算目标地址的。如果目标函数地址比call地址大,则地址相对量为正数,如果小则为负数。
		call near near_proc
		jmp $
		addr dd 4
		near_proc:
			mov ax,0x1234
			ret

在这里插入图片描述

  1. 16位实模式间接绝对近调用
    • 间接:目标函数的地址没有直接给出,要么在寄存器中,要么在内存中,总之不以立即数的形式出现
    • 绝对:目标函数的地址是绝对地址,不是相对地址
    • 近调用:不跨段
    • 指令格式:call 寄存器寻址/call 内存寻址
    section call_test vstart=0x900
    mov word [addr],near_proc	
    //word是告诉CPU一次要读写多少字节(2字节)的,因为地址在编译阶段会被替换为数字,这个数字宽度是不定的,同样的0x18,可能是0x0018也可能是0x00000018
    call [addr]		//call 内存寻址
    mov ax,near_proc
    call ax			//	call 寄存器寻址
    jmp $
    addr dd 4
    near_proc:
    	mov ax,0x1234
    	ret
    
  2. 16位实模式直接绝对远调用
    • 直接:不需要寄存器/内存,在指令中直接给出,是立即数
    • 远调用:跨段,CS和IP都要用新的。远调用的call far在栈中留下了段基址和段内偏移地址
    • 指令格式:call far 段基址(立即数):段内偏移地址(立即数)
    • 直接绝对远调用:far可以不写
    section call_test vstart=0x900
    call 0:far_proc
    jmp $
    far_proc:
    	mov ax,0x1234
    	retf
    
  3. 16位实模式间接绝对远调用
    • 间接:操作数没有直接给出,在寄存器/内存中。但是段基址和段内偏移地址都是16位,一个寄存器放不下,因为寄存器宝贵,所以段基址和段内偏移地址都放在内存中。
    • 指令格式:call far 内存寻址
    • 需要用call far,不然和间接绝对近调用一样了
    section call_test vstart=0x900
    call far  [addr]
    jmp $
    addr dw far_proc,0    //低2字节是far_proc 段内偏移地址,高2字节是段基址
    far_proc:
    	mov ax,0x1234
    	retf
    
  4. 需要通过ret来返回

3.ret

  • ret和retf
    1. ret:近返回,未跨段访问。在栈顶弹出2字节内容来替换IP寄存器
    2. retf(return far):远返回,从栈顶弹出4字节内容,栈顶的2字节置换IP寄存器,另外2字节置换CS寄存器。
    3. 指令不管里面的内容是数据还是地址,它只会执行

4.jmp

  • 原理:jmp指令只需要更新cs和ip寄存器的值,由于不需要返回原处,所以不需要对原地址进行保存。
  • 根据是否跨段分为近转移和远转移
  1. 16位实模式相对短转移
    • 指令格式:jmp short 立即数(标号)
    • 既然是相对,说明操作数是个相对增量,有正负之分
    • 短转移:段内转移,跳转的范围是1字节有符号数的大小—— -128——127(8位有符号数)
    • 和call的相对近转移一样
    section jmp_test vstart=0x900
    jmp short start		//短转移
    times 127 db 0		
    //+127是正偏移的最大值,如果是times 128 db 0就会报错:short jmp is out of range
    start:
    	mov ax,0x1234
    	jmp $
    
    • 扩大范围的方式:
      1. 将short换成near
      2. jmp后什么都不写,让nasm编译器自己判断是short还是near
  2. 相对近转移
    • 指令格式:jmp near 立即数地址
    • 近转移:操作数范围变大—— -32768——32767(16位有符号数)
    section jmp_test vstart=0x900
    jmp near start		//近转移
    times 128 db 0
    start:
    	mov ax,0x1234
    	jmp $			//短转移
    
  3. 16位实模式间接绝对近转移
    • 绝对:目标地址是绝对地址
    • 近转移:只改变IP值,16位地址,段内转移
    • 间接:地址不是直接给出(立即数),而是在寄存器/内存中
    • 指令格式:jmp near 寄存器寻址/内存寻址
    • 若是内存寻址,则段基址寄存器默认为DS
    section jmp_test vstart=0x900
    mov ax,start
    jmp near ax		//寄存器寻址
    times 128 db 0
    start:
    	mov ax,0x1234
    	jmp $
    
    section jmp_test vstart=0x900
    mov word [addr],start //word用来告诉CPU一次读写多少字节
    jmp near [addr]		//内存寻址
    times 128 db 0
    addr dw 0 			//定义addr为2字节大小变量
    start:
    	mov ax,0x1234
    	jmp $
    
  4. 16位实模式直接绝对远转移
    • 直接:操作数是立即数
    • 绝对:提供的操作数是绝对地址
    • 远转移:跨段,cs和ip都要改变
    • 指令格式:jmp 段基址(立即数):段内偏移地址(立即数)
    section jmp_test vstart=0x900
    jmp 0:start
    times 128 db 0
    start:
    	mov ax,0x1234
    	jmp $
    
  5. 16位实模式间接绝对远转移
    • 间接:操作数不是立即数,在寄存器/内存中。由于操作数是两个数,所以只能放在内存中。
    • 远转移:跨段,为了指示CPU在内存中取4个字节,需要用far关键字。前两个字节是段内偏移地址,后两个自己是段基址。
    • 指令格式:jmp far 内存寻址
    section jmp_test vstart=0x900
    jmp far [addr]
    times 128 db 0
    addr dw start,0		//低2字节是偏移地址,高2字节是段基址
    start:
    	mov ax,0x1234
    	jmp $
    

六、标志寄存器flags&有条件转移

  • flags
    • 作用:有条件转移的条件放在标志寄存器flags中。
    • 实模式下的标志寄存器是16位的flags,在保护模式下拓展为32位的eflags。
      在这里插入图片描述
  • flags中的位
英文名称意义
CFcarry flag进位可用于检测无符号数加减法是否溢出
PFparity flag奇偶位用于标记结果低8位中1的个数(奇偶),常用于数据传输开始和结束时的对比
AFauxiliary carry flag辅助进位标志用于记录运算结果低4位的进、借位情况
ZFzero flag零标志位记录运算结果是否为0
SFsign flag符号标志位若运算结果为负,则SF=1
TFtrap flag陷阱标志位若TF=1,则CPU进入单步运行方式,若TF=0,则进入连续工作方式。例如debug
IFinterrupt flag方向标志位
OFoverflow flag溢出位
  • 有条件转移
    • 指令格式:jxx 目标地址。(目标地址只能是段内偏移地址)
    • 若条件满足则跳转到目标地址,反之则继续运行下一条指令。
      在这里插入图片描述

七、实模式被淘汰的原因

  • 主要是安全隐患
  • 在实模式下,用户程序和操作系统是同一特权级的程序,因为实模式没有特权级,所以可以执行一些有破坏性的指令。
  • 程序可以随意修改段基址,可以访问到1MB的任何位置,甚至可以访问到操作系统的内存数据。

八、显示器

1.CPU如何与外设通信——IO接口

  • IO接口是连接CPU与外设的逻辑控制部件,有硬件软件两部分
    1. 硬件:协调CPU与外设之间的不匹配——速度不匹配、数据格式不匹配等
    2. 软件:控制接口电路工作的驱动程序&完成内部数据传输所需的程序
  • IO接口的功能:
    1. 设置数据缓冲,解决CPU与外设的速度不匹配
      数据先存入缓冲区,等需要的适合再发送出去。
    2. 设置信号电平转换电路
    3. 设置数据格式转换
      外设可能输出数字信号和模拟信号,而CPU只能处理数字信号。
    4. 设置时序控制电路来同步CPU和外设
    5. 提供地址译码
  • 为了区别CPU内部的寄存器,IO接口中的寄存器称为端口(与网络的端口有别)
  • in指令用于从端口中读取数据
    • 指令格式:操作码 目的操作数,源操作数
    • 只要用in指令,源操作数必须为dx,目的操作数根据寄存器宽度选择al(8位)或ax(16位)
    in al,dx
    in ax,dx
    //al和ax用来存储从端口中获取的数据,dx是端口号
    
  • out指令用于向端口中写数据
    out dx,al
    out dx,ax
    out 立即数,al
    out 立即数,ax
    //在out指令中,可以选择dx寄存器或立即数充当端口号
    

2.显卡

  • 某些IO接口也叫适配器,适配器是驱动某一外部设备的功能模块。
  • 显卡也成为显示适配器,它的本质是IO接口,用来连接CPU与显示器。
  • 无论哪种显卡,提供给我们的可编程接口都是一样的:IO端口和显存
    • 显存是由显卡提供的,位于显卡内部的一块内存。
    • 显卡的工作是不断读取显存,然后将其内容发送到显示器上。
  • 显卡有自己的BIOS,位置是0xC0000到0xC7FFF。显卡支持三种模式:文本模式、黑白图形模式、彩色图像模式。
    • 从0xB8000到0xBFFFF,这片32KB大小的内存区域是用于文本显示。
    • 我们向0xB8000处输入字符就会落入显存中,显存中有了数据,显卡就会将它搬到大屏幕上。
    • 彩色字符
      • 每个字符的低字节是ASCII码,高字节是字符属性的元信息。在高字节中,低4位是前景色,高4位是字符的背景色。
      • 颜色用RGB红绿蓝三种基色调和,第4位用来控制亮度。若为1则为高亮,为0则为正常亮度,第7位用来控制是否闪烁。
        在这里插入图片描述
        在这里插入图片描述
  • 操作数所占空间
    1. byte、word、dword分别表示1字节,2字节和4字节
    2. 这些关键字指明了操作数的数据宽度(字节数),同C语言的变量类型一样。
    3. 如果源操作数和目的操作数已经明确了数据宽度,则指令中就不必显示地指明操作数所占空间了。
    mov ax,0x10		//目的操作数ax是16位
    mov byte [gs:0x00],'1'		//‘1’的ASCII码是0x31,是个立即数,无法判断存储空间大小。
    //byte是告诉[gs:0x00]这个'1'要用多少字节去存储它
    

九、硬盘

1.硬盘控制器

  • 硬盘控制器:CPU与硬件的IO接口
  • 硬盘控制器端口:我们通过读写硬盘控制器
    在这里插入图片描述
  • 端口分类
    1. Command Block registers:向硬盘驱动器写入字/从硬盘控制器获得硬盘状态
    2. Control Block registers:控制硬盘工作状态【基本用不到】
  • Command Block register:
    1. 端口是按照通道给出的,一个通道上的主从两块磁盘都可以使用这个端口。要使用哪个端口的哪块磁盘需要单独指定。
    2. data端口:读取/写入数据,它是16位,其他寄存器都是8位。
      • 当读硬盘中,硬盘控制器将数据存入缓冲区,然后不断读data端口将数据读出。
      • 当写硬盘时,我们将数据源源不断地写入data端口,数据便被存入缓冲区中,硬盘控制器发现缓冲区中有数据了,便把数据写入对应磁盘中。
      • data是端口,缓冲区是缓冲区,不是一个概念。
      • 实模式的默认寄存器是16位,是指CPU,这些是硬盘中单独的寄存器。

    3. Error&Feature端口:
      • Error:读磁盘失败时生效,里面会记录失败的信息。尚未读取的扇区数在sector count中。
      • Feature:写磁盘时生效,有些命令会额外指定参数,这些参数保存在Feature中。
      • Error和Feature是同一个寄存器,在对应环境下有不同的名字。
    4. Sector count端口:用来指定待存入/待写入的扇区数,每完成一个扇区,数值-1。8位寄存器,最大值是255。
    5. LBA:逻辑块地址,一种逻辑上为扇区址的方法,这里我们采用28位地址。
      • LBA low:存储28位地址的0~7位
      • LBA mid:存储28位地址的8~15位
      • LBA high:存储28位地址的16~23位
    6. device端口:device寄存器是个杂项,宽度8位。
      • 低4位用来存储LBA地址的24~27位。
      • 第4位:指定通道上的主盘还是从盘,0代表主盘,1代表从盘。
      • 第6位:设置是否用LBA方式,1代表用LBA,0代表用CHS。
      • 第5位和7位固定为1,称为MBS位。
    7. Status端口:读磁盘时生效,用来给出磁盘的状态信息。
      • 第0位:ERR位 = 1表示命令出错,具体原因见Error端口。
      • 第3位:data request 位= 1表示磁盘已经把数据准备好,主机可以把它读出来。
      • 第6位:DRDY位,表示磁盘检测正常,可以执行命令。
      • 第7位:BSY位,表示磁盘是否繁忙,1表示忙碌。
      • 其他位无效。
    8. command端口:和Status是同一端口,写磁盘时生效。只要把命令写入端口,硬盘就开始工作。
      • identify:0xEC,磁盘识别
      • read sector:0x20,读磁盘
      • wirte sector:0x30,写磁盘
        在这里插入图片描述

2.常见的磁盘操作方法

  • 磁盘操作顺序:
    1. 先选择通道,向该通道的sector count端口中写入带读取扇区数
    2. 向该通道的三个LBA端口写入扇区起始地址的低24位
    3. 向device端口中写入LBA地址的24~27位,设置第6位=1,使其为LBA模式,设置第4位,选择操作的磁盘(master或slave磁盘)
    4. 向通道上的command端口写入操作命令
    5. 读取该通道的status端口,判断磁盘工作是否完成
    6. 如果以上步骤是读磁盘,进入7命令,否则结束
    7. 将磁盘数据读出
  • 数据传送方式:(硬盘工作完成后,CPU如何获得数据呢?)
    1. 无条件传送方式
      这些方式的数据源设备一定是随时准备好数据,CPU随时取随时拿都没问题,如寄存器、内存,CPU取数据不需要打招呼。
    2. 查询传送方式(程序IO,PIO)
      在传送之前,由程序先去检测设备的状态。当数据源准备好时才能传送数据,因为数据源是低速设备。status端口里面保存了工作状态,可以对磁盘采用这种方式来获取数据。
    3. 中断传送方式(中断驱动IO)
      当数据源准备好后自己通知CPU来取,通知CPU可以采用中断的方式。
    4. 直接存储器存取方式(DMA方式)
      当数据源通过中断通知CPU时,CPU要压栈保护现场,浪费资源。设置一个DMA控制器(硬件),代替CPU由数据源和内存直接传输。当CPU需要数据时,直接来内存中拿即可。
    5. IO处理机传送方式
      解放CPU,CPU不需要来内存取数据,IO处理机直接把数据处理也做了。

十、MBR

  • 因为MBR只有512字节,无法保证能加载好内核。所以先在另一个程序中完成初始化环境以及加载内核的任务,这个程序称为loader加载器。
  • 因为MBR在第0号扇区,loader邻着MBR不好,所以放在第2号扇区。
  • 在实模式下,可用区域只有0x500~ 0x7BFF和0x7E00~ 0x9FBFF两块。因为loader中要加载一些数据结构(GDT全局描述符表等),所以loader加载到内核后不能被覆盖,又不像离loader太近,所以选择了0x900地址。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值