自己动手从零写桌面操作系统GrapeOS系列教程——汇编语言

在内存中准备一段有特征的512字节数据,地址为0x7e00~0x7fff,其特征是前3个字节依次为4、5、6,最后3个字节依次为6、5、4。然后将该段内存数据写入到硬盘的第2个扇区,并查看虚拟硬盘第2个扇区的数据是否与内存中0x7e00~0x7fff的数据一致,如果一致则说明写硬盘成功。

本讲代码文件只有一个boot2.asm
boot2.asm代码如下:

;定义常量
DISK_BUFFER equ 0x7e00 ;临时存放数据用的缓存区,放到boot程序之后。0x7e00~0x7fff。

org 0x7c00

;初始化段寄存器
mov ax,cs
mov ds,ax ;ds指向与cs相同的段

mov bx,DISK_BUFFER
;向缓存区前3个字节依次写入4、5、6。
mov byte [bx+0],4
mov byte [bx+1],5
mov byte [bx+2],6
;向缓存区最后3个字节依次写入6、5、4。
mov byte [bx+509],6
mov byte [bx+510],5
mov byte [bx+511],4

mov si,DISK_BUFFER
mov edi,1 ;写入硬盘的第2个扇区
call func_write_one_sector

stop:
hlt
jmp stop 

;将内存中的512个字节写入到硬盘的一个指定扇区中(主硬盘控制器主盘)
;输入参数:ds:si,edi。
;ds:si 数据源内存地址
;edi LBA扇区号
;输出参数:无。
func_write_one_sector:
;第1步:检查硬盘控制器状态
mov dx,0x1f7
.not_ready1:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0xc0 ;第7位为1表示硬盘忙,第6位为1表示硬盘控制器已准备好,正在等待指令。
cmp al,0x40 ;当第7位为0,且第6位为1,则进入下一个步。
jne .not_ready1 ;若未准备好,则继续判断。
;第2步:设置要写入的扇区数
mov dx,0x1f2
mov al,1
out dx,al ;写入1个扇区
;第3步:将LBA地址存入0x1f3~0x1f6
mov eax,edi
;LBA地址7~0位写入端口0x1f3
mov dx,0x1f3
out dx,al
;LBA地址15~8位写入端口写入0x1f4
shr eax,8
mov dx,0x1f4
out dx,al
;LBA地址23~16位写入端口0x1f5
shr eax,8
mov dx,0x1f5
out dx,al
;第4步:设置device端口
shr eax,8
and al,0x0f ;LBA第24~27位
or al,0xe0 ;设置7~4位为1110,表示LBA模式,主盘
mov dx,0x1f6
out dx,al
;第5步:向0x1f7端口写入写命令0x30
mov dx,0x1f7
mov al,0x30
out dx,al
;第6步:检测硬盘状态
.not_ready2:
nop ;nop相当于稍息 hlt相当于睡觉
in al,dx ;读0x1f7端口
and al,0x88 ;第7位为1表示硬盘忙,第3位为1表示硬盘控制器已准备好数据传输。
cmp al,0x08 ;当第7位为0,且第3位为1,进入下一步。
jne .not_ready2 ;若未准备好,则继续判断。
;第7步:向0x1f0端口写数据
mov cx,256 ;每次写入2字节,一个扇区需要写256次。
mov dx,0x1f0
.go_on_write:
mov ax,[si]
out dx,ax
add si,2
loop .go_on_write
ret

times 510-($-$$) db 0
db 0x55,0xaa

之前我们介绍过读硬盘操作和写硬盘操作都是7个步骤,其中只有第5步和第7步不同,其它步骤完全相同,大家可以和上一讲中的代码对比看一下。
下面我们将boot2.asm编译并写入到虚拟硬盘的第一个扇区:

nasm boot2.asm -o boot2.bin
dd conv=notrunc if=boot2.bin of=/media/VMShare/GrapeOS.img

此时用hexdum命令查看一下虚拟硬盘第二个扇区当前的数据,截图如下:

从上面的截图可以看到,此时虚拟硬盘第二个扇区前3个字节依次为1、2、3,最后3个字节依次为3、2、1。
下面我们以调试模式运行QEMU:

qemu-system-i386 d:\GrapeOS\VMShare\GrapeOS.img -S -s

通过GDB连接到QEMU,直接输入GDB命令c,让程序运行几秒钟,然后Ctrl+C,让程序暂停。此时写硬盘程序应该已经运行完了。此时查看一下内存0x7e00~0x7fff的数据:

(gdb) x /512xb 0x7e00

从上面截图可以看到,在内存0x7e00~0x7fff的数据中,前3个字节依次为4、5、6,最后3个字节依次为6、5、4,其余全是0。如果程序运行正确的话,此时硬盘第二扇区中的数据与此相同。
下面我们退出GDB,并关闭QEMU。然后用hexdum命令再查看一下虚拟硬盘第二个扇区的数据,截图如下:

从上面截图中可以看到,硬盘第二扇区的数据与内存中0x7e00~0x7fff的数据一致,说明写入成功,实验完毕。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
本书在详细分析操作系统原理的基础上,用丰富的实例代码,一步一步地指导读者用C语言汇编语言编写出一个具备操作系统基本功能的操作系统框架。本书不同于其他的理论型书籍,而是提供给读者一个动手实践的路线图。书中讲解了大量在开发操作系统中需注意的细节问题,这些细节不仅能使读者更深刻地认识操作系统的核心原理,而且使整个开发过程少走弯路。全书共分7章。 本书适合各类程序员、程序开发爱好者阅读,也可作为高等院校操作系统课程的实践参考书。 折叠 作品目录 第1章 马上动手写一个最小的"操作系统"1 1.1 准备工作1 1.2 10分钟完成的操作系统1 1.3 Boot Sector3 1.4 代码解释3 1.5 水面下的冰山5 1.6 回顾6 第2章 搭建你的工作环境7 2.1 虚拟计算机(Virtual PC)7 2.1.1 Virtual PC初体验8 2.1.2 创建你的第一个Virtual PC9 2.1.3 虚拟软盘研究12 2.1.4 虚拟软盘实战14 2.2 编译器(NASM & GCC)18 2.3 安装虚拟Linux19 2.4 在虚拟Linux上访问Windows文件夹26 2.5 安装虚拟PCDOS26 2.6 其他要素29 2.7 Bochs29 2.7.1 Bochs vs. Virtual PC vs. VMware30 2.7.2 Bochs的使用方法31 2.7.3 用Bochs进行调试33 2.7.4 在Linux上开发34 2.8 总结与回顾36 第3章 保护模式(Protect Mode)37 3.1 认识保护模式37 3.1.1 GDT(Global Descriptor Table) 42 3.1.2 实模式到保护模式,不一般的jmp45 3.1.3 描述符属性47 3.2 保护模式进阶50 3.2.1 海阔凭鱼跃50 3.2.2 LDT(Local Descriptor Table)58 3.2.3 特权级62 3.3 页式存储82 3.3.1 分页机制概述83 3.3.2 编写代码启动分页机制84 3.3.3 PDE和PTE85 3.3.4 cr388 3.3.5 回头看代码88 3.3.6 克勤克俭用内存90 3.3.7 进一步体会分页机制100 3.4 中断和异常107 3.4.1 中断和异常机制109 3.4.2 外部中断111 3.4.3 编程操作8259A113 3.4.4 建立IDT116 3.4.5 实现一个中断117 3.4.6 时钟中断试验119 3.4.7 几点额外说明121 3.5 保护模式下的I/O122 3.5.1 IOPL122 3.5.2 I/O许可位图(I/O Permission Bitmap)123 3.6 保护模式小结123 第4章 让操作系统走进保护模式125 4.1 突破512字节的限制125 4.1.1 FAT12126 4.1.2 DOS可以识别的引导盘131 4.1.3 一个最简单的Loader132 4.1.4 加载Loader入内存133 4.1.5 向Loader交出控制权142 4.1.6 整理boot.asm142 4.2 保护模式下的"操作系统"144 第5章 内核雏形146 5.1 用NASM在Linux下写Hello World146 5.2 再进一步,汇编和C同步使用148 5.3 ELF(Executable and Linkable Format)150 5.4 从Loader到内核155 5.4.1 用Loader加载ELF155 5.4.2 跳入保护模式161 5.4.3 重新放置内核170 5.4.4 向内核交出控制权175 5.4.5 操作系统的调试方法176 5.5 扩充内核184 5.5.1 切换堆栈和GDT184 5.5.2 整理我们的文件夹191 5.5.3 Makefile191 5.5.4 添加中断处理200 5.5.5 两点说明218 5.6 小结219 第6章 进程221 6.1 迟到的进程221 6.2 概述222 6.2.1 进程介绍222 6.2.2 未雨绸缪--形成进程的必要考虑222 6.2.3 参考的代码224 6.3 最简单的进程224 6.3.1 简单进程的关键技术预测225 6.3.2 第一步--ring0→ring1227 6.3.3 第二步--丰富中断处理程序243 6.3.4 进程体设计技巧254 6.4 多进程256 6.4.1 添加一个进程体256 6.4.2 相关的变量和宏257 6.4.3 进程表初始化代码扩充258 6.4.4 LDT260 6.4.5 修改中断处理程序261 6.4.6 添加一个任务的步骤总结263 6.4.7 号外:Minix的中断处理265 6.4.8 代码回顾与整理269 6.5 系统调用280 6.5.1 实现一个简单的系统调用280 6.5.2 get_ticks的应用286 6.6 进程调度292 6.6.1 避免对称--进程的节奏感292 6.6.2 优先级调度总结300 第7章 输入/输出系统302 7.1 键盘302 7.1.1 从中断开始--键盘初体验302 7.1.2 AT、PS/2键盘304 7.1.3 键盘敲击的过程304 7.1.4 解析扫描码309 7.2 显示器325 7.2.1 初识TTY325 7.2.2 基本概念326 7.2.3 寄存器328 7.3 TTY任务332 7.3.1 TTY任务框架的搭建334 7.3.2 多控制台340 7.3.3 完善键盘处理346 7.3.4 TTY任务总结354 7.4 区分任务和用户进程354 7.5 printf357 7.5.1 为进程指定TTY357 7.5.2 printf()的实现358 7.5.3 系统调用write()361 7.5.4 使用printf()363 后记366
自己动手从0到1写嵌入式操作系统是一个需要全面的学习和深入的项目。首先,我们需要了解嵌入式系统的基本原理和工作原理,包括硬件和软件的结构与交互。然后,我们需要学习嵌入式系统开发的相关知识,如汇编语言、C语言等编程语言,以及相关的开发工具和平台。 接下来,我们可以开始编写嵌入式操作系统的核心部分,包括启动、进程管理、任务调度、内存管理、设备驱动等功能。在编写过程中,我们需要仔细设计系统的结构和接口,确保各个模块之间的协调和数据的正确传递。 在编写操作系统的过程中,我们还需要进行系统的调试和测试,以确保系统的稳定性和正确性。通过调试和测试,我们可以找出系统中的问题并进行修正,提高系统的性能和可靠性。 最后,我们可以将编写的嵌入式操作系统生成为PDF文档,以便于其他人学习和使用。在PDF文档中,我们可以详细描述操作系统的设计思路、实现方法和使用说明,让其他人能够更加容易地理解和使用这个操作系统。 总之,自己动手从0到1写嵌入式操作系统是一项具有挑战性的任务,需要全面的学习和深入的研究。通过学习相关知识、编写核心模块、进行调试和测试,最终可以得到一个完整的嵌入式操作系统,并将其生成为PDF文档,分享给他人。这样的项目将帮助我们深入了解嵌入式系统的原理和开发过程,并提高我们的编程和系统设计能力。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

2301_76429513

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值