软件下载站,为您提供安全的软件下载!

当前位置:首页 > 电脑专区 > 应用软件 > 电子阅读 > 30天自制操作系统-带书签pdf扫描版

30天自制操作系统-带书签pdf扫描版

分享到:
30天自制操作系统2012年8月由人民邮电出版社出版发行,是一本兼具趣味性、实用性与学习性的操作系统图书。30天自制操作系统中所展示的程序代码和文字的说明也很重要,通过阅读这本书来逐步学习关于这些编程语言的知识。30天自制操作系统有足足700多页,看起来很多,平均算下来,每天只要大约23页内容。所以轻轻松松就可以阅读完。作者从计算机的构造、汇编语言、C语言开始解说,让读者在实践中掌握算法。在这本书的指导下,从零编写所有代码,30天后就可以制作出一个具有窗口系统的32位多任务操作系。30天自制操作系统适合操作系统爱好者和程序设计人员阅读。
30天自制操作系统

作者介绍:

川合秀实(Hidemi.Kawai),生于1975年,是一位以“轻量化”编程思想见长的“非主流”开发者。2000年因自行开发的OSASK项目而名声大噪。OSASK是一个开源的32位微型操作系统,它并非以Linux等内核为基础,而是完全从零开始开发,在一张软盘的容量下实现了GUI、多任务、多语言等高级特性,启动时间只需1秒。本书的内容可以看成是作者以OSASK为蓝本,教会读者从零开始开发一个操作系统,同时可以让初学者在编写操作系统的过程中,了解操作系统背后更多的知识。

30天自制操作系统目录:

第0天 着手开发之前
1 前言
2 何谓操作系统
3 开发操作系统的各种方法
4 无知则无畏
5 如何开发操作系统
6 操作系统开发中的困难
7 学习本书时的注意事项(重要!)
8 各章内容摘要
第1天 从计算机结构到汇编程序入门
1 先动手操作
2 究竟做了些什么
3 初次体验汇编程序
4 加工润色
第2天 汇编语言学习与Makefile入门
1 介绍文本编辑器
2 继续开发
3 先制作启动区
4 Makefile入门
第3天 进入32位模式并导入C语言
1 制作真正的IPL
2 试错
3 读到18扇区
4 读入10个柱面
5 着手开发操作系统
6 从启动区执行操作系统
7 确认操作系统的执行情况
8 32位模式前期准备
9 开始导入C语言
10 实现HLT(harib00j)
第4天 C语言与画面显示的练习
1 用C语言实现内存写入(harib01a)
2 条纹图案(harib01b)
3 挑战指针(harib01c)
4 指针的应用(1)(harib01d)
5 指针的应用(2)(harib01e)
6 色号设定(harib01f)
7 绘制矩形(harib01g)
8 今天的成果(harib01h)
第5天 结构体、文字显示与GDT/IDT初始化
1 接收启动信息(harib02a)
2 试用结构体(harib02b)
3 试用箭头记号(harib02c)4 显示字符(harib02d)
5 增加字体(harib02e)
6 显示字符串(harib02f)
7 显示变量值(harib02g)
8 显示鼠标指针(harib02h)
9 GDT与IDT的初始化(harib02i)
第6天 分割编译与中断处理
1 分割源文件(harib03a)
2 整理Makefile(harib03b)
3 整理头文件(harib03c)
4 意犹未尽
5 初始化PIC(harib03d)
6 中断处理程序的制作(harib03e)
第7天 FIFO与鼠标控制
1 获取按键编码(hiarib04a)
2 加快中断处理(hiarib04b)
3 制作FIFO缓冲区(hiarib04c)
4 改善FIFO缓冲区(hiarib04d)
5 整理FIFO缓冲区(hiarib04e)
6 总算讲到鼠标了(harib04f)
7 从鼠标接受数据(harib04g)
第8天 鼠标控制与32位模式切换
1 鼠标解读(1)(harib05a)
2 稍事整理(harib05b)
3 鼠标解读(2)(harib05c)
4 移动鼠标指针(harib05d)
5 通往32位模式之路
第9天 内存管理
1 整理源文件(harib06a)
2 内存容量检查(1)(harib06b)
3 内存容量检查(2)(harib06c)
4 挑战内存管理(harib06d)
第10天 叠加处理
1 内存管理(续)(harib07a)
2 叠加处理(harib07b)
3 提高叠加处理速度(1)(harib07c)
4 提高叠加处理速度(2)(harib07d)
第11天 制作窗口
1 鼠标显示问题(harib08a)
2 实现画面外的支持(harib08b)
3 shtctl的指定省略(harib08c)
4 显示窗口(harib08d)
5 小实验(harib08e)
6 高速计数器(harib08f)
7 消除闪烁(1)(harib08g)
8 消除闪烁(2)(harib08h)
第12天 定时器(1)
1 使用定时器(harib09a)
2 计量时间(harib09b)
3 超时功能(harib09c)
4 设定多个定时器(harib09d)
5 加快中断处理(1)(harib09e)
6 加快中断处理(2)(harib09f)
7 加快中断处理(3)(harib09g)
第13天 定时器(2)
1 简化字符串显示(harib10a)
2 重新调整FIFO缓冲区(1)(harib10b)
3 测试性能(harib10c~harib10f)
4 重新调整FIFO缓冲区(2)(harib10g)
5 加快中断处理(4)(harib10h)
6 使用“哨兵”简化程序(harib10i)
第14天 高分辨率及键盘输入
1 继续测试性能(harib11a~harib11c)
2 提高分辨率(1)(harib11d)
3 提高分辨率(2)(harib11e)
4 键盘输入(1)(harib11f)
5 键盘输入(2)(harib11g)
6 追记内容(1)(harib11h)
7 追记内容(2)(harib11i)
第15天 多任务(1)
1 挑战任务切换(harib12a)
2 任务切换进阶(harib12b)
3 做个简单的多任务(1)(harib12c)
4 做个简单的多任务(2)(harib12d)
5 提高运行速度(harib12e)
6 测试运行速度(harib12f)
7 多任务进阶(harib12g)
第16天 多任务(2)
1 任务管理自动化(harib13a)
2 让任务休眠(harib13b)
3 增加窗口数量(harib13c)
4 设定任务优先级(1)(harib13d)
5 设定任务优先级(2)(harib13e)
第17天 命令行窗口
1 闲置任务(harib14a)
2 创建命令行窗口(harib14b)
3 切换输入窗口(harib14c)
4 实现字符输入(harib14d)
5 符号的输入(harib14e)
6 大写字母与小写字母(harib14f)
7 对各种锁定键的支持(harib14g)
第18天 dir命令
1 控制光标闪烁(1)(harib15a)
2 控制光标闪烁(2)(harib15b)
3 对回车键的支持(harib15c)
4 对窗口滚动的支持(harib15d)
5 mem命令(harib15e)
6 cls命令(harib15f)
7 dir命令(harib15g)
第19天 应用程序
1 type命令(harib16a)
2 type命令改良(harib16b)
3 对FAT的支持(harib16c)
4 代码整理(harib16d)
5 第一个应用程序(harib16e)
第20天 API
1 程序整理(harib17a)
2 显示单个字符的API(1)(harib17b)
3 显示单个字符的API(2)(harib17c)
4 结束应用程序(harib17d)
5 不随操作系统版本而改变的API(harib17e)
6 为应用程序自由命名(harib17f)
7 当心寄存器(harib17g)
8 用API显示字符串(harib17h)
第21天 保护操作系统
1 攻克难题——字符串显示API(harib18a)
2 用C语言编写应用程序(harib18b)
3 保护操作系统(1)(harib18c)
4 保护操作系统(2)(harib18d)
5 对异常的支持(harib18e)
6 保护操作系统(3)(harib18f)
7 保护操作系统(4)(harib18g)
第22天 用C语言编写应用程序
1 保护操作系统(5)(harib19a)
2 帮助发现bug(harib19b)
3 强制结束应用程序(harib19c)
4 用C语言显示字符串(1)(harib19d)
5 用C语言显示字符串(2)(harib19e)
6 显示窗口(harib19f)
7 在窗口中描绘字符和方块(harib19g)
第23天 图形处理相关
1 编写malloc(harib20a)
2 画点(harib20b)
3 刷新窗口(harib20c)
4 画直线(harib20d)
5 关闭窗口(harib20e)
6 键盘输入API(harib20f)
7 用键盘输入来消遣一下(harib20g)
8 强制结束并关闭窗口(harib20h)
第24天 窗口操作
1 窗口切换(1)(harib21a)
2 窗口切换(2)(harib21b)
3 移动窗口(harib21c)
4 用鼠标关闭窗口(harib21d)
5 将输入切换到应用程序窗口(harib21e)
6 用鼠标切换输入窗口(harib21f)
7 定时器API(harib21g)
8 取消定时器(harib21h)
第25天 增加命令行窗口
1 蜂鸣器发声(harib22a)
2 增加更多的颜色(1)(harib22b)
3 增加更多的颜色(2)(harib22c)
4 窗口初始位置(harib22d)
5 增加命令行窗口(1)(harib22e)
6 增加命令行窗口(2)(harib22f)
7 增加命令行窗口(3)(harib22g)
8 增加命令行窗口(4)(harib22h)
9 变得更像真正的操作系统(1)(harib22i)
10 变得更像真正的操作系统(2)(harib22j)
第26天 为窗口移动提速
1 提高窗口移动速度(1)(harib23a)
2 提高窗口移动速度(2)(harib23b)
3 提高窗口移动速度(3)(harib23c)
4 提高窗口移动速度(4)(harib23d)
5 启动时只打开一个命令行窗口(harib23e)
6 增加更多的命令行窗口(harib23f)
7 关闭命令行窗口(1)(harib23g)
8 关闭命令行窗口(2)(harib23h)
9 start命令(harib23i)
10 ncst命令(harib23j)
第27天 LDT与库
1 先来修复bug(harib24a)
2 应用程序运行时关闭命令行窗口(harib24b)
3 保护应用程序(1)(harib24c)
4 保护应用程序(2)(harib24d)
5 优化应用程序的大小(harib24e)
6 库(harib24f)
7 整理make环境(harib24g)
第28天 文件操作与文字显示
1 alloca(1)(harib25a)
2 alloca(2)(harib25b)
3 文件操作API(harib25c)
4 命令行API(harib25d)
5 日文文字显示(1)(harib25e)
6 日文文字显示(2)(harib25f)
7 日文文字显示(3)(harib25g)
第29天 压缩与简单的应用程序
1 修复bug(harib26a)
2 文件压缩(harib26b)
3 标准函数
4 非矩形窗口(harib26c)
5 bball(harib26d)
6 外星人游戏(harib26e)
第30天 高级的应用程序
1 命令行计算器(harib27a)
2 文本阅览器(harib27b)
3 MML播放器(harib27c)
4 图片阅览器(harib27d)
5 IPL的改良(harib27e)
6 光盘启动(harib27f)
第31天 写在开发完成之后
1 继续开发要靠大家的努力
2 关于操作系统的大小
3 操作系统开发的诀窍
4 分享给他人使用
5 关于光盘中的软件
6 关于开源的建议
7 后记
8 毕业典礼
9 附录

