1000字范文,内容丰富有趣,学习的好帮手!
1000字范文 > OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel

OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel

时间:2018-11-24 11:56:30

相关推荐

OK6410A 开发板 (八) 6 linux-5.11 OK6410A 详细解析 从 u-boot 的 theKernel 到 linux的 start_kernel

之前写过 linux-3.0.1 ok6410a 的启动流程, 从 arch/arm/boot/compressed/head.S 到 mm_init 完成

回忆 linux-3.0.1 ok6410a 的启动流程

这里讲述了 内存镜像的生成过程以及压缩/无压缩镜像启动的不同打印

压缩内核 会打印 Uncompressing Linux… done, booting the kernel ,再打印 Booting Linux on physical CPU

非压缩内核直接打印 Booting Linux on physical CPU

这里讲述了 压缩内核的入口(arch/arm/boot/compressed/head.S 中的start )及出口(到非压缩内核)(mov pc, r4 @ call kernel) 和 非压缩内核的入口(arch/arm/kernel/head.S 中的 stext)及出口(start_kernel) (b start_kernel)

这里简述了 arm压缩内核的 启动流程

这里简述了 arm非压缩内核的启动流程

这里 简述了 arm64 和 risc-v 架构的架构相关启动流程

这里 简述了各种地址(物理地址 虚拟地址 链接地址 运行地址)概念

这里 讲述了 uImage的头部

这里 从目录角度讲述了 目录在启动过程中扮演的角色

这里 讲述了 从 start 到 start_kernel 的过程中的内存分布

这里 讲述了 过程中的一些与内存相关的符号

这里 讲述了 过程中的一些与内存相关的内核配置

简述 linux-5.11 OK6410A 启动流程

1 从u-boot 到 arch/arm/boot/compressed/head.S 中的start
打印信息

bootm 0x50008000## Booting kernel from Legacy Image at 50008000 ...Image Name: Linux-5.11.0-00006-g1829225a7faImage Type: ARM Linux Kernel Image (uncompressed)Data Size: 2913264 Bytes = 2.8 MiBLoad Address: 50008000Entry Point: 50008000Verifying Checksum ... OKLoading Kernel ImageStarting kernel ...Booting Linux on physical CPU 0x0

流程

u-boot 1. 将 zImage 放置到 500080002. 设置 r0 为 03. 设置 r1 为 1626 // 这个是 smdk6410的board id4. 设置 r2 为 atags的 地址 0x50000100 , 此前 设置 了 setup_start_tag setup_commandline_tag setup_memory_tags setup_end_tag , 这个有 152 字节5. 并 将pc 置为 0x50008000linux0x50008000 为 arch/arm/boot/compressed/head.S 中的start // 需要去分析 arch/arm/boot/compressed/vmlinux.lds

2 从 arch/arm/boot/compressed/head.S 中的start 到 arch/arm/kernel/head.S 中的 stext
运行前的状态

内存 : Image : 0x50008000 - 0x502D12C7 2.8MBatags : 0x50000100 - 0x50000197 152字节cpu寄存器 : r0 : 0r1 : 1626 r2 : 0x50000100pc : 0x50008000 协处理器寄存器 :mmu offdcache officache off

没有关注CONFIG_ARM_VIRT_EXT,TODO

流程

简述 : 大概就是 利用 解压代码A 将 arch/arm/boot/compressed/piggy_data 解压 为 Image过程中涉及到了 很多事情1. 解压后的 Image 起始位置的确定2. 解压后的 Image 是否与 当前kernel运行空间 重叠如果重叠要搬运当前kernel要处理搬运后的符号链接问题(解压代码A的符号链接)3. 解压核心代码 decompress_kernel可直接 加载 运行 Image,从而忽略这个过程, 与加载 uImage并运行 产生的效果是一样的效果 : arch/arm/kernel/head.S 中的 stext 运行时的状态

