Adeos分析

https://blog.csdn.net/changexhao/article/details/77717459

1        简介
Adeos的全称是Adaptive Domain Environment for Operating System,它的目标是为操作系统提供了一个灵活的、可扩展的自适应环境,在这个环境下,多个相同或不同的操作系统可以共存,共享硬件资源;
随着历史的发展,目前已经存在了不少优秀的操作系统,正是因为这些操作系统的共同存在发展,而产生了以下的问题:
一方面,对于那些面向相同的用户,具有相似设计理念和功能的操作系统来说,它们之间是不兼容或不完全兼容的,例如,在Windows操作系统上的应用程序是不能直接在Linux上运行的;这就将用户(包括程序设计者和系统管理员)限制在了一个固定的软件环境下,用户在应用的选择上缺少灵活性。
另一方面,由于最初的应用环境和面向的用户的不同,有些操作系统在设计理念和功能上完全不同;但是,随着计算机技术的发展,现在的一个计算机系统往往具有以前多个系统的功能,各种计算机系统之间的界限越来越模糊;例如,现在的终端电子设备对实时性的要求越来越高(如智能手机),而某些实时系统也对人机界面的交互有了更高的要求,这就会促使这两种应用环境下的操作系统相互融合。
目前,主要存在两类方法使多个操作系统运行在同一个系统上;第一类方法是模拟,例如,VMWare,Plex86和VirtualPC等;它们都是在已有的操作系统上提供一个虚拟的硬件环境,在这个虚拟硬件环境下可以运行另外操作系统。这样,用户就可以充分的利用两个或多个系统所提供的功能和软件;但这种方法最大的缺点就是会极大的降低系统的性能,因为它包含三个软件层次:主机操作系统(Host Operating System)->虚拟硬件环境->客户操作系统(Guest Operating System)。第二类方法,是在硬件上实现一个所谓的超微内核(nano-kernel),通过这个超微内核实现硬件的共享,然后再在这个内核上构建实用的操作系统,例如,SPACE,Cache kernel和Exokernel等,但这些方法都没有考虑当前已经存在的操作系统和用户。
而Adeos是在已有的操作系统下插入一个软件层,通过向上层多个操作系统提供某些原语和机制而实现硬件共享。但是Adeos并不对硬件的使用强加任何的限制,上层的操作系统仍然可以自由的操作硬件,而不会因为Adeos的存在而有任何的约束(实际上,上层的操作系统可以完全不知道有Adeos的存在)。Adeos除了可以实现操作系统对系统资源的共享之外,还可以用于新的操作系统的开发、操作系统内核的调试、跟踪等。
目前,Adeos是基于Linux内核实现的,主要的应用是在Linux的实时化方面,使基于Linux的系统能满足硬实时的要求(Linux+RTAI)。


---------
2        基本原理
在基于Adeos的系统中,每个操作系统都在独立的域内运行(但不一定所有的域内实现的都是操作系统,也可以是完成其它功能的软件实体),每个域可以有独立的地址空间和类似于进程、虚拟内存等的软件抽象层,而且这些资源也可以由不同的域共享。
在基于Adeos的系统中,存在着四种类型的交互,如图3-1所示;
  
A类交互是各个域对硬件的直接操作,这些操作包括访存和和对硬件的设置等,在这种情况下,就和Adeos不存在一样;B类交互是双向的,一方面Adeos接收硬件产生的中断和异常,另一方面,Adeos也直接控制硬件;C类交互指当Adeos接收到硬件中断后,会执行相应域的中断服务程序;D类交互指当域内的操作系统知道有Adeos存在的时候,它可以主动向Adeos请求某些服务,例如,请求共享其它域中的资源、请求授权域优先级等。通过D类交互,可以实现各个域之间的通讯。
对于一个计算机系统来说,系统的运行是由内部和外部的中断和异常所触发的,例如系统时钟中断对操作系统来说就是最重要的,操作系统没有了系统时钟中断,就像人没有了心跳一样,所以说,如果想要控制操作系统的运行,最直接的方法就是接管操作系统的中断处理机制。所以,Adeos的主要工作就是管理硬件的中断,根据域的优先级依次执行相应域的中断服务程序,从而驱动域内的系统运行;同时,Adeos还提供域之间的通信机制、实现域的调度等。
为了实现对中断的管理和域之间的优先级控制,Adeos使用了中断管道(Interrupt Pipe)的概念,如图3-2所示;

  

