使用开源软件-自己动手写操作系统WriteOS_图文(精)
- 格式:doc
- 大小:1.79 MB
- 文档页数:13
写一个简易嵌入式操作系统在了解了操作系统的原理和工作后,我们可以自己写一个简易的嵌入式操作系统,下面由店铺为大家整理了写一个简易嵌入式操作系统的相关知识,希望对大家有帮助!写一个简易嵌入式操作系统概述1.首先确定CPU,在这里为了简单,就选用嵌入式的CPU,比如arm系列,之所以用RISC(简单指令集)类型的CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页式内存管理,还有就是芯片内部集成了一些常用外设控制器,比如以太网卡,串口等等,不需要像在PC机的主板上那么多外设芯片2.确定要实现的模块和功能,为了简单,只实现多任务调度(但有限制,比如最多不超过10),实现中断处理(不支持中断优先级),不进行动态SHELL交互,不实现动态模块加载,不实现fork之类的动态进程派生和加载(也就是说要想在你的操作系统上加入用户程序,只能静态编译进内核中;不支持文件系统,不支持网络,不支持PCI,磁盘等外设(除了支持串口,呵呵,串口最简单嘛),不支持虚拟内存管理(也就是说多任务中的每个进程都可以访问到任何地址,这样做的话,一个程序死了,那么这个操作系统也就玩完了)3.确定要使用的编译器,这里采用GCC,文件采用ELF格式,当然,最终的文件就是BIN格式,GCC和LINUX有着紧密的联系,自己的操作系统,需要C库支持和系统调用支持,所以需要自己去裁剪库,自己去实现系统调用4.实现步骤:首先是CPU选型,交叉编译环境的建立,然后就是写BOOTLOADER,写操作系统通过以上4点的学习一个简单的嵌入式操作系统准备工作就差不多做好了。
写一个简易嵌入式操作系统详解程序本质的剖析写操作系统这个高端大气上档次的工作肯定要有一些铺垫了,最必须的就是对你写的程序的了解,也许你会说,我写的程序,我还能不理解吗,但是这次咱么要从寄存器角度分析。
咱们首先从类比学习开始,咱们先来理解中断,对于中断,学习单片机的小朋友们肯定很理解,咱么来一起回顾下,单片机是怎么用硬件实现中断的(更为具体的说明在Cortex-M3权威指南-carpter9中断的具体行为)其实中断就是多任务的环境了,只不过这个多任务环境只能有两个任务(在只有一个中断的前提下),那么只要咱么能模拟出来中断,那实现自己的操作系统也是很简单的呢。
OS操作系统课程实验指导书附运行截图实验1使用动态优先权的进程调度算法的模拟1、实验目的(1)加深对进程概念的理解(2)深入了解系统如何组织进程,创建进程(3)进一步认识如何实现处理机调度2、实验内容(1)实现对N个进程采用动态优先权优先算法的进程调度。
(2)每个用来标识进程的进程控制块PCB用结构来描述,包括以下字段:进程标识数ID。
进程优先数PRIORITY,并规定优先数越大的进程,其优先权越高。
进程已占用的CPU时间CPUTIME。
进程还需占用的CPU时间ALLTIME。
当进程运行完毕时,ALLTIME变为0。
进程的阻塞时间STARTBLOCK,表示当进程再运行STARTBLOCK 个时间片后,将进入阻塞状态。
进程被阻塞的时间BLOCKTIME,表示已阻塞的进程再等待BLOCKTIME个时间片后,将转换成就绪状态。
进程状态STATE。
队列指针NEXT,用来将PCB排成队列。
(3)优先数改变的原则:进程在就绪队列中停留一个时间片,优先数加1。
进程每运行一个时间片,优先数减3。
(4)假设在调度前,系统中有5个进程,它们的初始状态如下:ID 0 1 2 3 4PRIORITY 9 38 30 29 0CPUTIME 0 0 0 0 0ALLTIME 3 3 6 3 4STARTBLOCK 2 -1 -1 -1 -1BLOCKTIME 3 0 0 0 0STATE ready ready ready ready ready(5)为了清楚的观察各进程的调度过程,程序应将每个时间片内的情况显示出来,参照的具体格式如下:RUNNING PROG:i READY-QUEUE:->id1->id2BLOCK-QUEUE:->id3->id4= = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = = == = =ID 0 1 2 3 4PRIORITY P0 P1 P2 P3 P4CUPTIME C0 C1 C2 C3 C4ALLTIME A0 A1 A2 A3 A4STARTBLOCK T0 T1 T2 T3 T4BLOCKTIME B0 B1 B2 B3 B4STATE S0 S1 S2 S3 S43、实验结果(给出编写的程序源代码和运行结果的截图)【程序代码】#include#include#define N 5// 进程状态enum STATE { Ready, Run, Block, Finish };// PCB数据结构struct PCB {int id; // 标志数int priority; // 优先数int cpuTime; // 已占CPU时间int allTime; // 还需占CPU时间int blockTime; // 已被阻塞的时间int startBlock; // 开始阻塞时间STATE state; // 进程状态PCB *pre; // PCB的前指针PCB *nxt; // PCB的后指针};int id[N] = {0, 1, 2, 3, 4};int priority[N] = {9, 38, 30, 29, 0};int cpuTime[N] = {0, 0, 0, 0, 0};int allTime[N] = {3, 3, 6, 3, 4};int startBlock[N] = {2, -1, -1, -1, -1};int blockTime[N] = {3, 0, 0, 0, 0};void QuePush(PCB *process, PCB *queHead){process->pre = NULL;process->nxt = queHead->nxt;if (queHead->nxt != NULL) {queHead->nxt->pre = process;}queHead->nxt = process;}void quePop(PCB *process, PCB *queHead){if (process->pre != NULL) {process->pre->nxt = process->nxt;} else {queHead->nxt = process->nxt;}if (process->nxt != NULL) {process->nxt->pre = process->pre;}process->pre = process->nxt = NULL;}void queWalk(PCB *queHead){PCB *pro = queHead->nxt;if (pro == NULL) {printf("(没有进程啦)\");return;}while (pro != NULL){printf("id: %d, priority: %d, cpuTime: %d, alltime: %d,blockTime: %d,state:%d,startblock: %d\", pro->id, pro->priority, pro->cpuTime, pro->allTime, pro->blockTime, pro->state, pro->startBlock);pro = pro->nxt;}}int readyQueNum; // 就绪队列的进程数量PCB readyQueHead; // 就绪队列的头部PCB *readyMaxProcess; // 就绪队列中优先级最高的进程void readyQuePush(PCB *process){readyQueNum ++;process->state = Ready;QuePush(process, &readyQueHead);}PCB* readyQuePop(){readyQueNum --;quePop(readyMaxProcess, &readyQueHead);return readyMaxProcess;}// 每个时间片,更新就绪队列里进程的信息void readyQueUpdate(){int maxPriority = -1;PCB *pro = readyQueHead.nxt;if (pro == NULL) {// 就绪队列没有进程readyMaxProcess = NULL;return;}while (pro != NULL){pro->priority ++;if (pro->priority > maxPriority) {maxPriority = pro->priority;readyMaxProcess = pro;}pro = pro->nxt;}}// 返回就绪队列最高优先级的值int readyMaxPriority(){return readyMaxProcess->priority;}// 查看就绪队列里进程的信息void readyQueWalk(){printf("就绪队列里的进程信息为:\");queWalk(&readyQueHead);}#define EndBlockTime 3 // 进程最长被阻塞时间int blockQueNum; // 阻塞队列的进程数量PCB blockQueHead; // 阻塞队列的头部PCB *blockMaxProcess; // 阻塞队列中优先级最高的进程// 进程插入到阻塞队列void blockQuePush(PCB *process){blockQueNum ++;process->blockTime = 0;process->state = Block;if (process->blockTime != -1) {QuePush(process, &blockQueHead);}}// 优先级最高的进程出列PCB* blockQuePop(){blockQueNum --;quePop(blockMaxProcess, &blockQueHead);return blockMaxProcess;}// 每个时间片,更新阻塞队列里进程的信息void blockQueUpdate(){int maxPriority = -1;PCB *pro = blockQueHead.nxt;while (pro != NULL){pro->blockTime ++;if (pro->blockTime >= EndBlockTime) {PCB *process = pro;pro = pro->nxt;// 阻塞时间到,调入就绪队列blockQueNum --;quePop(process, &blockQueHead); readyQuePush(process);} else if (pro->priority > maxPriority) {// 更新阻塞队列里优先级最高的进程指针maxPriority = pro->priority; blockMaxProcess = pro;pro = pro->nxt;}}}// 查看阻塞队列里进程的信息void blockQueWalk(){printf("阻塞队列里的进程信息为:\"); queWalk(&blockQueHead);}// 初始化数据void initData(){// 初始化就绪队列和阻塞队列readyQueNum = blockQueNum = 0; readyMaxProcess = blockMaxProcess = NULL;readyQueHead.pre = readyQueHead.nxt = NULL; blockQueHead.pre = blockQueHead.nxt = NULL; // 初始化进程进入就绪队列int i, maxPriority = -1;for (i = 0; i < N; i ++){// 分配一个PCB的内存空间PCB *pro = (PCB *)malloc(sizeof(PCB));// 给当前的PCB赋值pro->id = id[i];pro->priority = priority[i];pro->cpuTime = cpuTime[i];pro->allTime = allTime[i];pro->blockTime = blockTime[i];pro->startBlock = startBlock[i];if (pro->allTime > 0) {// 插入到就绪队列中readyQuePush(pro);// 更新就绪队列优先级最高的进程指针if (pro->priority > maxPriority) {maxPriority = pro->priority; readyMaxProcess = pro;}}}}// 模拟cpu执行1个时间片的操作void cpuWord(PCB *cpuProcess){cpuProcess->priority -= 3;if (cpuProcess->priority < 0) {cpuProcess->priority = 0;}cpuProcess->cpuTime ++;cpuProcess->allTime --;// 显示正执行进程的信息:printf("CPU正执行的进程信息为:\");printf("id: %d, pri: %d, alltime: %d\", cpuProcess->id,cpuProcess->priority, cpuProcess->allTime);}int main(){int timeSlice = 0; // 模拟时间片int cpuBusy = 0; // 模拟cpu状态PCB *cpuProcess = NULL; // 当前在cpu执行的进程initData(); // 初始化// 模拟进程调度while (1){if (readyQueNum == 0 && blockQueNum == 0 && cpuBusy == 0) { // 就绪队列、阻塞队列和cpu无进程,退出break;}if (cpuBusy == 0) {// cpu空闲,选择一个进程进入cpuif (readyQueNum > 0) {// 选择绪队列优先级最高的进程cpuProcess = readyQuePop();} else {// 就绪队列没有进程,改为选择阻塞队列优先级最高的进程cpuProcess = blockQuePop();}cpuProcess->cpuTime = 0;cpuProcess->state = Run;cpuBusy = 1;cpuProcess->startBlock --;}timeSlice ++;printf("\第%d个时间片后:\", timeSlice);// 模拟cpu执行1个时间片的操作cpuWord(cpuProcess);if (cpuProcess->allTime == 0) {cpuProcess->state = Finish;// 释放已完成进程的PCBfree(cpuProcess);cpuBusy = 0;}// 更新就绪队列和阻塞队列里的进程信息blockQueUpdate();readyQueUpdate();// 查看就绪队列和阻塞队列的进程信息readyQueWalk();blockQueWalk();if ((cpuProcess -> startBlock) > 0) {blockQuePush(cpuProcess);cpuProcess = readyQuePop();}else {if (cpuBusy == 1 && readyQueNum > 0 && cpuProcess->priority < readyMaxPriority()){readyQuePush(cpuProcess);cpuProcess = readyQuePop();}}}printf("\模拟进程调度算法结束2145115 刘成路\");return 0;}【运行截图】实验2使用动态分区分配方式的模拟1、实验目的(1)了解动态分区分配方式中使用的数据结构和分配算法(2)加深对动态分区存储管理方式及其实现过程的理解。
自己动手写操作系统(从引导到启动保护模式)自由软件社区是一个充满自由和梦想的地方,在10余年的时间里它创造了一个又一个奇迹。
然而,这些奇迹的创造者不只是Stallman,也不只是Linus Torvalds,而是活跃在世界各地的不计其数的开发人员。
在使用各种功能强大的自由软件时,我总会对其开发者充满崇敬之情,期盼有朝一日自己也能成为他们中的一员。
很多对自由社区充满向往之情的人,虽然也想努力融身于其中,但又不知该怎么做。
那么,就请与我们一起从编写一个简单的操作系统开始吧!我们要做的事情有人可能担心自己既没有学过计算机原理,也没有学过操作系统原理,更不懂汇编语言,对C语言也一知半解,能写操作系统吗?答案是没问题。
我将带大家一步一步完成自己的操作系统。
当然如果学一学上述内容再好不过。
首先要明确处理器(也就是CPU)控制着计算机。
对PC而言,启动的时候,CPU都处在实模式状态,相当于只是一个Intel 8086处理器。
也就是说,即使你现在拥有一个奔腾处理器,它的功能也只能是8086级别。
从这一点上来讲,可以使用一些软件把处理器转换到著名的保护模式。
只有这样,我们才可以充分利用处理器的强大功能。
编写操作系统开始是对BIOS控制,取出存储在ROM里的程序。
BIOS是用来执行POST(Power On Self Test,自检)的。
自检是检查计算机的完整性(比如外设是否工作正常、键盘是否连接等)。
这一切完成以后,你就会听到PC喇叭发出一声清脆的响声。
如果一切正常,BIOS就会选择一个启动设备,并且读取该设备的第一扇区(即启动扇区),然后控制过程就会转移到指定位置。
启动设备可能是一个软盘、光盘、硬盘,或者其它所选择的设备。
在此我们把软盘作为启动设备。
如果我们已经在软盘的启动扇区里写了一些代码,这时它就被执行。
因此,我们的目的很明确,就是往软盘的启动扇区写一些程序。
首先使用8086汇编来写一个小程序,然后将其拷贝至软盘的启动扇区。
DIY:给单片机写个实时操作系统内核!为了进一步把单片机的潜能发挥到极限,我一直想写个程序把单片机的所有资源都用光,但是如果依照单道程序顺序执行的方式,很难把MCU 的CPU 时间都充分利用,比如使用软件延时函数实际上就是在无谓地消耗着CPU 的时间什么事情都不做,因为CPU 一直在循环等待着条件结束,这相当于函数被阻塞了。
为了更明显地验证这一点,你可以在WINDOWS 下打开VC6.0或其他的C 语言编译器,写段代码如下:#include void main(void){while(1) ;}意思是让CPU 不做事情在等待,你猜,这句代码会消耗掉多少CPU 时间?答案会根据不同机型而不同,如果是单核CPU 的话,这句话会消耗掉CPU 接近100%的时间!如果是双核CPU,则只消耗掉50%左右,因为这段代码只运行在其中一个核,另外一个核还可以做别的事情,截图如下:然后你可以测试下面这几句代码:#include#includevoid main(void){while(1)Sleep(100);}这段代码实际上也是什么都不做,它不断地调用Sleep()函数,让它延时100 毫秒再醒来,然后继续睡觉。
现在你可以再打开任务管理器看一下CPU 时间用了多少,答案是基本不用CPU 时间!!为什么同样地什么事情都不做,差别咋就这么大呢?这是因为使用了Sleep()这个函数是WINDOWS 操作系统为你提供的,调用Sleep()之后WINDOWS 操作系统自动把你这个程序挂起了(就是暂时扔到一边不管),然后让CPU 去执行其他程序,等到时间到了,操作系统再把这段程序恢复继续执行,这样的话CPU 就可以得到充分地利用了,也就是说你可以在一块CPU 里面同时执行多个任务而互不影响!(这里所说的同时并不是同时执行,CPU。
跟大神一起15分钟制作一个属于自己的Linux操作系统!计算机已成为现代人日常工作、学习和生活中必不可少的工具。
操作系统是计算机之魂,作为用户使用计算机的接口,它负责调度执行各个用户程序,使计算机完成特定的任务;作为计算机硬件资源的管理者,它负责协调计算机中各类设备高效地工作。
操作系统的重要性不言而喻,市面上主流的操作系统有Windows、Unix、Linux、Mac OS X。
Linux于1991年由芬兰大学生Linus开发,是一个类Unix的开源版操作系统,主要有以下几个特点:开放式操作系统Linux是一个免费软件,开发者可以自由安装并任意修改软件的源代码,相比Unix的命令行操作,Linux提供了窗口管理系统,相对容易操作,企业可以免费使用Linux,大大降低了成本预算。
强大的硬件支持Linux系统非常容易维护,用户可以集中更新操作系统和所有安装的软件,即安全又高效。
Linux能有效利用系统资源,允许用户针对特定的硬件要求进行安装,允许在旧计算机上安装Linux,从而有助于最佳地利用计算机硬件资源。
安全性高、稳定性强Linux系统下除非用户以root身份登录,否则程序无法更改系统设置和配置,很少出现因为用户误操作导致计算机无法启动的情形。
Linux下载的文件、恶意软件的权限将受到限制,能有效避免病毒的侵入,Windows系统中常见的勒索病毒、蠕虫病毒均无法在Linux下运行。
Linux非常稳定,不易崩溃,Linux能在几年后保持和第一次安装时一样的运行速度。
而Windows的话可能在运行半年后,速度就跟不上了。
Linux系统的成功归功于每个Linux爱好者的贡献,不管是在Linux内核还是开源软件等方面,都为我们后来人提供了一个良好的学习和研究环境。
下面我们就一起来做个小实验:通过裁剪现有Linux系统,根据自己的需要,打造一个属于自己的Linux小系统,让其能够具备Linux的一些常用小功能。
开源onlyofficewindows编译-概述说明以及解释1.引言1.1 概述本文将介绍如何在Windows系统下编译开源onlyofficewindows。
开源onlyofficewindows是一个功能强大的办公套件,它提供了文档处理、电子表格编辑、演示文稿制作等多种办公功能。
只需按照本文所述步骤进行编译,即可在Windows系统下获得自己定制的onlyofficewindows版本。
在正式介绍编译步骤之前,我们将先了解一下onlyofficewindows的基本概念和功能。
onlyofficewindows是一个开放源代码软件,它允许用户自由地使用、复制、编辑和分发。
它与微软Office套件相似,但更加灵活和易于定制。
通过编译onlyofficewindows,用户可以根据自己的需求添加或修改功能,使其更好地适应工作场景。
本文的结构如下:引言部分介绍了本文的目的和结构;正文部分将详细介绍编译onlyofficewindows的步骤,包括环境准备、代码获取、依赖库安装等;结论部分对本文进行总结,并探讨了开源onlyofficewindows 编译的意义和影响,最后展望了它在未来的发展。
通过阅读本文,读者将了解到如何在Windows系统上编译onlyofficewindows,并能够根据自己的需求进行定制。
在本文的指导下,读者可以轻松地获取并使用onlyofficewindows,享受到强大的办公功能。
同时,通过参与onlyofficewindows的开源社区,读者还能为软件的改进和完善贡献自己的力量。
只要按照本文所述步骤,相信读者可以成功地编译onlyofficewindows,并将其应用于自己的工作和学习中。
1.2 文章结构在文章结构部分,我们将介绍本文的组织结构以及各个章节的内容概要。
通过明确的文章结构,读者可以更好地理解文章的主要内容和阐述思路。
本文的结构分为以下几个部分:1. 引言:在这一部分中,我们将对文章所要讨论的主题进行概述和介绍。
Verum ipsum factum.──Giambattista Vico1马上动手写一个最小的“操作系统”虽说万事开头难,但有时也未必。
比如说,写一个有实用价值的操作系统是一项艰巨的工作,但一个最小的操作系统或许很容易就实现了。
现在我们就来实现一个小得无法再小的“操作系统”,建议你跟随书中的介绍一起动手来做,你会发现不但很容易,而且很有趣。
1.1准备工作对于写程序,准备工作无非就是硬件和软件两方面,我们来看一下:1.硬件•一台计算机(Linux操作系统1或Windows操作系统均可)•一张空白软盘2.软件•汇编编译器NASMNASM最新版本可以从其官方网站获得2。
此刻你可能会有疑问:这么多汇编编译器中,为什么选择NASM?对于这一点本书后面会有解释。
•软盘绝对扇区读写工具在Linux下可使用dd命令,在Windows下则需要额外下载一个工具比如rawrite3或者图形界面的rawwritewin4。
当然如果你愿意,也可以自己动手写一个“能用就好”的工具,并不是很复杂5。
1实际上Linux并非一种操作系统,而仅仅是操作系统的内核。
在这里比较准确的说法是GNU/ Linux,本书提到的Linux泛指所有以Linux为内核的GNU/Linux操作系统。
GNU经常被人们遗忘,但它的贡献无论怎样夸大都不过分,这不仅仅是因为在你所使用的GNU/Linux中,GNU软件的代码量是Linux内核的十倍,更加因为,如果没有以Richard Stallman为首的GNU项目倡导自由软件文化并为之付出艰辛努力,如今你我可能根本没有自由软件可用。
本书将GNU/Linux简化为Linux,仅仅是为表达方便,绝不是因为GNU这一字眼可有可无。
2NASM的官方网站位于/projects/nasm。
3rawrite可以在许多地方找到,比如/debian/tools/。
4下载地址为/rawwrite。
5我们不需要太强大的软盘读写工具,只要能将512字节的数据写入软盘的第一个扇区就足够了。