第三章 完善MBR

发布时间:2025-12-09 19:39:52 浏览次数:5

地址、section、vstart

什么是地址

地址只是数字,描述各种符号在源程序中的位置,它是源代码文件中各符号偏移文件开头的距离

编译器的工作就是给各符号编址。 编译器根据所在硬件平台的特性,将源代码中的每一个符号(指令和数据)都按照本硬件平台的特性分配空间,在不考虑对齐的情况下,这些符号在空间上都彼此相邻,连续分布它们在程序中距第一个符号的距离便是它们在程序中的地址

硬盘控制器端口

CPU针对硬盘的IO接口是硬盘控制器,不过硬盘和硬盘控制器是连接在一起的。
让硬盘工作,我们需要读写硬盘控制器的端口,也就是硬盘控制器的寄存器。


data寄存器负责管理数据,作用是读取写入数据,16位。在读硬盘时,硬盘准备好数据后,硬盘控制器将其放在内部缓冲区中,不断读此寄存器便是读出缓冲区中的全部数据。在写硬盘时,我们要把数据源源不断地输送到此端口,数据便被存入缓冲区里,硬盘控制器发现缓冲区中有数据了,便将此处的数据写入相应的扇区中。

Error寄存器只有在读取硬盘失败时有用,里面会记录失败的信息,尚未读取的扇区数在Sector count寄存器中。在写硬盘时,此寄存器叫Feature寄存器,有些命令需要指定额外参数,这些参数就写在Feature寄存器中。这两个寄存器虽然名字不同,但指的是同一个寄存器,8位寄存器。
Sector count寄存器用来指定待读取或待写入的扇区数。硬盘每完成一个扇区,就会将此寄存器的值减1,所以如果中间失败了,此寄存器中的值便是尚未完成的扇区。8位寄存器,最大值255,若指定为0,则表示要操作256个扇区。

LAB寄存器用来描述一个是扇区的地址。LABlow、LABmid、LABhigh都是8位。LABlow用来存储28位地址的第0-7位,LABmid存储8-15位,LABhigh存储16-23位。

device寄存器,8位。低4位用来存储LAB地址的第24-27位。第4位用来指定通道上的主盘或从盘,0代表主盘,1代表从盘。第6位用来设置是否启用LAB方式,1代表启用LAB方式(磁盘中扇区从0开始依次递增编码),0代表启用CHS模式(柱面-磁头-扇区来定位)。另外两位第5位和第7位是固定1,称为MBS位。


常用的硬盘操作方法

硬盘操作顺序:

数据传输方法:

让MBR使用硬盘

改造MBR

负责从硬盘上把loader加载到内存,并使用loader为内核准备好环境,将内核成功加载到内存并运行。

由于MBR是占据了硬盘的第0扇区(以逻辑LBA方式,扇区从0开始编号,若以物理CHS方式,扇区则从1开始编号),第1扇区是空闲的,但离得太近,所以把loader放到第2扇区。MBR从第2扇区中把它读出来。