arch/arm/boot/compressed/head.S184 .section ".start", "ax"...235 mov r7, r1@ save architecture ID236 mov r8, r2@ save atags pointer...250 not_angel: // 解决 Booting from Angel 的问题251 safe_svcmode_maskall r0 // 关闭IRQ与FIQ252 msr spsr_cxsf, r9 @ Save the CPU boot mode in SPSR...288 add r4, r4, #TEXT_OFFSET // r4 中的值 0x50008000 , 为 解压后 Image的 起始位置...305 blcs cache_on // 开cache...307 restart: adr r0, LC1 // 如果 会 overwrite,则进行relocate之后,会跳到这里,然后继续往下再次判断是否需要 overwrite...313 get_inflated_image_size r9, r10, lr // 得到 Image 的大小...435 add r10, r10, #16384 // 计算当前zImage是否与解压后的Image有重叠.436 cmp r4, r10 // 如果有重叠,则 重定位 zImage437 bhs wont_overwrite---------------------------------------------------------- relocate自身 的开始...481 sub r9, r6, r5@ size to copy...491 #ifdef DEBUG...503 dbgkc r5, r6, r10, r9 // 打印了 C:0x500080C0-0x502D1240->0x5088F000-0x50B58180...506 #endif...513 badr r0, restart514 add r0, r0, r6515 mov pc, r0---------------------------------------------------------- relocate自身 的结束,会跳转到 restart 标号,而不是往下走517 wont_overwrite: // 重定位第一步(代码搬运)完成,或者是没有重定位,直接跳转到这里 , 本例是 重定位完成...535 orrs r1, r0, r5536 beq not_relocated ...551* Relocate all entries in the GOT table. // 重定位第二步,解决符号地址问题...563 /* bump our bss pointers too */ // 重定位第三步,清空bss段...582 not_relocated: mov r0, #0583 1:str r0, [r2], #4 @ clear bss...610 bl decompress_kernel// 解压zImage 为 Image...616 bl cache_clean_flush617 bl cache_off...623 bne __enter_kernel@ boot kernel directly1410 __enter_kernel:...1414 ARM( mov pc, r4) @ call kernel// 调用 Image的 arch/arm/kernel/head.S 中的 stext

打印相关

C:0x500080C0-0x502D1240->0x5088F000-0x50B58180Uncompressing Linux... done, booting the kernel. 上述打印需要 内核配置支持CONFIG_DEBUG_KERNEL=yCONFIG_DEBUG_LL=yCONFIG_DEBUG_UNCOMPRESS=y

地址相关

zImage 在解压缩前 进行了一次搬移 从 0x500080C0-0x502D1200 到 0x5088F000-0x50B58140zImage 被 解压缩 为 Image,Image在哪里?在 0x5088F000 前面,具体地址为0x50008000 - 0x50008000 + 8938824(Image的大小) -1 即0x50008000 - 0x5088E547-rwxrwxr-x 1 suws suws 8938824 Apr 21 14:53 arch/arm/boot/Image

3 从 arch/arm/kernel/head.S 中的 stext 到 init/main.c 中的 start_kernel
运行前的状态

内存 : Image : 0x50008000 - 0x5088E547 8.6Matags : 0x50000100 - 0x50000197 152字节cpu寄存器 : r0 : 0r1 : 1626 r2 : 0x50000100pc : 0x50008000协处理器寄存器 :mmu offdcache officache off

流程

arch/arm/kernel/head.S77 ENTRY(stext)...89safe_svcmode_maskall r9...92bl __lookup_processor_type@ r5=procinfo r9=cpuid...106adr_l r8, _text @ __pa(_text) 107sub r8, r8, #TEXT_OFFSET @ PHYS_OFFSET...116bl __vet_atags...123bl __create_page_tables...144ldr r13, =__mmap_switched @ address to jump to after...151mov r8, r4 @ set TTBR1 to swapper_pg_dir// r8 中值 为 50004000 , r4 中的值 也为 50004000 ...153ldr r12, [r10, #PROCINFO_INITFUNC]154add r12, r12, r10155ret r12// 跳转到 arch/arm/mm/proc-v6.S 中的 __v6_setup ,并返回156 1: b __enable_mmu// 跳转到 __enable_mmu...157 ENDPROC(stext)

