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

加入VIP,免费下载
 

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

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

下载须知

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

版权提示 | 免责声明

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

linuxmips启动分析.docx

1、linuxmips启动分析linux-mips启动分析 (1)系统加电起动后,MIPS 处理器默认的程序入口是0xBFC00000,此地址在无缓存的KSEG1的地址区域内,对应的物理地址是 0x1FC00000,即CPU从0x1FC00000开始取第一条指令,这个地址在硬件上已经确定为FLASH的位置,Bootloader将 Linux 内核映像拷贝到 RAM 中某个空闲地址处,然后一般有个内存移动操作,目的地址在 arch/mips/Makefile 内指定: load-$(CONFIG_MIPS_PB1550) += 0xFFFFFFFF80100000,则最终bootloader定会将内

2、核移到物理地址 0x00100000 处。上面Makefile 里指定的的 load 地址,最后会被编译系统写入到 arch/mips/kernel/vmlinux.lds 中:OUTPUT_ARCH(mips)ENTRY(kernel_entry)jiffies = jiffies_64;SECTIONS. = 0xFFFFFFFF80100000;/* read-only */_text = .; /* Text and read-only data */.text : *(.text).这个文件最终会以参数 -Xlinker -script -Xlinker vmlinux.lds 的形

3、式传给 gcc,并最终传给链接器 ld 来控制其行为。ld 会将 .text 节的地址链接到 0xFFFFFFFF80100000 处。关于内核 ELF 文件的入口地址(Entry point),即 bootloader 移动完内核后,直接跳转到的地址,由ld 写入 ELF的头中,其会依次用下面的方法尝试设置入口点,当遇到成功时则停止:a. 命令行选项 -e entryb. 脚本中的 ENTRY(symbol)c. 如果有定义 start 符号,则使用start符号(symbol)d. 如果存在 .text 节,则使用第一个字节的地址。e. 地址0注意到上面的 ld script 中,用 EN

4、TRY 宏设置了内核的 entry point 是 kernel_entry,因此内核取得控制权后执行的第一条指令是在 kernel_entry 处。linux 内核启动的第一个阶段是从 /arch/mips/kernel/head.s文件开始的。而此处正是内核入口函数kernel_entry(),该函数定义在 /arch/mips/kernel/head.s文件里。kernel_entry()函数是体系结构相关的汇编语言,它首先初始化内核堆栈段,来为创建系统中的第一个进程进行准备,接着用一段循环将内核映像的未初始化数据段(bss段,在_edata和_end之间)清零,最后跳转到 /init/

5、main.c 中的 start_kernel()初始化硬件平台相关的代码。NESTED(kernel_entry, 16, sp) # kernel entry point声明函数 kernel_entry,函数的堆栈为 16 byte,返回地址保存在 $sp 寄存器中。声明函数入口#define NESTED(symbol, framesize, rpc) .globl symbol; .align 2; .type symbol,function; .ent symbol,0; symbol: .frame sp, framesize, rpc汇编伪指令 frame 用来声明堆栈布局。它有

6、三个参数: 1)第一个参数 framereg:声明用于访问局部堆栈的寄存器,一般为 $sp。 2)第二个参数 framesize:申明该函数已分配堆栈的大小,应该符合 $sp framesize 原来的 $sp。 3)第三个参数 returnreg:这个寄存器用来保存返回地址。 kernel_entry_setup # cpu specific setup这个宏一般为空的,在 include/asm-mips/mach-generic/kernel-entry-init.h 文件中定义。某些MIPS CPU需要额外的设置一些控制寄存器,和具体的平台相关,一般为空宏;某些多核MIPS,启动时所有

7、的core的入口一起指向 kernel_entry,然后在该宏里分叉,boot core 继续往下,其它的则不停的判断循环,直到boot core 唤醒之 setup_c0_status_pri设置 cp0_status 寄存器 .macro setup_c0_status_pri#ifdef CONFIG_64BIT setup_c0_status ST0_KX 0#else setup_c0_status 0 0#endif .endm ARC64_TWIDDLE_PC除非 CONFIG_ARC64,否则为空操作#ifdef CONFIG_MIPS_MT_SMTC mtc0 zero, C

