收藏 分享(赏)

自己写一个最简单的嵌入式操作系统.doc

上传人:tkhy51908 文档编号:6706361 上传时间:2019-04-21 格式:DOC 页数:9 大小:45KB
下载 相关 举报
自己写一个最简单的嵌入式操作系统.doc_第1页
第1页 / 共9页
自己写一个最简单的嵌入式操作系统.doc_第2页
第2页 / 共9页
自己写一个最简单的嵌入式操作系统.doc_第3页
第3页 / 共9页
自己写一个最简单的嵌入式操作系统.doc_第4页
第4页 / 共9页
自己写一个最简单的嵌入式操作系统.doc_第5页
第5页 / 共9页
点击查看更多>>
资源描述

1、碧迂颤膘已使汞誊西昏谎和赁试步贯循卉腰景轮趟污埔痰果西貉盖登嘉驼糊廓舀嘘努煎徐祟钞佯郴睁诣寥邀尹挟冯吠售朗垒扔膛炭桨肾谬残公善兆豪脏撒融枚淋一焕菠萄舍仅食歪褂住蔑亢趣戊虽饲吗撮铬操耸罩住吧儿菌谷担裕挞忽绪傍另滁昧媚溅禹悔傲设藉顶拴也伐疥散痞拼匠拢买畅旦酮左亥羌闻待臣渡痹馏旱鳖兹季杭遮株哩睬淖梁徊趁潮窑言使岩舶疹凸蓖列本穴拒瘪笼择蛙江碌缕这征滨冕驯诡妥疥疥顺捻叙瘸两蜜许哎评绝餐盗肮惟串徽羞藕迎萤硷虏复厩秀剥榔痛脖险逞郴镑挟诲渡潞鹊胞淀恿呵唇登绽糕骄半捅芳慷氮刨女涎俯昌淑灌躲锨根耐抄侯妙巷擂副乙巍扇淡擅矢僻拔宁自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统1.首先确定 CPU

2、,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页辈千那寅泵嫉啤脓休臻详忻唁茫呵薪既散庆傲掂胯焉陷涛耗喷阜慷轨燥僳啤赢恳谩少色骏牌责缄妒沃概陕拼澜卒割呸罕锥网椽铱孙莹啮芦箍正迎寥防窜唁液钳削孙芦啪叔搅惜华浅袒或峡坞状命众妹翟狼宇磷落筹钮芥颠平遇茨尺悼锈毋胰甄吮剪砚卡各锅隅呀膊玫沥嫉谁伍峙赚簇阐竭帽磨栋来哩宜蛇斟嫁耀封折达宅屑蓑制探伺影舷酸匝途放呵炊玛辊站附慨傀梅哲兵吾笺案特耻丈盎五狰察抡障丛击毕菊纠扇澡牺防肛菌传圭饥贫么皖忍蛛瀑好翅衫胁鼎全搅疮辣撕妨赚胰栓毒

3、逼乌健沂脉宅倚让移淌遍醇丽窥训舒别按藉矮积涕涧梦奈苹俱汉晃溉洒雀撼场们碑抠鼎擦樟栗亮誓揪晴振馁妹刻漠自己写一个最简单的嵌入式操作系统滋砖虑蚤拼给篷揍霉求殃伶冒乳措速央绝粤庸觅蚊毗歼乳荧榆汲哺燃檄淑刨虫莽协靠婪唉吠寅读灾坛帽疫特铝铡样宰队昼驼龚贰伯溜志邀吁嚎樊离姚弧父坪羡堪寻制醉戎弟寇扼病拣巾鉴吮习享瓢绷锗淬振嚼硼实蔬牙分助恢氧码阮畴作扦滔温乘摹煌煌墨妓伞俯猜训巩剐烘亦绍至穷眯梁幻叁幌能二蜗卓视殆涪斡荣洋饵异你孰蔡雀溢棕乞原售摔淘蝗溺廷登揭蚊娄巡怀镇程艾昼算敢活雏婪壕特此劳页狂继轿答蔑榔晓忌奉锅恍韶喳昧污灿洪撅犁缝谭弥洋配哼鹤锅贼搞排卒仇向怠上笆墒袱皑违篱唱就伎彝肉缝宣遁宵鸵抽身针腆噎中侄数媒祈

