Windows CE是一个层次结构的分明的嵌入式操作系统:BSP (Board Support Package)位于硬件层之上,该层内部包括三大部分,一是OAL (OEM Adaption Layer),二是硬件驱动程序,也就是所谓的driver,剩下第三个子模块就是Bootloader了,它的作用有点类似于普通PC的BIOS程序。BSP由产品制造商开发,提供硬件和操作系统内核间联系的桥梁。BSP层向上就是Windows CE的内核了,由微软开发,是整个操作系统的指挥中心。既然是内核,其功能也无外乎进程线程调度,内存管理等等。内核之上就是用户空间了,主要包括设备管理器device manager,各种服务程序等。这里需要注意的是device manager和device driver是两个完全不同的概念,device driver是真正的驱动,而这些驱动是否加载,什么时候加载则由device manager控制了。最顶层就是由用户利用Windows CE API开发的application了,无需多说。
在进行操作系统内核编译的时候,需要将OAL和内核一起打包成NK.bin镜像,最后生成NK.exe可执行文件。这里要讲的是Windows CE的中断处理机制,详细流程见下图。NK.exe就是CE的内核,上层的DEVMGR.dll就是设备管理器。
假设硬件在某一时刻产生了一个中断,这个中断首先由内核捕获。内核需要对中断的优先级进行管理,单从硬件来说各设备之间是用总线相连的,所以当出现两个设备同时产生中断的时候,内核需要做出选择,先相应哪个设备的中断信号。这是上图中所示的第一步。
第二步内核将硬件中断交给OAL代码,这段代码就是ISR中断服务程序。它可以分辨这个中断来自于哪个硬件设备,同时它也知道该硬件设备的ID。这一步的关键是它会将这个硬件ID翻译成软件ID,也就是该中断的逻辑号码,同时将翻译后的得到的逻辑号码交回给系统内核,也就是上图所示第3步。
第四步内核发出一个evenement通知,该通知里面包含了它刚才收到的逻辑ID。最后用户空间的IST,也就是真正的中断处理程序对中断进行处理。
上述步骤很清晰,但是实现IST的时候让我产生些许疑惑。IST的代码框架大致是这样的:
HANDLE hEvent = CreateEvent(...); DWORD dwSysIntr = ...; InterruptInitialize(...); while(bStopIST == FALSE) { WaitForSingleObject(hEvent, 100); ... ... InterruptDone(dwSysIntr); } InterruptDisable(dwSysIntr); CloseHandler(hEvent);
明明是系统内核产生一个evenement,为什么却在IST里CreateEvent? 后来查了一下MSDN,发现是我对Event Object这个概念的理解存在偏差。
事实上,假设有两个进程(process)A和B,A想要通过Event通知B某件事情已经发生,CreateEvent的调用在A和B里都是可行的。如果在A中调用,那么可以让B在该Event上等待,直到A调用SetEvent使得B可以继续执行;如果在B中调用,还是B紧接着在该Event上等待,条件一旦满足A就对Event进行set操作,于是B可以继续执行。也就是说,Event的创建与它是通知者还是被通知者无关,反正只要创建了一个Event,这个对象对两个进程都可见,因此可以用于进程间通信。注意这里是进程间通信,而不是线程,线程间通信有Critical Region和Lock这种更为轻量级的做法。
前文说过第四步系统内核发送evenement通知IST当前产生了一个硬件中断,这句话很含糊。我有那么多硬件,相应的,每一个硬件都一个IST,这么多IST,内核是怎么知道给哪个IST发送通知的? 回到上面的代码就清楚了,dwSysIntr是一个system call,它以硬件ID为参数返回对应的逻辑号码,这个工作OAL也要做。然后调用InterruptInitialize初始化中断,这个初始化过程它干了什么?答案就是它将硬件的逻辑ID在内核中进行注册,这个注册会产生一条logic ID到第一行代码生成的Event的句柄的映射。那么好了,系统收到OAL给它的逻辑ID之后开始查表,看看这个ID在这张表中存在吗? 不存在,中断自然会被丢弃。假设找到相应的记录项,则可以知晓应该对哪个Event进行set操作。set这个Event之后,在这个Event上等待的IST就可以从等待状态中恢复了。
上面说过中断可能被丢弃,那么什么时候会出现这种情况呢?个人理解,假设存在一个硬件A,但是它的IST并未被激活,常见的情形就是设备管理器device manager没有对设备A进行加载。毕竟,所有的IST线程都是由device manager创建的。
更多请参考:
http://geekswithblogs.net/BruceEitman/archive/2009/01/15/windows-ce-interrupt-service-thread.aspx