8、P0_TCCONTEXT_bss_start mfc0 t0, CP0_STATUS ori t0, t0, 0xff1f xori t0, t0, 0x001e mtc0 t0, CP0_STATUS#endif /* CONFIG_MIPS_MT_SMTC */宏定义 CONFIG_MIPS_MT_SMTC 是使用多核的 SMTC Linux 时定义的。一般情况下不考虑。MIPS已经开发出 SMP Linux的改进版,叫做SMTC(线程上下文对称多处理) Linux。SMTC Linux能理解轻量级 TC 的概念,并能因此减少某些与SMP Linux相关的开销。 PTR_LA t0, _b

9、ss_start # clear .bss LONG_S zero, (t0) PTR_LA t1, _bss_stop - LONGSIZE1: PTR_ADDIU t0, LONGSIZE LONG_S zero, (t0) bne t0, t1, 1b清除 BSS 段,清 0。变量 _bss_start 和 _bss_stop 在连接文件arch/mips/kernel/vmlinux.lds 中定义。 LONG_S a0, fw_arg0 # firmware arguments LONG_S a1, fw_arg1 LONG_S a2, fw_arg2 LONG_S a3, fw_a

10、rg3把 bootloader 传递给内核的启动参数保存在 fw_arg0,fw_arg1,fw_arg2,fw_arg3 变量中。变量 fw_arg0 为内核参数的个数,其余分别为字符串指针,为 XXXX 的格式。 MTC0 zero, CP0_CONTEXT # clear context register清除 CP0 的 context register,这个寄存器用来保存页表的起始地址。 PTR_LA $28, init_thread_union初始化 $gp 寄存器,这个寄存器的地址指向一个 union,THREAD_SIZE 大小,最低处是一个thread_info 结构 PTR_

11、LI sp, _THREAD_SIZE - 32 PTR_ADDU sp, $28设置 $sp 寄存器,堆栈指针。 $sp = (init_thread_union 的地址) _THREAD_SIZE - 32的得出 $sp 指向这个 union 结构的结尾地址 32 字节地址。 set_saved_sp sp, t0, t1把 这个 CPU 核的堆栈地址 $sp 保存到 kernelspNR_CPUS 数组。 如果定义了 CONFIG_SMP 宏,即多 CPU 核。 .macro set_saved_sp stackp temp temp2#ifdef CONFIG_MIPS_MT_SMTC

12、 mfc0 temp, CP0_TCBIND#else MFC0 temp, CP0_CONTEXT#endif LONG_SRL temp, PTEBASE_SHIFT LONG_S stackp, kernelsp(temp) .endm如果没有定义 CONFIG_SMP 宏,单 CPU 核。 .macro set_saved_sp stackp temp temp2 LONG_S stackp, kernelsp .endm变量 kernelsp 的定义,在 arch/mips/kernel/setup.c 文件中。unsigned long kernelspNR_CPUS;把 这个 C

13、PU 核的堆栈地址 $sp 保存到 kernelspNR_CPUS 数组。 PTR_SUBU sp, 4 * SZREG # init stack pointer j start_kernel END(kernel_entry)最后跳转到 /arch/mips/kernel/main.c 中的 start_kernel()初始化硬件平台相关的代码。这个 init_thread_union 变量在 arch/mips/kernel/init_task.c 文件中定义。union thread_union init_thread_union _attribute_(_section_(.data.

14、init_task), _aligned_(THREAD_SIZE) = INIT_THREAD_INFO(init_task) ;问题: 1)这个 init_thread_union 结构体指针是怎么初始化的?linux-mips启动分析(2) linux 内核启动的第一个阶段是从 /arch/mips/kernel/head.s文件开始的。而此处正是内核入口函数kernel_entry(),该函数定义在 /arch/mips/kernel/head.s文件里。kernel_entry()函数是体系结构相关的汇编语言,它首先初始化内核堆栈段,来为创建系统中的第一个进程进行准备, 接着用一段循

15、环将内核映像的未初始化数据段(bss段,在_edata和_end之间)清零, 最后跳转到 /arch/mips/kernel/main.c 中的 start_kernel()初始化硬件平台相关的代码。下面讲述 start_kernel() 函数。asmlinkage void _init start_kernel(void) char * command_line; extern struct kernel_param _start_param, _stop_param; 定义了核的参数数据结构 smp_setup_processor_id(); 设置 SMP 多核的 CPU 核的 ID 号,

