OS实现过程之Xtensa DC_D_233L

来源:互联网 发布:ubuntu安装firefox 编辑:程序博客网 时间:2024/05/22 23:53

写这篇文章的目的,主要是给那些新手看的,以满足他们的好奇心,让他们知道写OS会经历哪些过程。至于老手,都已经会写OS了,本文就没啥吸引力了。大家瞅瞅就行 。
1. 背景

有现成的bootloader、OS、芯片驱动、产品,CPU是Xtensa DC_D_233L。我们有其它部分的源代码,但OS是其它公司开发的,源码没有。

2. 设计目的

 在DC_D_233L 上运行的多线程操作系统。当前已有bootloader、CPU内部模块的驱动、官方GDB(不是linux中的GDB)等。

3. 实现步骤

(1)了解OS的结构;(2)查阅xtensa官方手册,了解芯片工作机制;(3)分析xtensa官方手册,提取出与OS相关的内容;(4)在纸上或电子文档中写下OS运行过程;(5)检查第(4)步的结果是否可行;;(6)编写OS代码,在电路板或仿真器上运行。

4.了解OS的结构

多线程OS的结构如下:(1)内存管理;(2)中断和异常处理;(3)线程调度;(4)系统调用;(5)文件系统(暂不实现);(6)兼容现有OS接口;多线程和多进程非常不同,多进程的文件系统是一大难点。多线程可就简单好多好多了,不用实现文件系统、代码常驻在内存中,这些都省好多事情。

5 查阅xtensa官方手册,了解芯片工作机制

芯片工作机制,包含如下内容:(1)CPU寻址过程;(2)发生中断时,硬件对中断的处理过程;上述2项内容是必须要了解的。第(1)步牵涉到CPU寻址硬件的工作流程,它会使用很多硬件结构和寄存器,它们可能会成为单个线程正常工作的一部分。第(2)步是为了线程切换做准备,因为10ms定时中断一定会使用这种机制进行线程切换。xtensa官方文档很多,为了实现上述2个目的,需要做如下2步:(1)浏览多个官方文档,找出与上述目的相关的所有文档;(2)对第(1)步的文档进行重要性排序,先看最重要的文档;本人第(1)步唯一找到的文档是微处理器编程手册,紧接着就开始看了。坦白说,这份文档真不错,感觉是手把手教人如何写OS,就连代码设计的背后考虑,它都进行了详细说明。文档信息整理,这是本人现在面对的问题。这个编程手册才200多页,瞅瞅ARM的那些手册,动辄上千页,整理信息是很容易迷路和失去耐心的。抱着目的看文档,能有效解决这个问题。写OS是个艰苦的活,整理文档信息是第一步,是不可避免的。

6. 分析xtensa官方手册,提取出与OS相关的内容

这次的目的性非常强。首先是对总结内容的排序:(1)先做内存管理的总结。内存管理肯定排在线程调度、系统调用前面,但是如果内存访问时没有触发异常或引发中断,则中断和异常处理是不必要的;内存管理却是时时都要用的。因此先做内存管理的总结,直到其完成为止。(2)再做中断和异常处理的总结。中断和异常处理肯定排在系统调用前面,另外在中断里可以进行线程调度(如10ms定时中断),因此再做中断和异常处理的总结。(3)再做线程调度的总结。它肯定要排在系统调用的前面。(4)再做系统调用的总结。(5)兼容现有OS接口:这个暂时不考虑,等到写出了OS,再做兼容不迟。在总结过程中,我先在纸质笔记本上记录心中所想(纸张比电子文档更让人能思考),后来发现图表在纸质笔记本上写着不方便(经常删除内容),因此后来改用电子文档做总结思考。但是,总是在思考成熟后,比如在提出一个疑问并获得答案后,才会在电子文档上做记录。例如,内存寻址步骤是什么?每步做了什么事?内存寻址的参与对象有哪些?这步做下来,A3纸用了29页。

7. 设计的细化
7.1 设计目标

分2步实现我们的最终目标:(1)写出最小的、能正常工作的OS,OS越简单越好,效率高低无所谓;(2)在第一步的基础上,逐步扩充功能;采用上述策略的原因是:(1)一次性实现所有功能,难度大;(2)某些功能并非必需;(3)一次性实现所有功能,不利于程序调试;(4)一次性实现所有功能,不能增加软件实现者的信心(非常重要!);上述方案可以让我们一开始,就集中注意力在验证文档总结是否正确、核心模块如何实现上,非核心模块先不做。这种方式可以让我们在初期就发现设计缺陷。当然了,我们的设计仍是大而全的,只是先实现核心模块而已。

7.2 内存管理的设计

内存管理的目标:(1)不启用MMU(也就是说,不使用虚拟地址到物理地址的转换硬件---非常重大的设计决策);(2)可以随时分配内存、随时释放内存;(3)内存大小的改变不影响程序的改动;因为上述目标,使得内存管理蜕变为一个算法。

7.3 中断和异常处理的设计

(1)必须能够处理各种中断;(2)支持高频率的中断处理(此为通信芯片,物理层中断非常频繁);(3)支持硬件中断嵌套,不支持软件中断嵌套(这个决策与芯片有关);

7.4 线程调度的设计

(1)线程可以创建无数个;(2)线程可以手动退出,也可以自动退出;(3)提供线程间通信方法;(4)线程调度算法易于修改;(6)所有线程都是privileged权限;(7)线程的优先级可以在创建线程时设置(此为通信芯片,某些线程优先级很高);(8)线程调度接口简单;

7.5 系统调用的设计