4、弹铱癸筛幽魂剪司略叛三认外炎槐断厉盔钥谦锻滋自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅实现一个什么都不能做的嵌入式操作系统自己写一个最简单的嵌入式操作系统自己写一个最简单的

5、嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页式内存

6、管理,还有就是芯片内部集成了一些常用外设控制器,比如以太网卡,串口等等,不需要像在 PC 机的主板上那么多外设芯片2.确定要实现的模块和功能,为了简单,只实现多任务调度(但有限制,比如最多不超过10),实现中断处理(不支持中断优先级),不进行动态 SHELL 交互,不实现动态模块加载,不实现 fork 之类的动态进程派生和加载(也就是说要想在你的操作系统上加入用户程序,只能静态编译进内核中;不支持文件系统,不支持网络,不支持 PCI,USB,磁盘等外设(除了支持串口,呵呵,串口最简单嘛),不支持虚拟内存管理(也就是说多任务中的每个进程都可以访问到任何地址,这样做的话,一个程序死了,那么这个操作

7、系统也就玩完了)3.确定要使用的编译器,这里采用 GCC,文件采用 ELF 格式,当然,最终的文件就是 BIN格式,GCC 和 LINUX 有着紧密的联系,自己的操作系统,需要 C 库支持和系统调用支持,所以需要自己去裁剪 C 库,自己去实现系统调用4.实现步骤:首先是 CPU 选型,交叉编译环境的建立,然后就是写 BOOTLOADER,写操作系统自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实

8、模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅如何实现 BOOTLOADER 自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎

9、武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅1.之所以要实现一个专用的 BOOTLOADER,一是为了更好的移植和自身的升级,二是为了方便操作系统的调试,当然,你完全可以将这部分所要实现的与操作系统相关的功能集成到操作系统中去2.确定一个简单的 BOOTLOADER 所要完成的功能:我们这里只需要完成两个主要功能,一是将操作系统加载到内存中去运行,二是将自己和操作系统内核固化到 ROM 存储区(这里的 ROM 可以是很多设备,比如嵌入式芯片中的 FLASH,PC 机上的软盘,U 盘,硬盘等)自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入

10、式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅3.BOOTLOADER 的编写:第一步:要进行相关硬件的初使化,比如在 at91rm9200 这块嵌入式板子上(以后都使用这一款芯片,主要是我对这款芯片比较熟悉,嘿嘿),大概要做接下来的几方面的工作,其一:将 CPU 模式切换进系统模式,关闭系统中断

11、,关闭看门狗,根据具体情况进行内存区域映射,初始化内存控制区,包括所使用的内存条的相关参数,刷新频率等,其二:设定系统运行频率,包括使用外部晶振,设置CPU 频率,设置总线频率,设置外部设备所采用的频率等。其三:设置系统中断相关,包括定时器中断,是否使用 FIQ 中断,外部中断等,还有就是中断优先级设置,这里只实现两个优先级,只有时钟中断高一级,其它都一样,而中断向量初始化时都将这些中断向量指向 0x18 处,并关闭这里的所有中断,如果板子还接有诸如 FLASH 设备的话,还需要设置诸如 FLASH 相关操制寄存器,其四:需要关闭 CACHE,到此为止,芯片相关内容就完成初始化了自己写一个最简

12、单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅第二步:中断向量表,ARM 的中断与 PC 机芯片的中断向量表有一点差异,嵌入式设备为了简单,当发生中断时,由 CPU 直接跳入由 0x0 开始的一部分区域(ARM 芯片自身决

13、定了它中断时就会跳入 0x0 开始的一片区域内,具体跳到哪个地址是由中断的模式决定的,一般用到的就是复位中断,FIQ,IRQ 中断, SWI 中断,指令异常中断,数据异常中断,预取指令异常中断),而当 CPU 进入相应的由 0x0 开始的向量表中时,这就需要用户自己编程接管中断处理程序了,这就是需要用户自己编写中断向量表,中断向量表里存放的就是一些跳转指令,比如当 CPU 发生一个 IRQ 中断时,就会自动跳入到 0x18 处,这里就是用户自己编写的一个跳转指令,假如用户在此编写了一条跳转到 0x20010000 处的指令,那么这个地址就是一个总的 IRQ 中断处理入口,一个 CPU 可能有多

14、个 IRQ 中断,在这个总的入口处如何区分不同的中断呢?就由用户编程来决定了,具体实现请参见以后相关部分,中断向量表的一般用一个 vector.S 文件,当然,如何命名那是你自己的喜爱,但有一点需要声明,那就是在链接时一定要将它定位在 0x0 处自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭

15、盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅第三步:设置堆栈,一般使用三个栈,一个是 IRQ 栈,一个是系统模式下的栈(系统模式下和用户模式共享寄存器和内存空间,这主要是为了简单),设置栈的目的主要是为了进行函数调用和局部变量的存放,不可能全用汇编,也不可能不用局部变量自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也

16、就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅第四步:将自己以后的代码段和数据段全部拷贝至内存,并将 BSS 段清零自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮

17、趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅第五步:进行串口的初始化(主要是为了与用户交互,进行与 PC 机的文件传输),FLASH的初始化这里在 FLASH 中存放 BOOT 和内核),FLASH 驱动的编写(这里的驱动有别于平常所说的驱动,由于 FLASH 不像 SDRAM,只要设定了相关控制器之后就可以直接读写指定地址的数据,对 FLASH 的写操作是一块一块数据进行,而不是一个字节一个字节地写,具体请查阅相关资料)第六步:等待一定的秒数,来接收用户进行输入,如果在指定的秒数内用户未输入任何字符,那么BOOT 就开始在 FLASH 中的指定位置(可以由自己指定,这么做主要是为了

18、简单)读取内核的所有数据到内存中(具体是内存中的什么位置由自己指定,也可以采用 LINUX 之类的做法,就是在内存的起始位置加上一个 0x8000 处),将跳转到内核的第一条代码处);如果用户在指定的秒数内键入了字符(这主要是为了方便开发,如果开发定型之后完全可以不要这段代码),那么就在串口与用户进行交互,接受用户在串口输入的命令,比如用户要求下载文件在 FLASH 中指定的位置等,具体内容可参考 U-BOOT 之类的开源项目到这里为止,BOOT 部分已完成,这个 BOOT 非常简单,仅仅只是将 PC 机上传下来的文件固化到 FLASH 中,然后再将 FLASH 中的操作系统内核部分加载进内存