Adeos通过中断管道在不同的域之间传播中断,而且提供了相应的机制可以让域改变自己在中断管道中的优先级,在图3-2中,各个域的优先级为:域1>域2>……>域N>Idle域;
通常,在操作系统中,对中断的处理方式有两种:允许中断和禁止中断;但在基于Adeos的系统中,由于存在着中断管道,域内的操作系统对中断的处理方式还有另外两种:抛弃中断和终止中断。如果某个域允许中断,中断产生后,Adeos会调用相应域的中断处理程序,这和不存在Adeos的情况是类似的,只不过在这种情况下,中断服务程序由Adeos负责调用;如果某个域禁止中断(实际上并没有真正禁止硬件中断,而只是设置了一个软件标志),当硬件中断沿着中断管道传播到这个域的时候,Adeos既不调用相应域的中断处理程序,也不会将此中断沿着中断管道进一步向下传播,而只是将这个硬件中断的中断类型和环境参数保存起来,并更新这个中断的中断次数。当域允许中断后,Adeos再根据中断类型、环境参数和中断次数调用相应的中断处理程序,并将此硬件中断沿着中断管道进一步向下传播。如果某个域抛弃某个硬件中断,当中断传播到这个域的时候,Adeos不做任何的处理,直接将这个中断沿着中断管道向后传播。如果某个域终止某个中断,当中断传播到这个域的时候,Adeos根据这个域的设置处理完这个中断之后,不再将这个中断沿着中断管道向后传播,也就是说,后面低优先级的域将不知道有这个硬件中断的产生。
所以,Adeos就是通过控制系统的中断来实现对各个域内操作系统的控制。从图3-3可以对基于Adeos的系统的运行模型有一个整体的概念;其中,D1、D2分别代表两个域,且优先级为D1>D2,为了使描述更加清晰明了,对系统作如下的假设:
系统有两个域D1和D2,两个域完全一样,除了优先级D1>D2,且两个域都允许中断;
整个系统只有两个硬件中断INT1和INT2;
每个域有两个中断服务程序ISR1和ISR2,分别对应于INT1和INT2;
每个域有两个任务TASK1和TASK2(不包括IDLE任务),分别由ISR1和ISR2触发运行;且TASK1的优先级高于TASK2(只有当TASK1任务完成后,TASK2才能开始运行);
  

从图3-3可以看出,在T1时刻,Adeos接收到了硬件的中断信号,然后就开始遍历中断管道,找到最高优先级的域D1,然后执行域D1的中断服务程序ISR1,ISR1执行完后,就切换到域D1,D1内的任务TASK1开始运行;TASK1运行完成后,域D1就被挂起(Suspended),Adeos然后执行D2的中断服务程序ISR1,ISR1执行完后,就切换到域D2,开始D2内TASK1的运行;当D2的TASK1运行到T2时刻时,硬件产生了中断信号INT2,域D2被中断,Adeos接收到INT2后,又再一次开始从头遍历中断管道,找到了最高优先级的域D1,然后执行D2的中断服务程序ISR2,ISR2执行完后,就切换到域D1,开始D1内任务TASK2的运行;TASK2运行完成后,域D1被挂起,Adeos然后执行D2的中断服务程序ISR2,ISR2执行完后,就切换到域D2,并开始域D2内被中断的任务TASK1和新触发的任务TASK2的执行;当域D2的任务都执行完成后,域D2被挂起,系统进入IDLE状态。

