1、1020linux内核启动内核自解压分析内核自解压过程分析本章代码的主要工作是将zImage解压,并把解压后的内核拷贝的正确的执行位置。在解压之前cpu有几项工作要完成:1. 将bootloard传入的参数保存起来2. 进入管理模式,并将中断关闭3. 判断各段代码指针是否有偏移,有偏移的话就要更改指针地址4. 清楚bass段,打开高速缓存,设置栈的开始地址和结束地址,大小为64k5. 接下来要判断解压后各段数据是否有重叠,具体做法是(比较解压后内核的开始地址(执行内核的首地址)是否比设置的栈的结束地址大,如果大则跳转到wont_overwrite,否则比较解压后内核的结束地址是否比Image的
2、开始地址小,如果小则跳转到wont_overwrite。Wont_overwrite的作用是设置参数解压内核、运行解压后的内核)如果有重叠的话,做一些工作(这些工作很简单在代码中能见到)然后解压内核,解压之后要重新搬移内核到正确的位置,在搬移过程中可能有解压内核和搬移内核的代码相重叠,所以在搬移之前要将这段代码搬移到一个安全的地址,然后可以开始内核的搬移,搬移完内核之后要刷新cache,之后关闭cache然后开始运行内核。下面是内核自解压过程的完整代码和分析:/* * linux/arch/arm/boot/compressed/head.S * * Copyright (C) 1996-20
3、02 Russell King * Copyright (C) 2004 Hyok S. Choi (MPU support) * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License version 2 as * published by the Free Software Foundation. */#include /* * Debugging stuff * * Note that thes
4、e macros must not contain any code which is not * 100% relocatable(重定位). Any attempt to do so will result in a crash. * Please select one of the following when turning on debugging. */#ifdef DEBUG /*调试宏中间层*/#if defined(CONFIG_DEBUG_ICEDCC) /*使用内部调试协处理器*/#ifdef CONFIG_CPU_V6 .macro loadsp, rb .endm .
5、macro writeb, ch, rb mcr p14, 0, ch, c0, c5, 0 .endm#elif defined(CONFIG_CPU_XSCALE) .macro loadsp, rb .endm .macro writeb, ch, rb mcr p14, 0, ch, c8, c0, 0 .endm#else .macro loadsp, rb .endm .macro writeb, ch, rb mcr p14, 0, ch, c1, c0, 0 .endm#endif#else#include /*包含架构相关的调试宏的汇编文件 调试宏-底层*/ .macro w
6、riteb, ch, rb senduart ch, rb .endm#if defined(CONFIG_ARCH_SA1100) .macro loadsp, rb mov rb, #0x80000000 physical base address#ifdef CONFIG_DEBUG_LL_SER3 add rb, rb, #0x00050000 Ser3#else add rb, rb, #0x00010000 Ser1#endif .endm#elif defined(CONFIG_ARCH_S3C2410) .macro loadsp, rb mov rb, #0x50000000
7、 add rb, rb, #0x4000 * CONFIG_S3C_LOWLEVEL_UART_PORT .endm#else .macro loadsp, rb addruart rb .endm#endif#endif#endif .macro kputc,val mov r0, val bl putc .endm .macro kphex,val,len mov r0, val mov r1, #len bl phex .endm .macro debug_reloc_start#ifdef DEBUG kputc #n kphex r6, 8 /* processor id */ kp
8、utc #: kphex r7, 8 /* architecture id */#ifdef CONFIG_CPU_CP15 kputc #: mrc p15, 0, r0, c1, c0 kphex r0, 8 /* control reg */#endif kputc #n kphex r5, 8 /* decompressed kernel start */ kputc #- kphex r9, 8 /* decompressed kernel end */ kputc # kphex r4, 8 /* kernel execution address */ kputc #n#endif
9、 .endm .macro debug_reloc_end#ifdef DEBUG kphex r5, 8 /* end of kernel */ kputc #n mov r0, r4 bl memdump /* dump 256 bytes at start of kernel */#endif .endm .section .start, #alloc, #execinstr/* * sort out different calling conventions清理不同的调用约定 */ .align /默认以字节对齐start: .type start,#function .rept 8
10、mov r0, r0 .endr b 1f .word 0x016f2818 Magic numbers(魔数) to help the loader .word start absolute load/run zImage address(编译时确定) .word _edata zImage end address1: mov r7, r1 save architecture ID (此前有bootloard放入r1) mov r8, r2 save atags pointer 保存内核启动参数到地址r8 (此前有bootloard放入r2) 这一段的作用是将bootloard传入的参数保存
11、起来。#ifndef _ARM_ARCH_2_ /*下面这段代码的作用是进入管理模式,并将中断关闭。 * Booting from Angel - need to enter SVC mode and disable * FIQs/IRQs (numeric definitions from angel arm.h source). * We only do this if we were in user mode on entry. */ mrs r2, cpsr get current mode获取当前模式 tst r2, #3 not user?判断是不是用户模式,不是则跳转 bne n
12、ot_angel mov r0, #0x17 angel_SWIreason_EnterSVC swi 0x123456 angel_SWI_ARM /调用软中断指令进入管理模式not_angel: mrs r2, cpsr turn off interrupts to orr r2, r2, #0xc0 prevent angel from running msr cpsr_c, r2#else teqp pc, #0x0c000003 turn off interrupts(此外bootloader已经设置模式为svc)#endif /* * Note that some cache fl
13、ushing and other stuff may * be needed here - is there an Angel SWI call for this? */ /* * some architecture specific code can be inserted(插入) * by the linker here, but it should preserve r7, r8, and r9.(r7,r8,r9要保留,r7保存架构ID,r8保存内核启动参数地址) */ .text/* * 此处确定解压后的内核映像的绝对地址(物理地址),保存于r4 * 由于配置的不同可能有的结果 *
14、(1)定义了CONFIG_AUTO_ZRELADDR * ZRELADDR是已解压内核最终存放的物理地址 * 如果AUTO_ZRELADDR被选择了, 这个地址将会在运行时确定: * 将当pc值和0xf8000000做与操作, * 并加上TEXT_OFFSET(内核最终存放的物理地址与内存起始的偏移) * 这里假定zImage被放在内存开始的128MB内 * (2)没有定义CONFIG_AUTO_ZRELADDR * 直接使用zreladdr(此值位于arch/arm/mach-xxx/Makefile.boot文件确定) */* 把LC0的数据依次存入r1,r2,r3,r4,r5,r6,ip,sp,LC0中存储的正是*.word LC0 r1*.word _bss_start r2*.word _end r3*.word _load_addr r4*.word _start r5*.word _got_start r6*.word _got_end ip*.word user_stack+40Array6 sp*因为此时r0是LC0的地址,r1中存放的是初始地址,跟它相减计算
copyright@ 2008-2022 冰豆网网站版权所有
经营许可证编号:鄂ICP备2022015515号-1