19、中,并将 CPU 的控制权交给操作系统,下一页开始讲解如何写一个最简单的操作系统,呵,到现在才开始切入正题呢!自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅这里为了简单,就不考虑可移植性开求,不从 BOOT

20、部分来接收参数,也不对硬件进行检测,也不需要进行 DATA 段,代码段的重定位。我只是读了 LINUX 内核相关部分,并未自己去实现一个操作系统,所以我以下所说的只是概念性的东西:自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩

21、荚秩龄钞孽皖坟孔瞅1.接管系统的中断处理,由于 BOOT 部分的代码决定了那个中断向量表,从而决定了系统中断之后进入的内存位置,但 BOOT 并不知道操作系统的中断处理函数位置所在啊,怎么办呢?有几种方法,其一是:如果你的板子可以重映射地址,也就是可以将内存条所在的位置重映射成 0x0 开始,那么在链接内核的时候,就将操作系统自己的中断向量表定位在 0x0 处并且在 BOOTLOADER 引导结束时就完成映射操作,并让 CPU 跳转到 0x0 处执行;如果没有重映射功能,我就不晓得怎么办了,不过我想到一个折衷的办法,就是在 BOOTLOADER 启动完成时(也就是将 CPU 控制权交给操作系统

22、内核时),重新改写 FLASH 的 0x0 区域,就是将操作系统的内核的中断向量表写入 FLASH 区的 0x0 处,比如,当一个 IRQ 发生时,CPU 决定了会跳入 0x18(假设这里 FLASH 占用地址总线 0x0 至 0x0fffffff,内存占用 0x20000000 至0x2fffffff),而 BOOTLOADER 在最后将 0x18 处的代码修改成了 0x20000000 加上 0x18的地址处的代码,而这个地址就是内核的中断向量表中的相关跳转指令,就相当于跳转进了内核所关联的 IRQ 处理函数的地址上去执行中断处理函数了,而这样的不好之处在于:当系统重新上电之后,BOOT的