3        基于Linux的实现
考虑到从硬件层开始构建一个操作系统的难度,Adeos并没有并没有从零开始构建一个硬件抽象层;目前,Adeos是基于Linux内核实现的,这样的话,就可以将系统的启动和初始化工作都由Linux来完成,在系统完成初始化后,再进行Adeos的初始化工作(包括接管Linux的中断管理机制),Adeos功能既可以直接编译进内核,也可以作为一个内核模块在系统运行时动态加载,就和内核的驱动程序模块一样。
在这种实现方法下,Linux作为Adeos的一个特殊的域存在,我们称之为根域(Root Domain)。Adeos的很多功能都是依靠根域(也就是Linux内核)来实现的,例如,动态注册其它的域模块是通过Linux的动态模块加载功能实现的,为其它域的任务分配任务堆栈是通过Linux内存分配接口实现的等。根域的初始化是在Adeos的初始化过程中完成的;根域对于Adeos来说,有一点类似于Linux初始化过程中创建的INIT进程;
------------------
3.1        基本架构
Adeos在Linux配置中增加了三个配置开关来配置Adeos的代码:CONFIG_ADEOS_CORE,CONFIG_ADEOS和CONFIG_ADEOS_MODULE。如果定义了CONFIG_ADEOS_CORE,Adeos的核心支持就被编译进了Linux内核,不论Adeos功能最终编译进内核还是编译成可动态加载的模块,这个编译选项都必须被定义;如果定义了CONFIG_ADEOS,则也隐含着对CONFIG_ADEOS_CORE的定义,Adeos功能就被编译进了内核,那么,从Linux启动以后,Adeos功能就被使能了;如果定义了CONFIG_ADEOS_MODULE,则也隐含着对CONFIG_ADEOS_CORE的定义,Adeos功能被编译成可动态加载的模块,只有当这个模块被加载后,Adeos的功能才会起作用。
Adeos对Linux源代码树的修改涉及到30多个文件(包括新增加的文件),如图3-4所示。
  
其中的Makefie和Config.in文件,是为Adeos代码添加内核编译选项和内核配置选项;
adeos目录下的generic.c包含了与平台无关的通用的Adeos代码,而armv.c则包含了与ARM平台相关的通用于ARM平台的Adeos代码;
在arch/arm/kernel目录下,adeos.c中包含了Adeos关于中断处理的代码;armksyms.c中增加了代码,导出了ARM体系相关的Adeos接口;entry-armv.S和entry-common.S中增加了截获Linux中断和系统事件的代码,域的切换代码也在此处实现;同时,修改了irq.c以适应Adeos的中断处理机制;在process.c中修改了Linux的idle进程,当Linux进入idle状态时,将通知Adeos;time.c中增加了Adeos中修改定时器频率的接口;
Documentation/adeos.txt对Adeos进行了简单的介绍;
在init/main.c中增加了对Adeos进行初始化的代码;
kernel/adeos.c中包含的是Adeos对根域也就是Linux操作的代码;对kernel目录下的其它文件的修改,主要是为了增加Adeos对Linux系统事件进行捕获所需的代码;
3.2        源代码分析
-------------------------
3.2.1        Adeos相关实体
这里根据Adeos内全局量的重要性,对所有组成Adeos实体的全局量进行分析,包括其初始化、取值范围、功能等。


struct list_head __adeos_pipeline;
spinlock_t __adeos_pipelock = SPIN_LOCK_UNLOCKED;


在文件kernel/adeos.c中定义;Adeos的中断管道是用Linux的标准链表来实现的,而这个链表的头就是__adeos_pipeline,它实际上就是中断管道的访问入口,每个域都通过一个链表项按优先级连接在这个链表上。而__adeos_pipelock则是用来保护中断管道的互斥访问。


static adomain_t adeos_root_domain;
adomain_t *adp_root = &adeos_root_domain;
adomain_t *adp_cpu_current[ADEOS_NR_CPUS] = { [ 0 ... ADEOS_NR_CPUS - 1] = &adeos_root_domain };


在文件kernel/adeos.c中定义(本分析中的文件路径都是相对于Linux内核代码树的根目录而言的);adeos_root_domain是由Adeos静态定义的根域(也就是Linux);adp_root是指向根域的指针;而数组adp_cpu_current[]则是保存着指向CPU上当前运行的域的指针,ADEOS_NR_CPUS是系统中CPU的个数。