系统调用函数分为2类:    (1)线程切换类;    (2)非线程切换类。之所以分类,是因为中断处理函数开放给用户编写,用户可能会在其中胡乱调用系统调用函数。所以对每个系统调用函数分类,使得在中断中只能调用非线程切换类函数。

8. 实现策略
8.1 最终目标

#include <stdio.h>#include "OS_API.h"void *taskA(void *arg){    u32 i;    while (1) {        for (i = 0; i < 2000000; i++);        schedule();    }}void *taskB(void *arg){    u32 i;    while (1) {        for (i = 0; i < 2000000; i++);        schedule();    }}int main(){    u32 i;    /* 1: register main() as a task, and put it to task chain, this has     * been done statically     */    /* 2: */    mem_init();    /* 3: */    interrupt_init();    /* 4: must be done after memory init */    sched_init();    /* 5: start testing */    thread_create(taskA, NULL);    thread_create(taskB, NULL);    while (1) {        for (i = 0; i < 2000000; i++);        schedule();    }    return 1;}

上述代码只有创建线程和线程调度,没有使用内存分配算法和开启中断。这符合先前的简化目标,因为我们仍处于验证设计是否可行的阶段,此时不应把代码弄复杂。
8.2 系统初始化

分类                 内容                                        初始化顺序                     PC寄存器,SP寄存器                              21全局设置——>           PS寄存器                                       14                     WINDOWBASE寄存器                               11windows机制           WINDOWSTART寄存器                             12                     a0寄存器,a1寄存器                              13中断机制              INTENABLE寄存器                                 1                     INTERRUPT寄存器                                 2                     ICOUNTLEVEL寄存器                               6debug异常机制         IBREAKENABLE寄存器                              5                     DBREAKCn寄存器                                  4zero-overhead机制     LCOUNT寄存器                                    3时间计算              CCOUNT寄存器                                    7扩展L32R模式          LITBASE寄存器                                   8                     PTEVADDR寄存器                                 15MMU机制              RASID寄存器                                     16                     ITLBCFG寄存器,DTLBCFG寄存器                     17协处理器              CPENABLE寄存器                                  9浮点寄存器            FSR寄存器,FCR寄存器                             10MMU机制              指令cache,数据cache                             18                     TLB entries或CACHEATTR寄存器                    19                     其它寄存器                     其它硬件结构ROM解压              从ROM中解压到内存中                               20调用第1个C函数        调用main()                                      22

8.3 内存管理初始化
存储访问中的参与对象:

ITLB,DTLB组ITLBCFG,DTLBCFG寄存器RASID寄存器PTEVADDR寄存器(存放页表的基地址)cache结构EXCVADDR寄存器

在CPU上电启动后,应做如下初始化工作:(没有列出先后顺序)

(1)ITLB组和DTLB组中,除了way 6,其余的way都置为invalid。(2)设置ITLBCFG寄存器和DTLBCFG寄存器,以设置way4, way5, way6的页表大小。(3)设置RASID寄存器的值为0x04030201。(4)清空cache中所有内容。(5)不设置PTEVADDR寄存器。因为此时位于ring 0,寻址可以使用way6,故不会发生硬件自动填充TLB的情况。

在main()运行之前:

(1)定义1个数组avail_memory[内存字节大小/ (1024 × 4 ×8)],用每个成员的每个bit表示1个4KB的内存;bit = 0表示该4KB没有被使用,bit = 1表示该4KB正在被使用;(2)将数组avail_memory[]的每个成员都置为0;(3)定义存储分配函数为:    void *emalloc(u32 size);    // 从主内存中分配size个字节的存储区    void efree(void *addr); // 从主内存中释放以addr为起始地址的存储区【注】之所以叫emalloc(),efree(),是不想与malloc()和free()混淆。

在mem_init()内部:

(1)将avail_memory[]数组清零;

8.4中断初始化
main()运行之前:

(1)定义1个数组:void (*interrupt_handler)[32];

interrupt_init()内部:

(1)将interrupt_handler[]数组全部设置为NULL;(2)将10ms定时中断的中断优先级设置为最低(为了嵌套中断能工作更顺利);

8.5 线程调度初始化
main()运行之前:

(1)将main()定义成1个线程;这步一定要将main()定义为1个线程,原因是这样的:main()一定会创建新线程,当新线程被中断或主动进行线程切换时,如果main()不是一个线程(从而它不在全局的线程链表中),则线程调度时,永远不会选择并切换回main()。

sched_init()内部:

    空;

thread_create()内部:

(1)使用phy_malloc()为每个新线程分配PCB;(2)对该新PCB进行结构方面的初始化;(3)对该新PCB进行栈上内容的初始化;

9. 实现总结

(1)查阅并总结文档非常耗时,占整个时间的2/3;编码及测试只占1/3;(2)尽量看官方文档,官方文档比网络上的二手资料准确;(3)先写核心模块,再逐步扩充OS功能。OS功能众多,难道要一次性全部写完?对本人而言,一次性写完难度太高了,根本完成不了。所以在设计阶段,就应经想好实现模块的先后顺序。初期实现目标代码,当然是越简单越好(否则就没信心了),无所谓效率,能进行线程创建、线程切换就行,此时不要求线程退出(线程就是无限循环)。这个阶段伴随着设计方案的验证、设计方案的修改、芯片理解的校正等,逐步实现线程切换。一旦实现线程切换,则可以加上内存分配、互斥量、条件变量等,再加上中断和异常处理、定时器,形成可以工作的OS;(4)xtensa GDB可以进行软件层的线程切换(Keil也可以),它是个非常强大的程序调试工具;
0 0
原创粉丝点击