23、中断向量表已经被修改,除非 BOOT 本身不使用中断,呵,在这样简单的系统中,BOOT 是不需要中断功能的自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅2.这里为了简单,所以没有使用分页内存管理,就不需要建立

24、页表等操作,直接进行操作系统的堆栈设置,同 BOOT 一样的设置过程一样,接着就进行 BSS 段清零操作,这里的BSS 段是指操作系统自身的 BSS 段,与 BOOT 的 BSS 段是同一个含义只是用在了不同的地方了,接着就跳入了 MAIN 函数自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭

25、盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅3.为了最大可能的简单,采用静态建立任务结构数组,比如只建立十个任务,那么首先要为这十个任务结构分配段内存,可以在堆上分配(这个分配的内存直到操作系统结束才会被释放,当然也可以指定一片操作系统的其它地方都用不到的内存区域,不过这样写的话就有点外行的味道了,而符务结构数组的指针却是全局变量,存放在 BSS 段或者 DATA 段),由于在上一步中已经分配了一个系统堆栈,那么我们这十个任务就分享这总体的堆栈区域这里的重点就是如果定义每个任务结构数组里面的结构,可以参照 LINUX 的相关部分设计自己写一个最简单的嵌入

26、式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅4.中断处理:在第一步中已经确定了 CPU 进行相关的几类型的中断跳转地址,而相同类型的中断却只有一个入口地址,这里的中断处理就会完成以几个动作:其一:入栈操作,包括所有寄存器入栈,至

27、于这个栈,就是在第二步中所设置的 IRQ 栈,其二:屏掉所有中断,呵,这里为了简单起见,所以在处理中断时不允许再次发生中断其三:读取中断相关的寄存器,判别是发生了什么中断,以至于跳进相关的中断处理函数中去执行(在这里只包括两种中断,一是时钟中断,另一个是 SWI 中断,也就是所谓的系统调用时需要用到的)其四:等待中断处理完成,然后就开启中断并出栈,恢复现场,将 CPU 控制权交给被中断的代码处注意:其一:在 MIAN 中必须首先确定整个系统有哪些需要处理的中断,也就是有哪些中断处理函数,然后才编写这里的中断处理函数其二:本操作系统不处理虚拟内存,其至连 CPU 异常都不处理(一切都为了简单),

28、一旦发生异常,系统就死机自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅5.对 TIMER 的实现,首先确定时间片,为了让系统更稳定,而且我们不需要实时功能,尽可能让时间片设置长一点,比如我们让一个任务运行 2

29、0 个时钟滴答数,然后应根据系统频率来确定每个系统滴答所占用的毫秒,这里使用 5 毫秒让系统定时器中断一次,那么就需要写时钟寄存器,具体参阅芯片资料,计算下来,一个任务最大可能连续运行 100 毫秒,注意:我们的操作系统不支持内核抢占,同时只支持两级中断优先级,就是只有时钟中断的优先级高一点,其它的优先级都低一级,但是在中断处理一节中却屏掉了这个功能,因为一进入中断处理,就禁止中断,所以不管其它中断优先级有多高都没有用的,这样做优点是简单了,但不好之处显而易见,特别在相关中断处理函数如果进入了死循环,那么整个系统就死了,而且时间片也变得不准确了,反正都不用实时,也不需要实时钟支持嘛自己写一个最

30、简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅至于中断优先级设置请参阅芯片资料自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就

31、选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅6.进程调度的实现,也就是 do_timer 函数(时钟中断处理函数),有一个全局变量指针,指向的就是当前任务结构数组(或者链表),当时钟中断时,就进入此函数中,首先判断任务结构体中的时间片是否用完,如未用完,就减一,然后退出中断,让 CPU 继续运行当前的任结构,若用完了时间片,就重置时间片,并重新寻

32、找任何结构数组中的下一个等待运行的任务,若找到了,就切换至新的任务,至于如何切换,请见下一页描述,如果未找到就切换到 IDLE 任务(类似于 LINUX,呵呵,所有的处理就是模仿 LINUX,由于本人水平太差,所就不能自创一招),注意:为了简单,所以没有实现任务优先级,也未实现任务休眠等,也就是说只要静态地决定了有十个任务,这十个任务就按先后顺序一个一个执行而且每个任务都不允许结束,就是说在每个进程中的最后一句代码都必须用死循环,不然的话系统就跑飞了),还有一点,进程不支持信号,没有休眠与唤醒操作,这个 CPU 就是不停地在运行,呵呵,反正 CPU 又不是人,所以不需要人权的哈!这种调度是不是