精彩书摘:

......
第15天
多任务(1)
挑战任务切换(harib12a)
任务切换进阶(harib12b)
做个简单的多任务(1)(harib12c)
做个简单的多任务(2)(harib12d)
提高运行速度(harib12e)
测试运行速度(harib12f)
多任务进阶(harib12g)
1 挑战任务切换(harib12a)
话说,多任务到底是啥呢?”我们今天的内容,就从这个问题开始吧。
多任务,在英语中叫做“multitask”,顾名思义就是“多个任务”的意思。简单地说,在Windows等操作系统中,多个应用程序同时运行的状态(也就是同时打开好几个窗口的状态)就叫做多任务。
对于生活在现代社会的各位来说,这种多任务简直是理所当然的事情。比如你会一边用音乐播放软件听音乐一边写邮件,邮件写到一半忽然有点东西要查,便打开Web浏览器上网搜索。这对于大家来说这些都是家常便饭了吧。可如果没有多任务的话会怎么样呢?想写邮件的时候就必须关掉正在播放的音乐,要查东西的时候就必须先保存写到一半的邮件,然后才能打开Web浏览器……光想象一下就会觉得太不方便了。
然而在从前,没有多任务反倒是普遍的情形(那个时候大家不用电脑听音乐,也没有互联网)。在那个年代,电脑一次只能运行一个程序,如果要同时运行多个程序的话,就得买好几台电脑才行。
就在那个时候,诞生了最初的多任务操作系统,大家都觉得太了不起了。从现在开始,我们也要准备给“纸娃娃系统”添加执行多任务的能力了。连这样一个小不点儿操作系统都能够实现多任务,真是让人不由地感叹它生逢其时呀。
稍稍思考一下我们就会发现,多任务这个东西还真是奇妙,它究竟是怎样做到让多个程序同时运行的呢?如果我们的电脑里面装了好多个CPU的话,同时运行多个程序倒也顺理成章,但实际上就算我们只有一个CPU,照样可以实现多任务。
其实说穿了,这些程序根本没有在同时运行,只不过看上去好像是在同时运行一样:程序A运行一会儿,接下来程序B运行一会儿,再接下来轮到程序C,然后再回到程序A……如此反复,有点像日本忍者的“分身术”呢(笑)。
为了让这种分身术看上去更完美,需要让操作系统尽可能快地切换任务。如果10秒才切换一次,那就连人眼都能察觉出来了,同时运行多个程序的戏码也就穿帮了。再有,如果我们给程序C发出一个按键指令,正巧这个瞬间系统切换到了程序A的话,我们就不得不等上20秒,才能重新轮到程序C对按键指令作出反应。这实在是让人抓狂啊(哭)。
在一般的操作系统中,这个切换的动作每0.01~0.03秒就会进行一次。当然,切换的速度越快,让人觉得程序是在同时运行的效果也就越好。不过,CPU进行程序切换(我们称为“任务切换”)这个动作本身就需要消耗一定的时间,这个时间大约为0.0001秒左右,不同的CPU及操作系统所需的时间也有所不同。如果CPU每0.0002秒切换一次任务的话,该CPU处理能力的50%都要被任务切换本身所消耗掉。这意味着,如果同时运行2个程序,每个程序的速度就只有单独运行时的1/4,这样你会觉得开心吗?如果变成这种结果,那还不如干脆别搞多任务呢。
相比之下,即便是每0.001秒切换一次任务,单单在任务切换上面也要消耗CPU处理能力的10%。大概有人会想,10%也没什么大不了的吧?可如果你看看速度快10%的CPU卖多少钱,说不定就会恍然大悟,“对啊,只要优化一下任务切换间隔,就相当于一分钱也不花,便换上了比现在更快的CPU嘛……”(笑),你也就明白了浪费10%也是很不值得的。正是因为这个原因,任务切换的间隔最短也得0.01秒左右,这样一来只有1%的处理能力消耗在任务切换上,基本上就可以忽略不计了。
关于多任务是什么的问题,已经大致讲得差不多了,接下来我们来看看如何让CPU来处理多任务。
当你向CPU发出任务切换的指令时,CPU会先把寄存器中的值全部写入内存中,这样做是为了当以后切换回这个程序的时候,可以从中断的地方继续运行。接下来,为了运行下一个程序,CPU会把所有寄存器中的值从内存中读取出来(当然,这个读取的地址和刚刚写入的地址一定是不同的,不然就相当于什么都没变嘛),这样就完成了一次切换。我们前面所说的任务切换所需要的时间,正是对内存进行写入和读取操作所消耗的时间。
接下来我们来看看寄存器中的内容是怎样写入内存里去的。下面这个结构叫做“任务状态段”(task.status.segment),简称TSS。TSS有16位和32位两个版本,这里我们使用32位版。顾名思义,TSS也是内存段的一种,需要在GDT中进行定义后使用。
参考上面的结构定义,TSS共包含26个int成员,总计104字节(摘自CPU的技术资料),我特意把它们分成4行来写。从开头的backlink起,到cr3为止的几个成员,保存的不是寄存器的数据,而是与任务设置相关的信息,在执行任务切换的时候这些成员不会被写入(backlink除外,某些情况下是会被写入的)。后面的部分中我们会用到这里的设定,不过现在你完全可以先忽略它。
第2行的成员是32位寄存器,第3行是16位寄存器,应该没必要解释了吧……不对,eip好像到现在还没讲过呢。EIP的全称是"extended.instruction.pointer",也就是"扩展指令指针寄存器"的意思。这里的"扩展"代表它是一个32位寄存器,也就是说其对应的16位版本叫做IP,类比一下的话,跟EAX与AX之间的关系是一样的。
EIP是CPU用来记录下一条需要执行的指令位于内存中哪个地址的寄存器,因此它才被称为"指令指针"。如果没有这个寄存器,记性不好的CPU就会忘记自己正在运行哪里的程序,于是程序就没办法正常运行了。每执行一条指令,EIP寄存器中的值就会自动累加,从而保证一直指向下一条指令所在的内存地址。
说点题外话,JMP指令实际上是一个向EIP寄存器赋值的指令。JMP.0x1234这种写法,CPU会解释为MOV.EIP,0x1234,并向EIP赋值。也就是说,这条指令其实是篡改了CPU记忆中下一条该执行的指令的地址,蒙了CPU一把。这样一来,CPU在读取下一条指令时,就会去读取0x1234这个地址中的指令。你看,这不就相当于是做了一个跳转吗?
对了,如果你在汇编语言里用MOV EIP,0x1234这种写法是会出错的,还是不要尝试的好。在汇编语言中,应该使用JMP 0x1234来代替MOV EIP,0x1234。
如果在TSS中将EIP寄存器的值记录下来,那么当下次再返回这个任务的时候,CPU就可以明白应该从哪里读取程序来运行了。
按照常识,段寄存器应该是16位的才对,可是在TSS数据结构中却定义成了int(也就是DWORD)类型。我们可以大胆想象一下,说不定英特尔公司的人将来会把段寄存器变成32位的,这样想想也挺有意思的呢(笑)。
第4行的ldtr和iomap也和第1行的成员一样,是有关任务设置的部分,因此在任务切换时不会被CPU写入。也许你会想,那就和第1行一样,暂时先忽略好了--但那可是绝对不行的!如果胡乱赋值的话,任务就无法正常切换了,在这里我们先将ldtr置为0,将iomap置为0x40000000就好了。
关于TSS的话题暂且先告一段落,我们回来继续讲任务切换的方法。要进行任务切换,其实还得用JMP指令。JMP指令分为两种,只改写EIP的称为near模式,同时改写EIP和CS的称为far模式,在此之前我们使用的JMP指令基本上都是near模式的。不记得CS是什么了?CS就是代码段(code segment)寄存器啦。
说起来我们其实用过一次far模式的JMP指令,就在asmhead.nas的"bootpack启动"的最后一句(见8.5节)。
JMP DWORD 2*8:0x0000001b这条指令在向EIP存入0x1b的同时,将CS置为2*8(=16)。像这样在JMP目标地址中带冒号(:)的,就是far模式的JMP指令。
如果一条JMP指令所指定的目标地址段不是可执行的代码,而是TSS的话,CPU就不会执行通常的改写EIP和CS的操作,而是将这条指令理解为任务切换。也就是说,CPU会切换到目标TSS所指定的任务,说白了,就是JMP到一个任务那里去了。
CPU每次执行带有段地址的指令时,都会去确认一下GDT中的设置,以便判断接下来要执行的JMP指令到底是普通的far-JMP,还是任务切换。也就是说,从汇编程序翻译出来的机器语言来看,普通的far-JMP和任务切换的far-JMP,指令本身是没有任何区别的。
好了,枯燥的讲解就到这里,让我们实际做一次任务切换吧。我们准备两个任务:任务A和任务B,尝试从A切换到B。
首先,我们需要创建两个TSS:任务A的TSS和任务B的TSS。
本次的HariMain节选
struct TSS32 tss_a, tss_b;
向它们的ldtr和iomap分别存入合适的值。
本次的HariMain节选
tss_a.ldtr = 0;
tss_a.iomap = 0x40000000;
tss_b.ldtr = 0;
tss_b.iomap = 0x40000000;
接着将它们两个在GDT中进行定义。
本次的HariMain节选
struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
set_segmdesc(gdt + 3, 103, (int) &tss_a, AR_TSS32);
set_segmdesc(gdt + 4, 103, (int) &tss_b, AR_TSS32);
现在两个TSS都创建好了,该进行实际的切换了。
我们向TR寄存器存入3*8这个值,这是因为我们刚才把当前运行的任务定义为GDT的3号。TR寄存器以前没有提到过,它的作用是让CPU记住当前正在运行哪一个任务。当进行任务切换的时候,TR寄存器的值也会自动变化,它的名字也就是"task register"(任务寄存器)的缩写。我们每次给TR寄存器赋值的时候,必须把GDT的编号乘以8,因为英特尔公司就是这样规定的。如果你有意见的话,可以打电话找英特尔的大叔投诉哦(笑)。
给TR寄存器赋值需要使用LTR指令,不过用C语言做不到。唉,各位是不是都已经见怪不怪了啊?啥?你早就料到了?(笑)所以说,正如你所料,我们只能把它写进naskfunc.nas里面。
……

特别备注:

1.来源于网络,仅用于分享知识,学习和交流!请下载完在24小时内删除。
2.禁用于商业用途!如果您喜欢《30天自制操作系统》,请购买正版,谢谢合作。
3.爱学习,请到3322软件站查找资源自行下载!

下载说明:

方法一:
1、下载并解压,得出pdf文件
2、如果打不开本文件,别着急,这时候请务必在3322软件站选择一款阅读器下载哦
3、安装后,再打开解压得出的pdf文件
4、以上都完成后,接下来双击进行阅读就可以啦,朋友们开启你们的阅读之旅吧。
方法二:
1、可以在手机里下载3322软件站中的阅读器和百度网盘
2、接下来直接将pdf传输到百度网盘
3、用阅读器打开即可阅读
展开更多

软件截图

下载提示

30天自制操作系统-带书签pdf扫描版

正在下载...

扫描二维码,手机下载APP

软件下载站本地下载

相关文章