ImageVerifierCode 换一换
格式:DOCX , 页数:6 ,大小:25.65KB ,
资源ID:8435993      下载积分:3 金币
快捷下载
登录下载
邮箱/手机:
温馨提示:
快捷下载时,用户名和密码都是您填写的邮箱或者手机号,方便查询和重复下载(系统自动生成)。 如填写123,账号就是123,密码也是123。
特别说明:
请自助下载,系统不会自动发送文件的哦; 如果您已付费,想二次下载,请登录后访问:我的下载记录
支付方式: 支付宝    微信支付   
验证码:   换一换

加入VIP,免费下载
 

温馨提示:由于个人手机设置不同,如果发现不能下载,请复制以下地址【https://www.bdocx.com/down/8435993.html】到电脑端继续下载(重复下载不扣费)。

已注册用户请登录:
账号:
密码:
验证码:   换一换
  忘记密码?
三方登录: 微信登录   QQ登录  

下载须知

1: 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。
2: 试题试卷类文档,如果标题没有明确说明有答案则都视为没有答案,请知晓。
3: 文件的所有权益归上传用户所有。
4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
5. 本站仅提供交流平台,并不能对任何下载内容负责。
6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

版权提示 | 免责声明

本文(道生一ChinaUnix博客专业IT技术博客.docx)为本站会员(b****6)主动上传,冰豆网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。 若此文所含内容侵犯了您的版权或隐私,请立即通知冰豆网(发送邮件至service@bdocx.com或直接QQ联系客服),我们立即给予删除!

道生一ChinaUnix博客专业IT技术博客.docx

1、道生一 ChinaUnix博客专业IT技术博客狗拿耗子 道生一 狗拿耗子第十一篇 道生一,一生二,二生三,三生万物,linux 的启动过程还真有点这个味道。从 kernel 的入口 stext 到 process 1 切换到用户模式执行,其中坎坎坷坷的漫长道路鲜为人知。如果 这条路有一千里,我们先来看看前面五十里到底是什么样子的。 u-boot 给 kernel 传递了一些参数后,跳转到 kernel 所在的起始地址开始运行。一般 来说 kernel 会被压缩成 zImage 格式的压缩包, 这个压缩包会自解压。 然后跳转到符号 stext 处执行,经过一段晦涩的汇编代码后,到达第一个 C 函