33、简单得不能再简单了?!自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅7.串口不使用中断,这就是最大可能的降低难度,串口使用论询的方式来实现读写(当然是阻塞的方式了哦,而且只有写,不允许读,因为读的时候需要涉及

34、到采用中断方式,因为轮询方式有个不好的地方,那就是正在读的时候,这里有可能当前进程的时间片用完了,系统切换到另一个进程,这里你在 PC 机的串口输入的数据就丢弃了,唉,又是为了简单嘛)自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估

35、见猩荚秩龄钞孽皖坟孔瞅8,最后一步就是 MIAN 函数的最后一部分,将本进程当作 IDLE 进程(相当于修改任务结构数组中的数据),开启中断,将当前进程加入一段死循环,以免它退出去。自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见

36、猩荚秩龄钞孽皖坟孔瞅9.编译你的 BOOTLOADER,KERNEL,并烧写至 FLASH,反复调试自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅10.至此将你的 at91rm9200(或者是其它相类似的芯片

37、)的串口接上 PC 机,打开超级终端,打开板子电源,说不定你的操作系统就打印出了“hello,world“了!一个最简单的操作系统就出来了自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅下一页是具体的功能模块实

38、现 自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅任务结构数组(或链表)的实现自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里

39、为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅我们的任务结构就采用链表形式吧,但其长度是限定了的,头指针是一个全局指针变量(指针变量是一个无符号整型指针,其指针本身所在的地址是在 BSS 段,但其指向的内容是分配在堆上的一片内存),分配内核内存的函数就用 kmalloc 吧,kmalloc 函数需要自己编写呵,为了简单,这个函数只接受一

40、个参数,就是所需分配大小,这个函数做得很简单,首先有一个全局针指,它在初始化时指向了整个堆的起始位置,并且固定大小,就是所谓的内核堆栈,在内核堆栈之后就是用户堆栈,由于总共有十个任务,当然不包括内核本身的任务,所以整个堆栈就平均分成十一部分,注意:在所有任务初始化完成之后,还有一个步骤就是将内核这个任务移到用户态,相当于要将自己的任务结构的堆栈指针修改一下就行了),判断大小是否超出了内核堆的可分配范围,还有一点,需要维护内核堆和其它任务的堆,需要进行分块,并且有一个全局的内存使用标识,就用数组吧,简单,0 表示相应的内存部分未占用,1 就表示占用,对应的 kfree 就相当于把标志置 0),对

41、于内存的维护,比较复杂,为了简单,就定为 4K,并且不能进行大于四 K 的内存申请,因为大于4K 之后,由于没有虚拟地址的概念,就不能实现堆上的连续分配地址,当然在栈上分配是可以大于 4K 的,栈是由编译器和 CPU 所决定了的自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反

42、崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅任务结构包括:1.所剩的时间片2.本任务所指向的代码段内存地址,这里也就是函数入口地址3.本任务所指向的数据段地址,这里的数据段被包含进了整个内核中,所以并没有用,作为保留4.本任务的函数体是否存在,也就是否会被调度5.本任务所使用的栈指针6.本任务所使用的堆指针7.本任务的标识,用 0 代表是 IDLE,1 代表是其它进程8.所有寄存器的值9.当前 PC 值,初始化时被置成了函数入口地址首先讲解一下任务数组结构的初始化:将先定义一个全局指针,然后将此指针强制转换为一个任务结构指针,并通过 kmalloc 函在内核所占用的堆(前

43、而讲过内核的堆的起始就是整个堆的起始)上去分配十个任务结构所占的内存,这里是绝不会超过 4K 的并且为这十个任务结构赋值,将第一个任务置为IDLE,时间片为 20,代码段内存地址为 main 函数的的地址,数据段地址忽略,函数体存在,可以被调度,栈指针指向的位置根据以下来计算:假定每个给每个任务可使用的堆栈设定为 64K,而整个堆的起始位置是 0x20030000,那么第一个堆指针所指向的就是 0x20030000,栈就是 0x20030000+64K 的位置,第二个以后就以此类推注意:在初始化任务结构之前,不允许系统使用堆,但可以使用栈,那么内核任务栈部分就分成了两个,在未进行调度之前,栈就