arch/arm/kernel/head.S420 __enable_mmu:...439mcr p15, 0, r5, c3, c0, 0 @ load domain access register440mcr p15, 0, r4, c2, c0, 0 @ load page table pointer // 将 页表基址(50004000) 告知 mmu ...442b __turn_mmu_on// 跳转到 __turn_mmu_on443 ENDPROC(__enable_mmu)461 ENTRY(__turn_mmu_on)...468mov r3, r13469ret r3// 跳转到 __mmap_switched 470 __turn_mmu_on_end:471 ENDPROC(__turn_mmu_on)

arch/arm/kernel/head-common.S77 __mmap_switched:...106bl __memset @ clear .bss...108ldmia r4, {r0, r1, r2, r3} 109str r9, [r0] @ Save processor ID110str r7, [r1] @ Save machine type111str r8, [r2] @ Save atags pointer...118b start_kernel// 跳转到 start_kernel

重点函数解析 __create_page_tables

__create_page_tablesClear the swapper page table // 16KB 空间 即 4K个页表(1个页表4Byte) 清0,1个页表map 1MB虚拟地址 , 正好 Map 4GB虚拟地址addr value50004000050004004050004008 05000400c050004010 0...50007ffc0Create identity mapping to cater for __enable_mmu // __turn_mmu_onaddr value5000540050100c0eMap our RAM from the start to the end of the kernel .bss section.// 9MB, 因为 我们的 Image 为 8.6M ,不足 9个MBaddr value5000700050000c0e5000700450100c0e5000700850200c0e5000700c50300c0e5000701050400c0e5000701450500c0e5000701850600c0e5000701c50700c0e5000702050800c0eThen map boot params address in r2 if specifiedaddr value50007fe0 50000c0e50007fe4 50100c0e// 一旦开启 mmu , 多了虚拟地址 ,对应的虚拟地址为 500x xxxx__enable_mmuC00x xxxx kernelff8x xxxx atags10 0000 是 1MB页表的含义:50000c0eSection base address : 500 00000SectionB:1C:1XN:0Domain:0000// 表明 属于 domain0 , D0 IMP:0AP:11TEX:000APX:0S:0nG:0

重点过程解析 虚拟地址和连接地址一致问题