16、单核不进行任何操作,我们不关心。 unwind_init(); 在 MIPS 体系结构中,这个函数是个空函数(可能调用setup_arch,配置核的相关函数) lockdep_init(); 初始化核依赖关系哈希表。 local_irq_disable(); 关闭当前 CPU 核的中断 early_boot_irqs_off(); 通过一个静态全局变量 early_boot_irqs_enabled 来帮助我们调试代码, 通过这个标记可以帮助我们知道是否在“early bootup code”, 也可以通过这个标志警告是否有无效的中断打开。 和 early_boot_irqs_on() 函数配

17、置使用,参考下面。 early_init_irq_lock_class(); 每一个中断都有一个 IRQ 描述符 ( struct irq_desc )来进行描述。 这个函数的主要作用是设置所有的 IRQ 描述符 ( struct irq_desc )的锁是统一的锁, 还是每一个 IRQ 描述符 ( struct irq_desc )都有一个小锁。 参考linux-mips启动分析(2-1)。 lock_kernel(); 获取大内核锁,这种大内核锁锁定整个内核。 tick_init(); 如果没有定义 CONFIG_GENERIC_CLOCKEVENTS 宏定义,则这个函数为空函数, 如果定

18、义了这个宏,这执行初始化 tick 控制功能,注册 clockevents 的框架。 boot_cpu_init(); 对于 CPU 核的系统来说,设置第一个 CPU 核为活跃 CPU 核。 对于单 CPU 核系统来说,设置 CPU 核为活跃 CPU 核。 参考linux-mips启动分析(2-1)。 page_address_init(); 当定义了 CONFIG_HIGHMEM 宏,并且没有定义 WANT_PAGE_VIRTUAL 宏时,非空函数。 其他情况为空函数。 参考linux-mips启动分析(2-1)。 printk(KERN_NOTICE); printk(linux_bann

19、er); 输出打印版本信息。 setup_arch(&command_line); 每种体系结构都有自己的 setup_arch() 函数,这些是体系结构相关的。 如何确定编译那个体系结构的 setup_arch() 函数呢? 主要由 linux 源码树顶层 Makefile 中 ARCH 变量来决定的。 例如: MIPS 体系结构的。 SUBARCH := mips ARCH ?= $(SUBARCH) setup_command_line(command_line); 保存未改变的 comand_line 到字符数组 static_command_line 中。 保存 boot_comma

20、nd_line 到字符数组 saved_command_line 中。 参考linux-mips启动分析(2-1)。 unwind_setup(); 空函数。 setup_per_cpu_areas(); 如果没有定义 CONFIG_SMP 宏,则这个函数为空函数。 如果定义了 CONFIG_SMP 宏, 则这个 setup_per_cpu_areas() 函数给每个CPU分配内存,并拷贝 .data.percpu 段的数据。 参考linux-mips启动分析(2-1)。 如果没有定义 CONFIG_SMP 宏,则这个函数为空函数。 如果定义了 CONFIG_SMP 宏,这个函数 smp_pr

21、epare_boot_cpu(); sched_init(); 核心进程调度器初始化,调度器的初始化优先于任何中断的建立(包括 timer 中断)。 并且初始化进程 0 ,即 idle 进程,但是并没有设置 idle 进程的 NEED_RESCHED 标志, 以完成内核剩余的启动部分。 preempt_disable(); 进制内核的抢占。使当前进程的 struct thread_info 结构 preempt_count 成员的值增加 1。 参考linux-mips启动分析(2-1)。 建立各个节点的管理区的 zonelist,便于分配内存的 fallback 使用。 这个链表的作用: 这个

22、链表是为了在一个分配不能够满足时可以考察下一个管理区来设置了。 在考察结束时,分配将从 ZONE_HIGHMEM 回退到 ZONE_NORMAL, 在分配时从 ZONE_NORMAL 退回到 ZONE_DMA 就不会回退了。 build_all_zonelists(); 参考linux-mips启动分析(2-1)。 page_alloc_init(); 在 MIPS 体系结构下,这个函数已经在 arch_mem_init() 函数中调用了一次。 这个函数的具体分析详细分析,请看linux-mips启动分析(4)。 所以这个函数直接返回。 parse_early_param(); 打印 linux 启动命令行参数。 printk(KERN_NOTICE Kernel command line: %sn, boot_command_line); 这个函数在 linux-mips启动分析(4)文件有分析,可以参考。 这个函数的意思对 linux 启动命令行参数进行再分析和处理。 这两个变量 _start_param 和 _stop_param 在 链接脚本 arch/mips/kernel/vmlinux.lds 中定义。 最后一个参数为,当不能够识别 linux 启动命令行参数时,调用

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

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