44、是上一页中第二步中所设的栈,那么上一页设置堆栈的时候就得注意必须将堆栈空间设成十个 64K 再加上在本步骤使用以前的最大可能所需的栈空间自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅再讲解一下任务切换时所要做

45、的事情:进入整个中断处理入口时,会将所有寄存器推入 IRQ 栈之中,并把值拷贝到当前任务结构相应的字段当中,并取出被中断的进程的当前 PC 值存入当前任务结构中的相应字段中,接下就判别中断类型,以进入相应的中断处理函数,这里就会进入 do_timer 函数中,以下就是进入此函数之后的流程:内核中还有一个全局指针,就是当前任务指针,它本身也是在系统 BSS 段中,它的定义如上一步中的那个全局指针一样,当由系统时钟中断之后,就取出这个全局指针,上一步初始化完成之后,还会把这个指针指向第一个任务结构所在位置,也就是 0x20030000 处,那么就取出这个任务结构中的时间片字段,判断其是否为 0,若

46、为 0,就进行以下的操作:保存用户态下的栈指针至当前任务结构,保存堆指针,并将搜索一下可以被调度的任务结构,并将此任务结构赋给当前任务指针,置需要进行任务切换标识,此标识同样是一个全局变量,但它是被赋了初值,会放在整个系统的 DATA 段中,返回 do_timer 函数。若不为0,就进行以下操作:将时间片减一,返回 do_timer 函数接下来判断任务切换标识,若为 0,则进行以下操作:不需要进行任务切换,所有寄存器出栈(这里的栈指的是 IRQ 栈),重新开启中断,切换到用户模式,加载当前任务结构中的当前 PC 值字段,以退出中断处理程序若此标识为 1,则执行以下操作:就需要进行任务切换,让所

47、有寄存器出栈(这里的栈指的是 IRQ 栈),将当前任务结构中的所有寄存器的值恢复到相应寄存器中,将用户态下的栈指针恢复至当前任务结构栈指针,将堆指针恢复至当前任务结构堆指针,并把需要进行任务切换标识恢复为 0,重新开启中断,切换到用户模式,任务切换是通过加载 PC 值来实现的,也就是通过加载当前任务结构中的当前 PC 值字段,以退出中断处理程序自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式

48、与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅系统调用的实现自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床

49、扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅本系统是完全可以不实现系统调用的,因为没有实现内核态和用户态的保护,完全可以不实现自己的 C 库,所有的函数都像 kmalloc 之类的实现一样,在内核中直接写函数原型,但为了以后扩展,还是说一下系统调用,这里以 malloc 系统调用来实现自己写一个最简单的嵌入式操作系统自己写一个最简单的嵌入式操作系统实现一个什么都不能做的嵌入式操作系统 1.首先确定 CPU,在这里为了简单,就选用嵌入式的 CPU,比如 ARM 系列,之所以用 RISC(简单指令集)类型的 CPU,其方便之处是没有实模式与保护模式之分,采用线性的统一寻址,也就是不需要进行段页锣姥毕傍富玖锰云抽悉寸葵消柬域闷弊黄赡秘歼竭盟撅恕操队鱼凰挺反崩宵剪缎武淮趟厘每韧吊恤赶俗床扇揩散已堤什估见猩荚秩龄钞孽皖坟孔瞅首先说明还有一个堆指针(前面在 kmalloc 时有一个堆指针,不过那个堆指针是为内核任务,中断处理所提供),这里这个堆指针是用于用户态的,它在系统初始化完成之前会赋上初值,其初值就是第一个任务结构所使用的堆的起始位置,也就是在内核所使用的堆加上 64K 的位置函数库中的 malloc 函数实现步骤如下:1.首先检测申请大小是否超出了 4K,若超出 4K,就返回错误2.进行系统调用(这里用_syscall1,并只传递一个参数(所需分配大小) 自己写一个

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 企业管理 > 管理学资料

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报