ARM上的Linux内核及启动过程.ppt
文本预览下载声明
ARM上的Linux内核及启动过程 2007.12 linux 2.4 的内核目录结构 读懂linux内核源码 linux内核庞大,结构复杂 对linux内核的统计:接近1万个文件,4百万行代码 内核编程习惯(技巧)不同于应用程序 (uC)linux内核的C代码 Linux内核的主体使用GNU C,在ANSI C上进行了扩充 Linux内核必须由gcc编译器编译 gcc和linux内核版本并行发展,对于版本的依赖性强 内核代码中使用的一些编程技巧,在通常的应用程序中很少遇到 GNU C的扩充举例 从C++中吸收了inline和const关键字 ANSI C代码与GNU C中的保留关键字冲突的问题可以通过双下划线(_ _)解决 例如:inline 等价于 __inline__、asm等价于__asm__ 结构体(struct)的初始化 结构体初始化 struct sample { int member_int; char *member_str; void (*member_fun)(void); }; ANSI C中的实现 struct sample inst_c={ 100, //member_int NULL, //*member_str; myfunc //void (*member_fun)(void); }; GCC中的实现 struct sample inst_gcc = { member_fun: myfun, member_int: 100, }; 与C99中的用法类似,不必关心struct定义中的实际的顺序和其他未定义的数据,在复杂的结构体初始化的时候很有优势。 宏定义的灵活使用(1) 虽然GCC中定义了inline关键字,但是,宏操作(#define)仍然在系统中大量使用 举例: #define DUMP_WRITE(addr,nr) do\ { memcpy(bufp,addr,nr); bufp += nr; } while(0) 应用DUMP_WRITE,就像使用C的函数一样: if(addr) DUMP_WRITE(addr, nr); else… 但是,如果如通过下的定义,都不能满足上述的情况 定义1: #define DUMP_WRITE(addr,nr) memcpy(bufp,addr,nr);\ bufp += nr ; 定义2: #define DUMP_WRITE(addr,nr) {memcpy(bufp,addr,nr);\ bufp += nr;} 宏定义的灵活使用(2) #define OFFSETOF(strct, elem) \ ((long)(((struct strct *)0)-elem)) 1、((struct strct *)0) 结构体strct的指针 2、((struct strct *)0)-elem)成员的地址,也就是相对于0的偏移 3、结果:OFFSETOF(strct,elem)返回的是,结构体strct中成员elem的偏移量 C语言中goto的使用 在应用程序的C编程中,为了保证程序的模块化,建议不使用goto 内核代码需要兼顾到效率,所以,大量使用goto 整个内核的比例大概是每260行一个goto语句——速度优先 短距离的goto Linux内核加载过程 通常,Linux内核是经过gzip压缩之后的映象文件 bootloader复制压缩内核到内存空间 内核自解压 运行内核 编译完成的Linux内核在哪里? ./vmlinux,elf格式未压缩内核 arch/arm/boot/compressed/vmlinux,压缩以后的elf格式内核 arch/arm/boot/zImage,压缩内核 压缩内核(zImage)的入口 /arch/arm/boot/compressed/vmlinux.lds文件为编译器指定连接(link)顺序 ENTRY(_start),压缩内核从.start段开始 在arch/arm/boot/compressed/head.S中 检测系统空间 初始化C代码空间 跳转到C代码decompress_kernel,arch/arm/boot/compressed/misc.c中 解压之前的串口输出 include/asm-arm/arch-s3c2410/uncompress.h定义了puts作为串口输出函数 解压结束以后,跳转到r5:解压之后内核的起始地址 开始真正的Linux内核 入口在arch/arm/kernel/head-armv.S 查找处理器类型 __lookup_processor_type __lookup_archit
显示全部