zepto网站开发,用帝国cms做的网站首页,软装设计公司排行,做老托福听力的网站前情提要
上一节我们讲了如何启动计算机#xff0c;这一节我们讲如何加载内核#xff0c;内核是存在于硬盘上的一段程序#xff0c;要加载这段程序#xff0c;那么必然需要从硬盘上读取数据#xff0c;这里我们就需要使用 ATA PIO 模式 根据ATA规范#xff0c;所有符合A…前情提要
上一节我们讲了如何启动计算机这一节我们讲如何加载内核内核是存在于硬盘上的一段程序要加载这段程序那么必然需要从硬盘上读取数据这里我们就需要使用 ATA PIO 模式 根据ATA规范所有符合ATA的驱动器必须始终支持PIO模式作为默认的数据传输机制。 现在较为流行的SATA硬盘也是一种符合ATA标准的硬盘所以当然也需要支持 ATA PIO而 ATA PIO 较为简单所以我们就将其当做默认的读取硬盘的模式
在实际应用中为了获得更好的性能和效率通常会选择更高级的硬盘访问模式如 DMA 或 Ultra DMA以及操作系统提供的直接访问硬盘的接口如 Windows 的AHCI模式。这些模式能够更有效地利用系统资源提供更快速的数据传输速度。甚至是NVME直接走PCIE通道与CPU直连。但是这些比较复杂不在本文的考虑范围内。
一、硬盘的主要端口 其中Primary为主通道Secondary为从通道
其中主通道读时
0x1F0 是数据端口0x1F1 是错误端口可以返回错误信息每一位都是一个错误信息包括0、AMNF未找到地址标记。1、TKZNF未找到零磁道。2、ABRT中止命令。3、MCR变更请求。4、IDNF未找到ID。5、MC 发生了变化。6、UNC不可纠正的数据错误。7、BBK检测到坏块。0x1F2 是扇区数量端口0x1F3 是LBA低地址0x1F4 是LBA中地址0x1F5 是LBA高地址0x1F6 0-3位在CHS寻址中表示柱头位在LBA寻址中表示LBA地址的24-27位。4位DRV表示选择主盘或者从盘。5位、永远为1。6位、如果为0则为CHS寻址如果为1则为LBA寻址。7位、永远为1。0x1F7 是状态寄存器端口 0位ERR如果为1则表示出错了。3位Data 如果为1表示硬盘已经把数据准备好了。6位DRDY表示硬盘检测正常可以执行命令。7位BSY如果为1表示硬盘正繁忙此寄存器中的其他位都无效。
主通道写时有一些yu寄存器有了不同的用途
0x1F1 是参数端口用于传递写硬盘时的参数0x1F7 是指令端口我们主要用到了这么几个指令。0xEC硬盘识别。0x20读扇区。0x30写扇区。
二、加载Loader
哈哈哈哈上面说的是加载内核现在又成了加载loader没办法加载内核之前就得加载LoaderLoader的作用有 加载内核loader 负责将操作系统内核从存储设备如硬盘、闪存中读取到内存中以便后续执行。确认内核完整性loader 在加载内核之前通常会对内核进行校验以确保内核文件的完整性和正确性避免因为损坏或错误的内核文件导致系统启动失败。设置环境loader 在加载内核前会设置好适当的执行环境包括初始化硬件设备、建立内存映射关系等为内核的正常执行做好准备工作。启动内核加载完内核后loader 会将控制权转交给内核的起始地址启动内核的执行让操作系统开始运行。 由于MBR是占据了硬盘的第0扇区以逻辑LBA方式扇区从0开始编号若是以物理CHS方式扇区则从1开始编号所以我们的loader就放在第1扇区可以看第二章的内存布局现在有两块内存可用0x5000x7BFF和0x7E009FBFF那我们就放在 0x600 的地方吧。下面我们接着改MBR
2.1、修改Mbr使其可以加载Loader
这里我们添加一点宏定义
; os/src/boot/boot.inc
LOADER_BASE_ADDR equ 0x600
LOADER_START_SECTOR equ 0x1然后改写mbr
; os/src/boot/mbr.s
; 设置开始的地址并且初始化寄存器
%include boot.inc
SECTION MBR vstart0x7c00 mov ax,cs mov ds,axmov es,axmov ss,axmov fs,axmov sp,0x7c00mov ax,0xb800mov gs,ax; 利用0x06号功能实现清理屏幕
; AL 0x06 功能号
; AL 上卷的行数(如果为0,表示全部)
; BH 上卷行属性
; (CL,CH) 窗口左上角的(X,Y)位置,这里是 (0,0)
; (DL,DH) 窗口右下角的(X,Y)位置,这里是 (80,25)mov ah, 0x06mov al, 0x00mov bh, 0x7mov bl, 0x00mov cx, 0 mov dx, 0x184fint 0x10 ; int 0x10mov byte [gs:0x00],M ; 字符为M的ascii值mov byte [gs:0x01],0x0F ; 11100001b 即背景色为黑字体为白不闪烁 mov byte [gs:0x02],B ;mov byte [gs:0x03],0x0F ; mov byte [gs:0x04],R ;mov byte [gs:0x05],0x0F ;mov eax,LOADER_START_SECTOR ; Loader起始扇区 mov bx, LOADER_BASE_ADDR ; Loader起始内存地址mov cx, 1 ; 待写入扇区数call rd_disk_m_16 ; 执行读取硬盘程序jmp LOADER_BASE_ADDR ; 跳转到Loader执行rd_disk_m_16: ; eaxLBA扇区号; ebxLoader内存; ecx扇区数量mov esi,eax ; 备份eaxmov di,cx ; 备份cxmov dx,0x1f2 ; 设置要写入端口即读取端口数mov al,cl ; 设置要读取扇区数out dx,al ; 设置mov eax,esi ; 恢复eaxmov dx,0x1f3 ; 设置要写入端口即LBA低地址 out dx,al mov cl,8 ; ax右移八位 shr eax,clmov dx,0x1f4 ; 设置要写入端口即LBA中地址 out dx,alshr eax,cl ; ax右移八位 mov dx,0x1f5 ; 设置要写入端口即LBA高地址 out dx,alshr eax,cl ; ax右移八位and al,0x0f ; 保留低4位设置高4位为 0000or al,0xe0 ; 保留低4位设置高4位为 1110mov dx,0x1f6out dx,almov dx,0x1f7 ;mov al,0x20 ; 读扇区指令 out dx,al.not_ready: ; 未准备好nop ; 不执行任何指令占用一个机器周期in al,dx ; 查看读取状态and al,0x88 ; 与 10001000 做与运算cmp al,0x08 ; 比较第三位和第七位jnz .not_readymov ax, di ; 要读的扇区数mov dx, 256 ; 乘以256即要读多少次mul dxmov cx, ax ; 将要读的次数传给cxmov dx, 0x1f0 ; 要读的端口号.go_on_read:in ax,dx ; 向ax中读一次读两个字节mov [bx],ax ; 将ax中数据给bx地址的内存add bx,2 ; bx中内存地址加2loop .go_on_read ; 循环cx次ret; 将510个字节中剩余的空间填充为0
; $ 是当前地址
; $$ 是本节开头地址也就是0x7c00
times 510-($-$$) db 0
db 0x55,0xaa2.2、写一个小Loader
; os/src/boot/loader.s
%include boot.inc
section loader vstartLOADER_BASE_ADDR
.begin_loader:mov byte [gs:0x00],L ; 字符为M的ascii值mov byte [gs:0x01],0x0F ; 11100001b 即背景色为黑字体为白不闪烁 mov byte [gs:0x02],O ;mov byte [gs:0x03],0x0F ; mov byte [gs:0x04],A ;mov byte [gs:0x05],0x0F ;mov byte [gs:0x06],D ;mov byte [gs:0x07],0x0F ;mov byte [gs:0x08],E ;mov byte [gs:0x09],0x0F ;mov byte [gs:0x0A],R ;mov byte [gs:0x0B],0x0F ;; 程序在此处卡住
jmp $这里loader的作用还是输出一些内容作为指示
2.3、执行
执行前需要把脚本更新一下
# os/run.sh
# 编译mbr
nasm -I src/boot/ -o bin/mbr.bin src/boot/mbr.s
nasm -I src/boot/ -o bin/loader.bin src/boot/loader.s # 复制mbr二进制程序到硬盘
dd ifbin/mbr.bin of/home/lyj/bochs/bin/hd60M.img bs512 count1 seek0 convnotrunc
dd ifbin/loader.bin of/home/lyj/bochs/bin/hd60M.img bs512 count2 seek1 convnotrunc# 启动仿真
/home/lyj/bochs/bin/bochs -f /home/lyj/bochs/bin/bochsrc.disk 执行 结束语
第三章也结束了这一章我们讲了如何加载一个Loader以及如何读写硬盘下一章我们就要开始讲一些有关于保护模式的东西了先将这个Loader完善一下。