2、数 start_kernel(。本文介绍的正 是 start_kernel(之前发生的事情。 硬件环境仍然是那块 smdk_2410 的板子,不过所有代码均在 skyeye-1.2.8 上运行。 u-boot 版本为 1.3.4,linux 版本为 2.6.31,busybox 版本为 1.15.2,编译工具 为 eldk-2008.11.24。 本文主要参考网友 byte_x 所写arm linux 从入口到 start_kernel ,正所谓“闻道 有先后,术业有专攻” ,另“千江水有千江月” ,本文的视角主要从分析功能出发。仍然要感 谢网友 bytex 所做的工作,以及其他朋友们的分享。

3、 1、u-boot 的工作 rootfs 用的是 ramfs,依据building embedded linux systems用 busybox 生成 initramfs。 用 u-boot 加载 initramfs 压缩包到内存, 并告诉 kernel rootfs 的位置。 ramfs 与 ramdisk 是两种不同的 fs,前者出道时间晚,比后者先进。在 u-boot 的环境变量中的 initrd 的全称是 init ramdisk,在下面用 initrd=uInitramfs 来告诉 kernel rootfs 的位 置,是老瓶装新酒的行为。 1.1 mkimage $UBOOT_P

4、ATH/tools/mkimage -n linux-2.6.31 -A arm -O linux -T kernel -C none -a 0x30008000 -e 0x30008040 -d $KERNEL_PATH/arch/arm/boot/zImage $TFTP_PATH/uImage $UBOOT_PATH/tools/mkimage -n initramfs -A arm -O linux -T ramdisk -C gzip -a 0x30800000 -e 0x30800040 -d $BASE_PATH/initramfs.cpio.gz $TFTP_PATH/uIni

5、tramfs zImage 是自解压 kernel 压缩包,u-boot 在它前面增加 0x40 字节生成 uImage,用来记录自 己需要暂时保存的信息。同样 u-boot 在 initramfs 前面增加了 0x40 字节。 1.2 boot kernel setenv bootargs console=ttySAC0,115200 mem=64M initrd=0x30800040 1 狗拿耗子 tftp 0x30008000 uImage tftp 0x30800000 uInitramfs bootm 0x30008000 0x30800000 内存布局为: z zImage 被加载

6、到 0x30008040; z initramfs 压缩包被加载到 0x30800040; z parameter list(即 u-boot 的环境变量,格式可参考booting arm linux )被写到 0x30000100。 运行上下文为: z cpu 工作于 svc 模式,irq 与 fiq 被禁止; z mmu 与数据 cache 被关闭; z 指令 cache 可以打开; (可参考 z z z r0 为 0; r1 为 machine type; r2 为 parameter list 的地址。 parameter list: z console 用 ttySAC0; z ra

7、m 大小为 64M; z initramfs 压缩包位于 0x30800040 处。 2、zImage 自解压 zImage 由位置无关的自解压代码,以及压缩后的 kernel 链接而成。自解压代码解压 kernel 压缩包至 0x30008000 处,最后跳转到该位置运行。显然该地址对于不同的 ARM 芯片 是不相同的, 在 arch/arm/mach-s3c2410/Makefile.boot 可知 smdk_2410 的起始物理地址为 0x30008000。zImage 的生成与自解压过程挺复杂的,因为与 kernel 关系不大,这里就只介 绍这么多。 3、kernel 入口 参考链接脚

8、本 arch/arm/kernel/vmlinux.lds.S 可知,input secton *.text.head 被放 入位于 kernel 最前面的 output section .text.head 中。zImage 自解压代码最后跳转到 0x30008000 处执行, 即跳转到第一个 input section *.text.head 起始处执行。 另外 kernel 的程序入口为 stext。 . OUTPUT_ARCH(arm ENTRY(stext . SECTIONS 2 狗拿耗子 #ifdef CONFIG_XIP_KERNEL . = XIP_VIRT_ADDR(CON

9、FIG_XIP_PHYS_ADDR; #else . = PAGE_OFFSET + TEXT_OFFSET; #endif .text.head : _stext = .; _sinittext = .; *(.text.head . 而第一个 input section *text.head 位于 arch/arm/kernel/head.S,可见 kernel 的 程序入口 stext 正好是该 section 的起始地址。 . .section .text.head, ax .type ENTRY(stext msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | S

10、VC_MODE ensure svc mode and irqs disabled mrc p15, 0, r9, c0, c0 bl _lookup_processor_type movs r10, r5 beq _error_p bl _lookup_machine_type movs r8, r5 beq _error_a bl bl . _vet_atags _create_page_tables get processor id r5=procinfo r9=cpuid invalid processor (r5=0? yes, error p r5=machinfo invalid

11、 machine (r5=0? yes, error a stext, %function 4、struct proc_info_list 该结构体定义于 arch/arm/include/asm/Procinf.h,虽然被起名为 list 却不是 list, 称之为 proc_info 更为合理。 struct proc_info_list unsigned int unsigned int unsigned long unsigned long unsigned long cpu_val; cpu_mask; _cpu_mm_mmu_flags; _cpu_io_mmu_flags; _c

12、pu_flush; /* used by head.S */ /* used by head.S */ /* used by head.S */ 3 狗拿耗子 const char const char unsigned int const char struct processor *arch_name; *elf_name; elf_hwcap; *cpu_name; *proc; *user; *cache; struct cpu_tlb_fns *tlb; struct cpu_user_fns struct cpu_cache_fns ; 4.1 proc_info array 显然

13、不同的 cpu 有着不同的 proc_info 实例,这些实例分别被定义在不同的 section *.proc.info.init 中。链接脚本 vmlinux.lds.S 将它们组成了一个 proc_info array,并用 符号_proc_info_begin、_proc_info_end 分别指向 array 的起始、结束地址。 OUTPUT_ARCH(arm ENTRY(stext . SECTIONS . .init : . _proc_info_begin = .; *(.proc.info.init _proc_info_end = .; . /* Init code and

14、data */ 4.2 arm920t 的 proc_info arm920t 的 proc_info 实例化于 arch/arm/mm/proc-arm920.S,在本文中我们需要关心 它的四个域(field: z cpu_val 与 cpu_mask,是该实例的标识; z _cpu_mm_mmu_flags,用于初始化临时内核页表; z _cpu_flush,指向_arm920_setup(,该函数用于复位 cache 与 TLB。 .section .proc.info.init, #alloc, #execinstr .type .long .long _arm920_proc_inf

15、o,#object 0x41009200 0xff00fff0 _arm920_proc_info: 4 狗拿耗子 .long PMD_TYPE_SECT | PMD_SECT_BUFFERABLE | PMD_SECT_CACHEABLE | PMD_BIT4 | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ .long PMD_TYPE_SECT | PMD_BIT4 | PMD_SECT_AP_WRITE | PMD_SECT_AP_READ b _arm920_setup cpu_arch_name cpu_elf_name HWCAP_SWP | HWCA

16、P_HALF | HWCAP_THUMB cpu_arm920_name arm920_processor_functions v4wbi_tlb_fns v4wb_user_fns arm920_cache_fns v4wt_cache_fns _arm920_proc_info, . - _arm920_proc_info .long .long .long .long .long .long .long .long #else .long #endif .size #ifndef CONFIG_CPU_DCACHE_WRITETHROUGH 5、struct machine_desc 该

17、结构体定义于 arch/arm/include/asm/mach/Arch.h。它与 struct proc_info_list 非常类似,不同的 machine(processor 对应于 920t,machine 对应于 s3c2410)有着不同 的实例,这些实例组成了一个 array,链接脚本 vmlinux.lds.S 用符号_arch_info_begin、 _arch_info_end 分别指向该 array 的起始、结束地址。smdk2410 相应的实例定义在 arch/arm/mach-s3c2410/Mach-smdk2410.c 中。在本文中,我们只需要关心 arch nu

18、mber 即 可,它是相应实例的标识。 struct machine_desc /* * Note! The first four elements are used * by assembler code in head.S, head-common.S */ unsigned int unsigned int unsigned int nr; /* architecture number */ phys_io; /* start of physical io */ io_pg_offst; /* byte offset for io * page tabe entry */ 5 狗拿耗子

19、const char unsigned long unsigned int unsigned int unsigned int unsigned int unsigned int unsigned int void *name; /* architecture name */ */ */ */ */ */ */ */ boot_params; /* tagged list video_start; /* start of video RAM video_end; /* end of video RAM /* never has lp0 /* never has lp1 /* never has

20、 lp2 /* soft reboot reserve_lp0 :1; reserve_lp1 :1; reserve_lp2 :1; soft_reboot :1; (*fixup(struct machine_desc *, struct tag *, char *, struct meminfo *; void void void ; (*map_io(void;/* IO mapping function (*init_irq(void; *timer; /* system tick timer */ */ struct sys_timer (*init_machine(void; M

21、ACHINE_START(SMDK2410, SMDK2410 /* TODO: request a new identifier and switch * to SMDK2410 */ /* Maintainer: Jonas Dietsche */ .phys_io = S3C2410_PA_UART, .io_pg_offst = (u32S3C24XX_VA_UART 18 & 0xfffc, .boot_params = S3C2410_SDRAM_PA + 0x100, .map_io = smdk2410_map_io, .init_irq = s3c24xx_init_irq,

22、 .init_machine = smdk2410_init, .timer MACHINE_END = &s3c24xx_timer, 6、临时内核页表 6.1 section 临时内核页表只用一级分页, 页大小为 1M, s3c2410 称之为 section。 一级页表需要 4096 个表项,每个表项需要 4 个字节,整个一级页表共占用 16k 字节。每个表项最后两个 bit 为 0b10,表示使用一级分页。 6.2 几个重要的宏定义 z z z PAGE_OFFSET,内核起始线性地址 0xc0000000; PHYS_OFFSET,内核起始物理地址 0x30000000; TEXT_

23、OFFSET,内核入口偏移 0x8000; 6 狗拿耗子 z z KERNEL_RAM_VADDR,内核入口线性地址 0xc0008000; KERNEL_RAM_PADDR,内核入口物理地址 0x30008000。 6.3 内核页表的位置 内核页表位于线性地址 0xc0004000、物理地址 0x30004000 处。变量 swapper_pg_dir 记录着它的线性地址,head.S 给出了 swapper_pg_dir 的定义。这是一个重要的变量,但在 本文中不会引用它。 .globl swapper_pg_dir .equ swapper_pg_dir, KERNEL_RAM_VADD

24、R - 0x4000 6.4 更新内核页表表项 设符号 pg_tbl 指向内核页表起始物理地址 (即 0x30004000) , 待映射物理地址为 p_addr, 线性地址为 v_addr,则有: z z z section 起始物理地址 sect_p_addr = p_addr & 0xfff00000; 待更新表项索引 entry_index = (v_addr & 0xfff00000 20; 待更新表项起始物理地址为 entry_p_addr = pg_tbl + entry_index * 4。 表项内容 entry_content = sect_p_addr | PROCINFO_

25、MM_MMUFLAGS,其中后者为 struct proc_info_list 的域_cpu_mm_mmu_flags 的值。 将长度为四个字节的 entry_content 写入到 entry_p_addr 即可完成内核页表表项的更新。 7、cache 7.1 三种类型的 cache 假设 cache 共有 32 line,每个 line 包含 16 bytes。ram 中的数据以 line 为单位映射 到 cache 中,下文中用 ram n 表示 ram 中(16*n到(16*n+15 bytes,称之为 ram 块,假设 共包含 1024 个 ram 块。 z Direct Mappe

26、d Cache: ram (32*m+n映射到 line n,其中 m、n 取 0、1、2。即 ram 0、32、64 映射到 line 0,ram 1、33、65 映射到 line 1,以此类推。ram N 只能映射 到某个 line 中,并与其它(1024/32-1个 ram 块竞争 line (N%32。 Fully Associative Cache: ram N 可以映射到任何一个 line,并与所有其它的 ram 块 竞争。 N-Way Set Associative Cache: 将所有 line 分成大小为 N 的 set,即 line 0、1、N-1 为 set 0,line

27、 N、N+1、2N-1 为 set 1,以此类推。ram N 可以映射到某个 set,并 与其它(1024/32*N-1个 ram 块竞争同一个 set。 z z 7 狗拿耗子 最后一种类型的 cache 是前两种的中和产物,令 set 大小为 1,就变成了 Direct Mapped Cache,令 set 大小为 32,就变成了 Fully Associative Cache。这是从工作效率与工作时 间两个方面综合考虑后,设计出来的 cache。 7.2 cache 的回写机制 z Write through,cpu 待写入的 arm 块已经映射到了 cache,则直接写入 cache 相

28、应的 line,并同时写入 ram 块。 Write back, cpu 待写入的 arm 块已经映射到了 cache, 则直接写入 cache 相应的 line, 并做上标记。不是立即写入 ram 块,而是在一个合适的时候再将数据写入 ram 块,比如 说在相应的 line 被其它 ram 块映射时。 z 8、使能 MMU 在使能 MMU 前流水线按物理地址寻址, 在使能 MMU 生效之后流水线按线性地址寻址, 需 要通过 MMU 获得相应的地址或数据。另外在使能 MMU 之前的代码必须是“位置无关” (PIC) 的,必须按相对地址寻址,即相对于 pc 寻址;如果按直接地址寻址,则相应地址是

29、链接器 重定位后的地址,即线性地址,必然导致流水线运行异常。 另外 arm902t 采用的是五级流水线,使能 MMU 指令的下两条指令的取指会发生在使能 MMU 生效之前。 综合考虑这两点,在使能 MMU 之前采用“flat translation”来映射 linux 内核前 1M 代码,使其线性地址与物理地址相等,显然使能 MMU 的代码位于 linux 内核的前 1M 之内。 这样流水线按相对地址寻址得到的地址与数据,以及取指得到的指令,均是所期望的。 9、process 0 process 0 是 kernel 的第一个进程,也是所有进程的“祖先” ,是它创建了 process 1, 而

30、 process 1 创建了其它所有进程。直接用understanding the linux kernel中的原文 来介绍吧: The ancestor of all processes, called process 0, the idle process, or, for historical reasons, the swapper process, is a kernel thread created from scratch during the initialization phase of Linux (see Appendix A. This ancestor process

31、 uses the following statically allocated data structures (data structures for all other processes are dynamically allocated: A process descriptor stored in the init_task variable, which is initialized by the INIT_TASK macro. A thread_info descriptor and a Kernel Mode stack stored in the init_thread_

32、union variable and initialized by the INIT_THREAD_INFO macro. The following tables, which the process descriptor points to: o init_mm 8 狗拿耗子 o o o o init_fs init_files init_signals init_sighand The tables are initialized, respectively, by the following macros: o o o o o INIT_MM INIT_FS INIT_FILES INIT_SIGNALS INIT_SIGHAND The master kernel Page Global Directory stored in swapper_pg_dir (see the section Kernel Page Tables in Chapter 2. 在本文中我们只需要关心两个地方: z 内核

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1