;主引导程序 ;------------------------------------------------------------%include "boot.inc"SECTION MBR vstart=0x7c00 mov ax,cs mov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0xb800mov gs,ax; 清屏;利用0x06号功能,上卷全部行,则可清屏。; -----------------------------------------------------------;INT 0x10 功能号:0x06 功能描述:上卷窗口;------------------------------------------------------;输入:;AH 功能号= 0x06;AL = 上卷的行数(如果为0,表示全部);BH = 上卷行属性;(CL,CH) = 窗口左上角的(X,Y)位置;(DL,DH) = 窗口右下角的(X,Y)位置;无返回值:mov ax, 0600hmov bx, 0700hmov cx, 0 ; 左上角: (0, 0)mov dx, 184fh ; 右下角: (80,25),; 因为VGA文本模式中,一行只能容纳80个字符,共25行。; 下标从0开始,所以0x18=24,0x4f=79int 10h ; int 10h; 输出字符串:MBRmov byte [gs:0x00],'1'mov byte [gs:0x01],0xA4mov byte [gs:0x02],' 'mov byte [gs:0x03],0xA4mov byte [gs:0x04],'M'mov byte [gs:0x05],0xA4 ;A表示绿色背景闪烁,4表示前景色为红色mov byte [gs:0x06],'B'mov byte [gs:0x07],0xA4mov byte [gs:0x08],'R'mov byte [gs:0x09],0xA4mov eax,LOADER_START_SECTOR ; 起始扇区lba地址mov bx,LOADER_BASE_ADDR ; 写入的地址mov cx,1 ; 待读入的扇区数call rd_disk_m_16 ; 以下读取程序的起始部分(一个扇区)jmp LOADER_BASE_ADDR;-------------------------------------------------------------------------------;功能:读取硬盘n个扇区rd_disk_m_16: ;-------------------------------------------------------------------------------; eax=LBA扇区号; ebx=将数据写入的内存地址; ecx=读入的扇区数mov esi,eax ;备份eaxmov di,cx ;备份cx;读写硬盘:;第1步:设置要读取的扇区数mov dx,0x1f2mov al,clout dx,al ;读取的扇区数mov eax,esi ;恢复ax;第2步:将LBA地址存入0x1f3 ~ 0x1f6;LBA地址7~0位写入端口0x1f3mov dx,0x1f3 out dx,al ;LBA地址15~8位写入端口0x1f4mov cl,8shr eax,clmov dx,0x1f4out dx,al;LBA地址23~16位写入端口0x1f5shr eax,clmov dx,0x1f5out dx,alshr eax,cland al,0x0f ;lba第24~27位or al,0xe0 ; 设置7~4位为1110,表示lba模式mov dx,0x1f6out dx,al;第3步:向0x1f7端口写入读命令,0x20 mov dx,0x1f7mov al,0x20 out dx,al;第4步:检测硬盘状态.not_ready:;同一端口,写时表示写入命令字,读时表示读入硬盘状态nopin al,dxand al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙cmp al,0x08jnz .not_ready ;若未准备好,继续等。;第5步:从0x1f0端口读数据mov ax, dimov dx, 256mul dxmov cx, ax ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,; 共需di*512/2次,所以di*256mov dx, 0x1f0.go_on_read:in ax,dxmov [bx],axadd bx,2 loop .go_on_readrettimes 510-($-$$) db 0db 0x55,0xaa

这个%include是nasm编译器中的预处理指令,意思是让编译器在编译之前把boot.inc文件包含进来。

%include "boot.inc"

boot.inc中写的是关于加载器的配置文件。nasm中的语法是:宏名 equ 值,LOADER_BASE_ADDR和LOADER_START_SECTOR是两个宏名。LOADER_BASE_ADDR定义了loader在内存中的位置,MBR要把loader从硬盘读入后放到此处。LOADER_START_SECTOR定义了loader在硬盘上的逻辑扇区地址,即LAB地址。

;------------- loader和kernel ----------LOADER_BASE_ADDR equ 0x900 LOADER_START_SECTOR equ 0x2

为函数rd_disk_m_16传递参数。由于汇编语言能够直接操作寄存器,所以其传递参数可以用寄存器,也可以用栈。这里,选择用eax、bx、cx寄存器来传递参数。函数名rd_disk_m_16的意思是“在16位模式下读硬盘”。

mov eax,LOADER_START_SECTOR ; 起始扇区lba地址mov bx,LOADER_BASE_ADDR ; 写入的地址mov cx,1 ; 待读入的扇区数

跳到了rd_disk_m_16这个函数,之后还会返回

call rd_disk_m_16 ; 以下读取程序的起始部分(一个扇区)

rd_disk_m_16函数