__turn_mmu_on在 非压缩内核启动流程中重定位前, 访问 全局符号 时,因为全局符号是链接地址,所以要将链接地址转换为运行地址(运行的物理地址)重定位技术: MMU重定位后, 访问全局符号 时,因为全局符号时虚拟地址,MMU自动将虚拟地址转换为运行地址,直接给出(指令或数据)而 MMU 开启前, 创建了 三组页表,其中对 整个 Image 所在内存的映射,做出来的 start_kernel 虚拟地址 和 start_kernel 的链接地址 是一样的不是因为巧合,是必须这么做.下面看一下 链接地址的生成过程A(决定了链接地址) 和 页表的创建过程B(决定了虚拟地址)A:arch/arm/kernel/vmlinux.lds10 . = ((0xC0000000)) + 0x00008000; 11 .head.text : {12 _text = .; arch/arm/kernel/vmlinux.lds.S50. = PAGE_OFFSET + TEXT_OFFSET; 51.head.text : {52 _text = .;arch/arm/include/asm/memory.h24 #define PAGE_OFFSETUL(CONFIG_PAGE_OFFSET)include/generated/autoconf.377 #define CONFIG_PAGE_OFFSET 0xC0000000arch/arm/Makefile141 textofs-y := 0x00008000238 TEXT_OFFSET := $(textofs-y)B:arch/arm/kernel/head.S232/*233* Map our RAM from the start to the end of the kernel .bss section. 234*/ 235add r0, r4, #PAGE_OFFSET >> (SECTION_SHIFT - PMD_ORDER) // r4 = 50004000 , r0 = 50007000// C0008000 的虚拟地址和 50004000的页表基址决定了 必须在 50007000 写页表 236 237ldr r6, =(_end - 1) // _end : c08c413c238orr r3, r8, r7 // 计算写入的值(页表描述符) ,值为 50000c0e// 这个值决定了 该表为 section表// 索引该页表时,物理地址为 0x50000000 - 0x50100000 239add r6, r4, r6, lsr #(SECTION_SHIFT - PMD_ORDER) // 计算 末位地址// 此时已经准备好 240 1: str r3, [r0], #1 << PMD_ORDER // 写入241add r3, r3, #1 << SECTION_SHIFT // 重新计算写入的值(页表描述符) 242cmp r0, r6 // 比较写入的地址243bls 1b // 地址不同,执行循环arch/arm/include/asm/pgtable-2level.h95 #define SECTION_SHIFT20arch/arm/kernel/head.S44 #define PG_DIR_SIZE 0x400045 #define PMD_ORDER 2

重点函数解析 __mmap_switched

__mmap_switchedarch/arm/kernel/head-common.S68 * The following fragment of code is executed with the MMU on in MMU mode,69 * and uses absolute addresses; this is not position independent....71 * r0 = cp#15 control register (exc_ret for M-class) // 用来 mcr p15, 0, r0, c1, c0, 0 @ write control reg (arch/arm/kernel/head.S L476)72 * r1 = machine ID73 * r2 = atags/dtb pointer74 * r9 = processor ID...76__INIT77 __mmap_switched:7879mov r7, r1// 将 machine id 放入 r7 , 值为162680mov r8, r2// 将 atags pointer 放入 r8 , 值为 0xC0000100 (虚拟地址)81mov r10, r0// 将 ??? 放入 r1083adr r4, __mmap_switched_data// 将 __mmap_switched_data 的地址放入 r484mov fp, #0 // 将 0 放入 r11101 ARM( ldmia r4!, {r0, r1, sp} )// 将内存中的数据加载到 寄存器中// 将 __bss_start 放入 r0 , 该符号为连接符号,在 System.map 查到地址// 将 __bss_stop 放入 r1// 将 init_thread_union + THREAD_START_SP 放入 sp...104sub r2, r1, r0// r2 = r1 - r0, 计算 .bss段 的长度 , 0x00035BF4105mov r1, #0// 将 0 放入 r1 中106bl __memset @ clear .bss// 此时r0为__bss_start,r1为0,r2为长度,调用 __memset 来 clear bss107108ldmia r4, {r0, r1, r2, r3} // 将内存中的数据加载到 寄存器中// 将 processor_id 放入 r0// 将 __machine_arch_type 放入 r0// 将 __atags_pointer 放入 r2// 将 cr_alignment 放入 r3109str r9, [r0] @ Save processor ID // 将r9中的值 放入 以r0中的值为地址的 地址中 ,赋值 unsigned int processor_id110str r7, [r1] @ Save machine type// 将r7中的值 放入 以r1中的值为地址的 地址中 ,赋值 unsigned int __machine_arch_type111str r8, [r2] @ Save atags pointer // 将r8中的值 放入 以r2中的值为地址的 地址中 ,赋值 unsigned int __atags_pointer __initdata112cmp r3, #0// 比较 r3中的值 与 0 , r3 中存放的值 的值 就是 cr_alignment 变量初始化的值 为 0 113strne r10, [r3] @ Save control register values // 不相等,则 将r10中的值 放入 以r3中的值为地址的 地址中 ,赋值 cr_alignment...117mov lr, #0 // 将 0 放入 lr 中118b start_kernel // 跳转到 start_kernel , 不修改 lr...122.type __mmap_switched_data, %object 123 __mmap_switched_data:...133.long __bss_start @ r0134.long __bss_stop@ r1135.long init_thread_union + THREAD_START_SP @ sp 136 137.long processor_id @ r0 138.long __machine_arch_type@ r1 139.long __atags_pointer @ r2 ...141.long cr_alignment @ r3 ...146.size __mmap_switched_data, . - __mmap_switched_data

b start_kernel 运行前的状态

b start_kernel 运行前的状态cpu寄存器r0 : r1 : r2 : r3 :r4 : r5 : r6 :r7 : r8 :r9 :r10 :r11 : r12 : r13 : init_thread_union + THREAD_START_SP // init_thread_union + (((1 << 12) << 1) - 8) // 0xc0800000 + (十进制)8184 = 0xC0801FF8r14 : 0pc : start_kernel 的虚拟地址 0xc07009f0spsr : 0x600001d3cpsr : 0x200001d3Supervisor ModeARM Instruction SetIRQ disabledFIQ disabledDisables imprecise data abortslittle endian运行非cpsr相关指令时会修改的位dsp指令GE[3:0] bit[19:16]在ARMv6中,SIMD指令使用位[19:16] 作为结果的单个字节或半字的大于或等于(GE)标志。您可以使用这些标志来控制以后的SEL指令Q bit[27] 在ARMv5及更高版本的E变体中,CPSR的位[27]的Q标志称为Q标志,用于指示在某些面向DSP的指令中是否发生了溢出和/或饱和。arm指令Nbit[31] 负Z bit[30] 零C bit[29] 进位V bit[28] 溢出协处理器cp15寄存器cp15 Register 1: Control register : 0x00c5387dmmu : enabledAlignment fault checking: disabledDcache: enabledwrite buffer: enabledThe use of the S and R bits is deprecated in VMSAv6Icache : enabledNormal replacement strategysubpages : disabledcp15 Register 2: Translation table base : 0x50004000 页表基址寄存器,存放的是物理地址cp15 Register 3: Domain access control : 0x00000051D0: 01: Client Accesses are checked against the access permission bits in the TLB entryD1 : 00: No access Any access generates a domain faultD2: 01: Client Accesses are checked against the access permission bits in the TLB entryD3 : 01 : Client Accesses are checked against the access permission bits in the TLB entryD4 : 00: No access Any access generates a domain fault...cp15 Register 7: cache management functionsinstr_sync : mcr p15, 0, r0, c7, c5, 4// Flush prefetch buffer (PrefetchFlush)// Instruction barrier内存物理内存页表 : 物理地址: 0x50005400 - 0x50005403 __turn_mmu_on页表 : 物理地址: 0x50007000 - 0x50007023 Image页表 : 物理地址: 0x50007fe0 - 0x50007fe7 atagsImage : 物理地址: 0x50008000 - 0x5088E547 8.6MBatags : 物理地址: 0x50000100 - 0x50000197 152字节虚拟内存针对页表 : 用 下面(Image) 的映射关系针对Image : 虚拟地址:0xC000 0000 - 0xC08F FFFF 9MB <->物理地址 0x5000 0000 - 0x508F FFFF 9MB针对atags : 虚拟地址:0xFF80 0000 - 0xFF9F FFFF 2MB <->物理地址 0x5000 0000 - 0x501F FFFF 2MB页表内容:三组页表都是段表(bit[1:0]为10)bit[31:20] 为 Section base address , 这个值在不同页表中不同// 例如 500 表示 Section base address : 500 00000其他bit都是相同的, bit[19:0] 为 0x00c0ebit[1:0]:10// 表示该First-level descriptor是一个 Section descriptorMemory region attributesTEX:000 B:1C:1S:0表示 Outer and inner write back, no write allocate // 对于 s3c6410 来说 , 无 Outer , inner 为 16KB的 dcache// 也就是说 dcache 支持 write back, 支持 no write allocate // write allocate/write through/write back 是 缓存策略的范畴, 全局搜索 缓存策略Memory type : Normal// 属于内存属性的范畴 , 还没理清楚Page shareable : S设置则shareable,否则not shareable //该例为 not shareable// 属于内存属性的范畴 , 还没理清楚Memory access controlDomains permissionsDomain:0000// 表明 属于 domain0 , D0 // 参与 Domains permissions// D0 为01,表示 Accesses are checked against the access permission bits in the TLB entry// 即 Domain permissions 是 OK的,但还要检查 access permission bitsAccess permissionsAPX:0AP:11// 参与 Access permissions// 表示 Full accessXN:0// 表示包含可执行代码IMP:0//微架构实现定义 , 需查询 ARM1176 的 TRM 手册nG:0//页表翻译条目 在TLB中应标记为全局Image 虚拟内存分段Image 虚拟地址 : 0xC0008000 - 0xC088E547 8.6MB// include/asm-generic/sections.h_stext_etext.code: c0100000 - c0600000__start_rodata__end_rodata.rodata: c0600000 - c06b6000_sdata_edata.datac0800000 - c088e548__bss_start __bss_stop.bss: c088e548 - c08c413cinit_thread_union + THREAD_START_SP.stack: - C0801FF8.heap: nullImage 全局变量arch/arm/kernel/setup.c 中的 unsigned int processor_id: 0x410fb766arch/arm/boot/compressed/misc.c 中的 unsigned int __machine_arch_type : 0x0000065a // 1626arch/arm/kernel/setup.c 中的 unsigned int __atags_pointer: 0x50000100// SUDEBUG : arch/arm/kernel/setup.c,setup_arch,line = 1090,atags_vaddr:0xff800100arch/arm/kernel/entry-armv.S 中的 cr_alignment: 0x00c5387d // cp15 Register 1: Control register 的值

其他

过程 2 从 arch/arm/boot/compressed/head.S 中的start 到 arch/arm/kernel/head.S 中的 stext 的等价过程

参考 /u011011827/article/details/115766762 中的 镜像Image的执行 bash ./scripts/mkuboot.sh -A arm -O linux -C none -T kernel -a 0x50008000 -e 0x50008000 -n 'Linux-5.11.0-00004-g2b88cbadf5c-dirty' -d arch/arm/boot/Image arch/arm/boot/uImage2=> tftp 0x50008000 uImage2=> bootm 0x50008000

缓存策略

一、CPU读数据1. Read through即直接从内存中读取数据;2. Read allocate先把数据读取到Cache中,再从Cache中读数据。二、CPU写数据1. 若hit命中,有两种处理方式:Write-through:write through: write is done synchronously both to the cache and to the backing store。(直写模式)在数据更新时,把数据同时写入Cache和后端存储。此模式的优点是操作简单;缺点是因为数据修改需要同时写入存储,数据写入速度较慢。Write-back (also called write-behind) write backinitially, writing is done only to the cache. The write to the backing store is postponed until the cache blocks containing the data are about to be modified/replaced by new content。(回写模式)在数据更新时只写入缓存Cache。只在数据被替换出缓存时,被修改的缓存数据才会被写到后端存储(即先把数据写到Cache中,再通过flush方式写入到内存中)。此模式的优点是数据写入速度快,因为不需要写存储;缺点是一旦更新后的数据未被写入存储时出现系统掉电的情况,数据将无法找回。 2. 若miss,有两种处理方式:Write allocate (also called fetch on write)data at the missed-write location is loaded to cache, followed by a write-hit operation. In this approach, write misses are similar to read misses.先把要写的数据载入到Cache中,写Cache,然后再通过flush方式写入到内存中; 写缺失操作与读缺失操作类似。No-write allocate (also called write-no-allocate or write around)data at the missed-write location is not loaded to cache, and is written directly to the backing store. In this approach, only the reads are being cached。并不将写入位置读入缓存,直接把要写的数据写入到内存中。这种方式下,只有读操作会被缓存。

swapper_pg_dir

arch/arm/kernel/head.S L28swapper_pg_dir is the virtual address of the initial page table..globl swapper_pg_dir // 页表基址 对应的 虚拟地址.equ swapper_pg_dir, (((0xC0000000)) + 0x00008000) - 0x4000

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。