Wince支持arm, mips, sh, x86四种平台,所以在kernel下存在4个目录对应4个平台相关代码, 只分析arm的。
[内核编译]
Kernel.dll = kern.dll
编译kern.dll = <nkcompr.lib> + <nkmapfile.lib> + <nkmsgq.lib> + oemstub.lib + nklogger.lib + nkmain.lib + fulllibc.lib链接成nk模块。前面3个库是可选的:组件[compression]决定变量sysgen_nkcompr,进而决定是否包括nkcompr. 组件[Memory Mapped Files]决定变量sysgen_nkmapfile,进而决定是否包括nkmapfile。 组件[Message Queue]决定变量sysgen_msgqueue,进而决定是否包括nkmsgq。 fulllibc.lib就是c语言库, 狭义上的内核就是nkmain.lib
[进入内核之前 -- 设计一个nkldr]
OAL跳转到内核本来是KernelStart(g_oalAddressTable); 因为wince6特性OAL和kernel分离, 这时候没有直接跳转到kernel的入口点, 而是到nkldr.lib的KernelStart转了一下。 KernelStart()根据参数,首先设定一级页表,初始化堆栈(NKStartup是c语言入口),启动MMU和cache,并且将KDATA段地址做为参数,真正跳转到内核kern.dll的入口NKStartup(pKdata). 。nkldr怎么找到kernel.dll? 根据关键字kernel.dll直接在镜像里面搜寻然后重定位。以后再把这个过程细细挖掘。
[NKStartup的参数KData是什么?]
其实就是一个数据结构, 它位于nkldr的data区。如下:
AREA |.KDATA|,DATA,NOINIT
KDataArea
PTs % 0x4000 ; space for first-level page table
ExceptionVectors
% 0x0400 ; space for exception vectors
% 0x0400 ; space for interrupt stack
% 0x0100 ; space for FIQ stack
% 0x0700 ; space for Abort stack
KPage % 0x0c00 ; space for kernel stack & KDataStruct
HighPT % 0x0400 ; 2nd level page table to map 0xFFF00000
KDEnd % 0
撇开实现, 单纯去理解的话, 和传递一个结构体指针没有什么区别。 再问: 这个数据结构干嘛的,代表什么? 这得明白高地址分配。
[高地址分配]
^ 0xFFFD0000
FirstPT # 0x4000
# 0x4000
# 0x8000
# 0x10000 ; not mapped
ExVector # 0x0400 ; vectors and table
# 0x0400 ; 1K interrupt stack (ffff0400)
IntStack # 0x0100 ; 256 byte FIQ stack (ffff0800)
FIQStack # 0x0700 ; 2K-256 abort stack (ffff0900)
AbortStack #0xC000-0x1000;not mapped (ffff1000)
KDBase # 0x07E0 ; 2K-32 kernel stack
KStack # 0x0020 ; temporary register save area
KData # 0x400 ; kernel data area
FirstPT就 是之前说的一级页表所在。大小16kbytes。 后面保留了2块区域,也许是提供给2级页表使用。 ExVector是异常入口, Arm有个机 制, 通过设定p15, 可以将异常入口从0x18改成高地址 FFFF0000. IntStack, FIQStack, AbortStack, KStack分别是各个模式以及内核的堆栈。 KData就是内 核参数区了。
typedef struct ARM_HIGH {
ulong firstPT[4096]; // 0xFFFD0000: 1st level page table
char reserved2[0x20000-0x4000];
char exVectors[0x400]; // 0xFFFF0000: exception vectors
char reserved3[0x2400-0x400];
char intrStack[0x400]; // 0xFFFF2400: interrupt stack
char reserved4[0x4900-0x2800];
char abortStack[0x700]; // 0xFFFF4900: abort stack
char reserved5[0x6800-0x5000];
char fiqStack[0x100]; // 0xFFFF6800: FIQ stack
char reserved6[0xC000-0x6900];
char kStack[0x800]; // 0xFFFFC000: kernel stack
struct KDataStruct kdata; // 0xFFFFC800: kernel data page
} ARM_HIGH;[回顾启动流程]
Mdarm.c文件的最后一个函数NKStartup()就是kern.dll的入口点。
NKStartup()
ARMSetup()
OEMInitDebugSerial()
OEMInit()
KernelFindMemroy()
KernelStart()
KernelInit()
APICallInit();
HeapInit();
InitMemoryPool();
PROCInit();
VMInit(g_pprcNK);
THRDInit();
MapfileInit();
FirstSchedule();
THRDInit()初始化了第一个线程是SystemStartupFunc, 所以FirstSchedule开始第一次调度, 就调度到SystemStartupFunc函数开始执行:
SystemStartupFunc()
KernelInit2();
LoaderInit();
PagePoolInit();
LoggerInit();
SysDebugInit();
CreateKernelThread(Monitor1);
InitMsgQueue();
InitWatchDog();
CreateKernelThread(PowerHandlerGuardThrd);
CreateKernelThread(RunApps);
While(1) {
NKWatiForSingleObject(ONE_DAY);
}
RunApps() 里面就是启动filesys.exe了, 在ce6是filesys.dll.后面的事情是另一波了。