;-------------------------------------------------------------------------------;功能:读取硬盘n个扇区rd_disk_m_16: ;-------------------------------------------------------------------------------; eax=LBA扇区号; ebx=将数据写入的内存地址; ecx=读入的扇区数mov esi,eax ;备份eax,将exa中的值先备份到esi,因为al在out指令中会被用到,会影响eax的低8位mov di,cx ;备份cx,cx的值会在读取数据时用到;读写硬盘:;第1步:设置要读取的扇区数mov dx,0x1f2 ;sector count寄存器是用0x1f2来访问的mov al,clout dx,al ;读取的扇区数,out指令用于往端口中写入数据,dx寄存器是用来存储端口号的,al表示寄存器中的值mov eax,esi ;恢复ax;第2步:将LBA地址存入0x1f3 ~ 0x1f6;LBA地址7~0位写入端口0x1f3mov dx,0x1f3 ;LABlower out dx,al ;LBA地址15~8位写入端口0x1f4mov cl,8shr eax,cl ;逻辑右移指令,置换出地址的相应部分,写入相应的LBAmov dx,0x1f4 ;LABmidout dx,al;LBA地址23~16位写入端口0x1f5shr eax,clmov dx,0x1f5 ;LABhighout dx,alshr eax,cland al,0x0f ;lba第24~27位or al,0xe0 ; 设置7~4位为1110,表示lba模式mov dx,0x1f6out dx,al;第3步:向0x1f7端口写入读命令,0x20 mov dx,0x1f7 ;Status寄存器mov al,0x20 out dx,al;第4步:检测硬盘状态,由于寄存器还是0x1f7,所以不用为dx赋值.not_ready: ;是个标号,循环从这里开始;同一端口,写时表示写入命令字,读时表示读入硬盘状态nop ;空操作,只是为了增加延迟in al,dx ;将Status寄存器中的值读入al寄存器and al,0x88 ;第4位为1表示硬盘控制器已准备好数据传输,第7位为1表示硬盘忙cmp al,0x08 ;与0x08做减法jnz .not_ready ;若未准备好,继续等。判断结果是否等于0,等于0读数据,不等于0继续循环读状态;第5步:从0x1f0端口读数据mov ax, dimov dx, 256mul dx ;被乘数隐含在ax中mov cx, ax ; di为要读取的扇区数,一个扇区有512字节,每次读入一个字,; 共需di*512/2次,所以di*256mov dx, 0x1f0.go_on_read:in ax,dx ;读数mov [bx],axadd bx,2;每次读2字节,地址+2 loop .go_on_readret

创建/include/boot.inc文件

sudo mkdir includelscd include/sudo vim boot.inc

编译

nasm -I include/ -o mbr.bin mbr.S

写入硬盘,dd第三行显示了实际写入硬盘的数据大小,是512字节

sudo dd if=./mbr.bin of=hd60M.img bs=512 count=1 conv=notrunc


实现内核加载器

loader是要经过实模式到保护模式的过渡,并最终在保护模式下加载内核

%include "boot.inc"section loader vstart=LOADER_BASE_ADDR ;0x900; 输出背景色绿色,前景色红色,并且跳动的字符串"2 LOADER"mov byte [gs:0x20],'2'mov byte [gs:0x21],0xA4 ; A表示绿色背景闪烁,4表示前景色为红色mov byte [gs:0x22],' 'mov byte [gs:0x23],0xA4mov byte [gs:0x24],'L'mov byte [gs:0x25],0xA4 mov byte [gs:0x26],'O'mov byte [gs:0x27],0xA4mov byte [gs:0x28],'A'mov byte [gs:0x29],0xA4mov byte [gs:0x2a],'D'mov byte [gs:0x2b],0xA4mov byte [gs:0x2c],'E'mov byte [gs:0x2d],0xA4mov byte [gs:0x2e],'R'mov byte [gs:0x2f],0xA4jmp $ ; 通过死循环使程序悬停在此 vim loader.S sudo nasm -I include/ -o boot/loader.bin boot/loader.S sudo dd if=/usr/local/boot/loader.bin of=/usr/local/boot/hd60M.img bs=512 count=1 seek=2 conv=notrunc sudo bin/bochs -f boot/bochsrc.disk
需要做网站?需要网络推广?欢迎咨询客户经理 13272073477