int __adeos_event_monitors[ADEOS_NR_EVENTS] = { [ 0 ... ADEOS_NR_EVENTS - 1] = 0 };


在文件kernel/adeos.c中定义;此数组中的每个元素对应着Linux中的一个系统事件(例如,进入系统调用事件、退出系统调用事件等),当某个域想要跟踪某个系统事件是,它就调用adeos_catch_event,告诉Adeos它想要跟踪这个系统事件,并将事件的处理函数传递给Adeos。Adeos根据事件的类型将__adeos_event_monitors数组中的某个元素的值加一或减一(当事件处理函数为空时减一,否则加一)。当某个系统事件发生时,Adeos根据事件类型,检查__adeos_event_monitors数组中的相应元素的值是否大于零,如果大于零,则说明某个域想跟踪这个系统事件,那么就将这个事件传递给中断管道处理,处理过程中会调用域的事件处理程序。


static struct irqdesc __adeos_std_irq_desc[NR_IRQS];


在文件adeos/armv.c中定义的,它的赋值是在__adeos_enable_pipeline中进行的,代码段如下:


for (irq = 0; irq < NR_IRQS; irq++)
        __adeos_std_irq_desc[irq] = irq_desc[irq];


其中的数组irq_desc[]是标准Linux中用来保存中断描述符的;所以,从这里就可以看出,__adeos_std_irq_desc[]数组保存的是标准的Linux中断描述符;由于Adeos需要接管Linux的中断管理,就要修改irq_desc[]数组的内容,因此,就将修改前的标准的Linux中断描述符保存起来。一方面,在卸载Adeos模块的时候可以恢复(在函数__adeos_disable_pipeline中调用),另一方面,在Adeos的代码中还需要调用标准描述符中的代码(例如,在__adeos_override_irq_mask中)。


unsigned long __adeos_virtual_irq_map = 0;


在文件kernel/adeos.c中定义的;变量__adeos_virtual_irq_map记录着虚拟中断的分配情况,在32位处理器上,共有32个虚拟中断,从0到31;当某一位为1时,表示虚拟中断已经被分配了,为0时,则没有分配;Adeos用虚拟中断来提供域之间的通信,当某个域需要执行另一个域的某些操作时,可以触发一个虚拟中断,当这个虚拟中断沿着中断管道传播时,接收这个虚拟中断的域就会执行相应的操作,这在处理上和硬件中断类似,只不过这个中断是由域触发的而已。


int adp_pipelined = 0;


在文件arch/arm/kernel/adeos.c中定义的;表示Adeos是否已经接管根域的中断管理,也就是说,表示中断管道当前是否有效。很多代码都要通过判断这个标志量来确定应该执行的操作。
----------------------------
3.2.2        域(Domain)相关实体
Adeos中的每个域都由一个域结构变量表示,这个结构变量保存着域的属性和和状态;域结构adomain_t的定义如下:


typedef struct adomain {


    /* -- Section: offset-based references are made on these fields
       from inline assembly code. Please don't move or reorder. */
    void (*dswitch)(void);        /* Domain switch hook */
    int *esp[ADEOS_NR_CPUS];        /* Domain stack pointers */
    /* -- End of section. */


    int *estackbase[ADEOS_NR_CPUS];


    unsigned domid;


    const char *name;


    int priority;


    struct adcpudata {
        unsigned long status;
        unsigned long irq_pending_hi;
        unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
        unsigned irq_hits[IPIPE_NR_IRQS];
        adevinfo_t event_info;
    } cpudata[ADEOS_NR_CPUS];


    struct {
        int (*acknowledge)(unsigned irq);
        void (*handler)(unsigned irq);
        unsigned long control;
    } irqs[IPIPE_NR_IRQS];


    struct {
        void (*handler)(adevinfo_t *evinfo);
    } events[ADEOS_NR_EVENTS];


    int ptd_keymax;
    int ptd_keycount;
    unsigned long ptd_keymap;
    void (*ptd_setfun)(int, void *);
    void *(*ptd_getfun)(int);


    struct adomain *m_link;        /* Link in mutex sleep queue */


    struct list_head p_link;        /* Link in pipeline */


} adomain_t;


