使用开源软件-自己动手写操作系统WriteOS_图文(精)
写一个简易嵌入式操作系统

写一个简易嵌入式操作系统在了解了操作系统的原理和工作后,我们可以自己写一个简易的嵌入式操作系统,下面由店铺为大家整理了写一个简易嵌入式操作系统的相关知识,希望对大家有帮助!写一个简易嵌入式操作系统概述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.2 操作系统的发展过程
1.2.1 无操作系统时的计算机系统 1.2.2 单道批处理系统(simple batch processing) 1.2.3 多道批处理系统(multiprogramming system) 1.2.4 分时系统(time-sharing system) 1.2.5 实时系统(real-time system)
– 通常按时间片(time slice)分配:各个程序在CPU上执行的 轮换时间。
20
分时的定义
把计算机的系统资源(尤其是CPU时间)进行时 间上的分割,每个时间段称为一个时间片(time slice),每个用户依次轮流使用时间片。
• 抢先式和非抢先式(preemptive & nonpreemptive):出让CPU是OS强迫或程序 主动
– CPU等待用户:计算前,手工装入纸带或卡片;计 算完成后,手工卸取纸带或卡片;CPU利用率低;
9
• 主要矛盾
– 计算机处理能力的提高,手工操作的低效率 (造成浪费);
– 用户独占全机的所有资源;
• 提高效率的途径
– 专门的操作员,批处理
10
➢ 联机输入输出方式 (On-Line I/O)
➢ 脱机输入输出方式 (Off-Line I/O) 外围机控制I/O, 减少CPU空闲时间 高速磁带、磁盘
• 缺点:
– 用户交互性差:整个作业完成后或中间出错时, 才与用户交互,不利于调试和修改;
– 作业平均周转时间长:短作业的周转时间显著增 长;
18
多道批处理系统的问题
• 处理机 • 内存 • I/O设备 • 文件 • 作业 各种类型
19
1.2.4 分时系统
70年代中期至今,用户的需求
自己动手写CPUOpenMIPS教学版讲解主要内容

指令wishbone接口 OpenMIPS 数据wishbone接口
iwishbone
dwishbone
m0
WB_CONMAX
s0
s1
s2
s3
SDRAM Controller
UART Controller
GPIO Controller
FLASH Controller
•《自己动手写CPU》OpenMIPS教 学版讲解主要内容
四 OpenMIPS教学版的文件组织
asm_test
包括所有的测试例程,其组织方式是参照《10天实现 处理器——OpenMIPS成长记》一文,按照“天”来组织, 比如Day2文件夹中存放的是《10天实现处理器—— OpenMIPS成长记》一文中第二天对应的测试例程,当 然所有的测试例程都可以在最终的OpenMIPS中进行测 试
•《自己动手写CPU》OpenMIPS教 学版讲解主要内容
四 OpenMIPS教学版的文件组织
rtl
所有OpenMIPS的源代码文件在该文件夹下,包括
流水线文件iu.vhd 除法模块div.vhd 寄存器文件Reg 顶层文件OpenMIPS.vhd 宏定义文件stdlib.vhd
•《自己动手写CPU》OpenMIPS教 学版讲解主要内容
一 OpenMIPS项目简介
OpenMIPS是采用具有哈佛结构的32位标量处理器,兼容 MIPS32体系结构,这样可以使用现有的MIPS编译环境。
具有以下特点:
五级整数流水线,分别是:取指、译码、执行、访存、 回写
哈佛结构,分开的指令、数据接口
32个32位整数寄存器
大端模式
向量化异常处理,支持精确异常处理
•《自己动手写CPU》OpenMIPS教 学版讲解主要内容
OS操作系统课程实验指导书附运行截图

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-给单片机写个实时操作系统内核!

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操作系统

跟大神一起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编译-概述说明以及解释

开源onlyofficewindows编译-概述说明以及解释1.引言1.1 概述本文将介绍如何在Windows系统下编译开源onlyofficewindows。
开源onlyofficewindows是一个功能强大的办公套件,它提供了文档处理、电子表格编辑、演示文稿制作等多种办公功能。
只需按照本文所述步骤进行编译,即可在Windows系统下获得自己定制的onlyofficewindows版本。
在正式介绍编译步骤之前,我们将先了解一下onlyofficewindows的基本概念和功能。
onlyofficewindows是一个开放源代码软件,它允许用户自由地使用、复制、编辑和分发。
它与微软Office套件相似,但更加灵活和易于定制。
通过编译onlyofficewindows,用户可以根据自己的需求添加或修改功能,使其更好地适应工作场景。
本文的结构如下:引言部分介绍了本文的目的和结构;正文部分将详细介绍编译onlyofficewindows的步骤,包括环境准备、代码获取、依赖库安装等;结论部分对本文进行总结,并探讨了开源onlyofficewindows 编译的意义和影响,最后展望了它在未来的发展。
通过阅读本文,读者将了解到如何在Windows系统上编译onlyofficewindows,并能够根据自己的需求进行定制。
在本文的指导下,读者可以轻松地获取并使用onlyofficewindows,享受到强大的办公功能。
同时,通过参与onlyofficewindows的开源社区,读者还能为软件的改进和完善贡献自己的力量。
只要按照本文所述步骤,相信读者可以成功地编译onlyofficewindows,并将其应用于自己的工作和学习中。
1.2 文章结构在文章结构部分,我们将介绍本文的组织结构以及各个章节的内容概要。
通过明确的文章结构,读者可以更好地理解文章的主要内容和阐述思路。
本文的结构分为以下几个部分:1. 引言:在这一部分中,我们将对文章所要讨论的主题进行概述和介绍。