dswitch是一个函数指针,指向一个钩子函数,这个函数在域的切换过程中被调用;esp[ADEOS_NR_CPUS]是一个指针数组,域在不同的CPU上运行的时候有不同的栈,而esp则用来在域切换之前保存当前栈的位置;estackbase[ADEOS_NR_CPUS]则保存着每个栈的栈底;domid是域的识别号,这个值对每个域都是唯一的;name则是域的名字;priority表示域的优先级,也就是域在中断管道中的优先级;cpudata和irqs都与中断处理有关,在后面分析Adeos的中断处理的时候再详细讨论;events保存着域的事件处理程序;所有以ptd_开头的字段,都和所谓的Per-thread data key有关;m_link是一个指向域的指针,用于域睡眠时加入等待队列;p_link则是用于中断管道的连接。
------------------------
3.2.3        Adeos初始化
Adeos的初始化是在Linux的初始化过程中调用的,是由函数start_kernel来调用,初始化函数为__adeos_init();这个函数的定义在文件kernel/adeos.c中,它完成的主要工作如下:
初始化根域adeos_root_domain;
分配一个虚拟中断__adeos_printk_virq,主要用来完成其它域对根域请求的printk内核输出操作;
Adeos接管Linux的中断管理机制,这是通过调用__adeos_takeover()实现的;
__adeos_takeover()仅仅调用__adeos_enable_pipeline()来完成中断的接管操作;__adeos_enable_pipeline()定义在adeos/armv.c中,它的主要功能如下:
1.调用函数adeos_virtualize_irq指定所有根域中断的中断处理函数和中断确认函数;
2.将Linux原来的中断描述符保存在数组__adeos_std_irq_desc[]中;
3.用Adeos相关的中断屏蔽、中断响应等函数替换原有Linux的相应函数;
4.将标志变量adp_pipelined置为1;
至此,Adeos的初始化就已经完成;初始化完成后,系统中存在着一个域,那就是根域(root domain),这时Linux的中断管理机制已经由Adeos来管理。
----------------
3.2.4        域注册
Adeos系统中,除了根域(root domain)是在Adeos初始化过程中被静态创建的之外,其它的所谓的客户域(client domain),在使用Adeos提供的服务之前,都必须通过域注册函数int adeos_register_domain (adomain_t *adp, adattr_t *attr)先进行注册。参数adp指向将要被注册的域实体结构变量,参数attr则指向一个域属性结构变量,注册函数将根据attr中的属性对adp进行初始化;域注册函数完成的功能如下:
1.检查当前域是否是根域(Linux),只有根域才可以注册其它的域,因为在目前的Adeos实现下,其它的域都要以Linux下内核动态模块的形式存在;
2.遍历所有的域,检查当前需要注册的域是否已经存在(根据域标志domid来判断),如果已经存在,则出错返回;
3.对域结构变量内的字段进行初始化;通过__adeos_init_domain()函数对域的栈进行初始化,并给栈赋初值,为域的首次运行做好准备;
4.查找中断管道的域列表,根据域的优先级找到新域在中断管道中的位置;并将新域插入中断管道;
5.调用__adeos_switch_to()函数切换到新域;
在attr所指的域属性结构中,有一个字段attr->entry,它是一个函数指针,它指向域自己定义的初始化函数,这个函数地址在初始化域的程序栈的时候被保存在了栈中,当域第一次执行的时候,将会从栈中取出这个初始化函数的地址,执行域自己定义的初始化。
----------------------------
3.2.5        Adeos中断处理
Adeos中断处理函数的入口是asmlinkage int __adeos_handle_irq (int irq, struct pt_regs *regs),它的定义在arch/arm/kernel/adeos.c中;这个函数既用来处理硬件中断,也用来处理软件中断(这里所说的软件中断是由域触发,用于域之间的通信);所以,这个函数在两个地方被调用。
第一个,是在系统的中断处理入口,在基于ARM的平台中,中断处理入口都在文件arch/arm/kernel/entry-armv.S中,Adeos用这个函数替换了Linux原来的中断处理函数do_IRQ(),例如,USER MODE模式下中断处理代码片断如下:


__irq_usr:      sub     sp, sp, #S_FRAME_SIZE
                stmia   sp, {r0 - r12}                  @ save r0 - r12
                ldr     r4, .LCirq
                add     r8, sp, #S_PC
                ldmia   r4, {r5 - r7}                   @ get saved PC, SPSR
                stmia   r8, {r5 - r7}                   @ save pc, psr, old_r0
                stmdb   r8, {sp, lr}^
                alignment_trap r4, r7, __temp_irq
                zero_fp
1:              get_irqnr_and_base r0, r6, r5, lr
                movne   r1, sp
                adrsvc  ne, lr, 1b
                @
                @ routine called with r0 = irq number, r1 = struct pt_regs *
                @
#ifdef CONFIG_ADEOS_CORE
                bne     __adeos_handle_irq
#else /* !CONFIG_ADEOS_CORE */
                bne     do_IRQ
#endif /* CONFIG_ADEOS_CORE */
                mov     why, #0
                get_current_task tsk
                b       ret_to_user


第二个,是在函数adeos_trigger_irq中被调用,当某个域想要触发某个软件中断时,就可以调用软件中断触发函数adeos_trigger_irq产生一个软件中断,这个软件中断就会沿着中断管道传播,触发其它域执行相应的处理函数,这样就可以达到域之间通信的目的。
Adeos中断处理函数__adeos_handle_irq完成的功能如下:
1.判断标志变量adp_pipelined的值,如果为零,则说明中断管道现在不可用,则调用Linux的中断处理入口函数do_IRQ来进行中断处理;
2.依次遍历中断管道,如果域接受相应的中断,则将此中断记录在域的中断日志中,包括记录中断类型和中断次数,然后调用中断应答函数;
3.调用函数__adeos_walk_pipeline,沿着中断管道执行域的中断处理函数,在执行完域的中断处理函数后,Adeos会切换到这个域,也就是将CPU的控制权交给这个域,当这个域执行完所有的操作后,域就主动挂起,控制权交回Adeos,Adeos在执行中断管道中随后的域的中断处理程序并根据需要交换控制权,直到所有的域都执行完。
每个域与中断相关的数据主要存放在域结构变量的两个字段中,分别是cpudata和irqs,它们的定义如下:


struct adcpudata {
        unsigned long status;
        unsigned long irq_pending_hi;
        unsigned long irq_pending_lo[IPIPE_IRQ_IWORDS];
        unsigned irq_hits[IPIPE_NR_IRQS];
        adevinfo_t event_info;
    } cpudata[ADEOS_NR_CPUS];


    struct {
        int (*acknowledge)(unsigned irq);
        void (*handler)(unsigned irq);
        unsigned long control;
    } irqs[IPIPE_NR_IRQS];


在结构变量cpudata[ADEOS_NR_CPUS]中,每个元素包含在某个CPU上的中断信息;其中,字段status表示当前域的状态,它的取值范围如下:
IPIPE_STALL_FLAG:表示域禁止中断,当硬件中断沿着中断管道传递到这个域的时候,Adoes将不会执行域的中断处理程序,也不会将中断沿着中断管道继续向下传播;
IPIPE_SYNC_FLAG:表示Adoes正在为这个域执行中断处理程序(被称为IRQ同步),保护同步代码不被同步执行;
IPIPE_XPEND_FLAG:表示域收到了异常(或者说系统事件,如进入、退出系统调用等)通知消息,而且还没有对其进行处理;
IPIPE_SLEEP_FLAG:表示域已经将自己挂起,也就是说,现在是其它的域在运行;当一个域刚被注册的时候就是处于被挂起的状态;
在cpudata中,字段irq_pending_hi,irq_pending_lo[IPIPE_IRQ_IWORDS]和irq_hits[IPIPE_NR_IRQS]用于保存域接收到的中断信息。IPIPE_NR_IRQS为系统中断个数(包括用于域间通信的软件中断)irq_hits[]的每个元素对应于某一个中断发生的次数;irq_pending_lo[]是一个映射表,每一位对应于一个中断,当某个中断发生时,就将这个映射表中的相应位置1表示相应的中断发生了;irq_pending_hi也是一个映射表,其中的每一位对应于irq_pending_lo数组中的每一个元素;例如,当接收到32号中断后,irqs_hits[32]的值加1,irq_pending_lo[1]的位0被置1(相当于映射表的位32),irq_pending_hi的位1被置1(表示数组irq_pending_lo的第2个元素有位被置1)。
在cpudata中的字段event_info则是用来保存接收到的系统事件通知的信息,它的结构如下:


typedef struct adevinfo {
    unsigned domid;
    unsigned event;
    void *evdata;
    volatile int propagate;        /* Private */
} adevinfo_t;


其中的字段domid表示系统事件是在哪个域发生的;event表示事件类型;evdata则是传递给事件处理函数的参数;propagate指示执行完事件处理函数后是否将这个事件通知传递给中断管道中后面的域。
irqs[IPIPE_NR_IRQS]保存着中断的中断处理函数、中断应答函数和中断的处理模式;中断处理模式字段control是一个位掩码,目前中断处理共有四种模式:
1.域不处理中断而直接将中断传递给低优先级的域(control = IPIPE_PASS_MASK);
2.域对中断进行处理,但不再将中断传递给低优先级的域(control = IPIPE_HANDLE_MASK);
3.域对中断进行处理并将之传递给低优先级的域(control = IPIPE_HANDLE_MASK | IPIPE_PASS_MASK);
4.域既不对中断进行处理,也不将中断传递给中断管道中优先级的域;
从上面的分析可以看出,Adeos的中断入口函数仅仅只是将中断信息纪录在每个域的中断相关的日志内,每个域的中断处理函数的执行实际上是由中断管道来调度的(根据域的优先级);中断管道对域的中断函数的执行是通过对函数__adeos_walk_pipeline的调用实现的(在函数__adeos_handle_irq的最后被调用)。
在分析__adeos_walk_pipeline之前,先考虑一下一个域在Adeos系统中所处的状态,将会有助于对后面分析的理解。Adeos系统中的每个域,都处于以下3种状态之一:
第一种是域处于运行状态,在这种情况下,中断管道中比当前运行状态的域优先级高的域都处于挂起状态,也就是说,高优先级的域都没有任务、中断或系统事件需要处理,他们都通过调用函数adeos_suspend_domain将本身挂起;而中断管道中比当前运行域优先级的的域则或者处于挂起状态或者处于被中断状态;
第二种是域处于挂起状态,这说明这个域是通过调用adeos_suspend_domain将本身挂起的,在挂起的时候域没有任务或中断或事件需要处理。但经过一段时间后,处于挂起状态的域,可能也有需要处理的中断或事件通知,只不过现在有更高优先级的域在运行而已。
第三种是域处于被中断的状态,当一个域正处于运行态时,如果这个时候产生中断,或是触发了一个系统事件,Adeos就开始进行中断的处理,如有更高优先级的域需要处理这个中断的时候,Adoes就会调度高优先级的域先运行,那么,这个被中断的域就处于被中断状态了。
__adeos_walk_pipeline定义在文件arch/arm/kernel/adeos.c中,它完成的主要功能如下:
1.沿着中断管道从头开始对域进行处理;
2.如果域禁止中断,则不再对之后的域进行中断的处理;
3.如果某个域有需要处理的中断,则调用域切换函数__adeos_switch_to从当前域切换到那个域,那个域在恢复运行的时候会通过调用函数__adeos_sync_stage执行中断处理函数;
4.如果遍历到了当前域,则直接调用__adeos_sync_stage执行当前域的中断处理函数,然后就可以退出函数__adeos_walk_pipeline,紧接着退出Adeos的中断处理函数__adeos_handle_irq,返回被中断的域继续运行。
__adeos_sync_stage的主要功能是执行域的中断处理函数,并更新域结构的中断相关日志。
__adeos_switch_to的功能就是通过调用汇编函数__adeos_switch_domain进行域切换,然后再调用域切换的钩子函数dswitch。

猜你喜欢

转载自blog.csdn.net/sunjing_/article/details/85049474
今日推荐