1020linux内核启动内核自解压分析.docx
《1020linux内核启动内核自解压分析.docx》由会员分享,可在线阅读,更多相关《1020linux内核启动内核自解压分析.docx(41页珍藏版)》请在冰豆网上搜索。
![1020linux内核启动内核自解压分析.docx](https://file1.bdocx.com/fileroot1/2022-11/15/fdb9fc86-6fae-446c-8d42-e563667eebb1/fdb9fc86-6fae-446c-8d42-e563667eebb11.gif)
1020linux内核启动内核自解压分析
内核自解压过程分析
本章代码的主要工作是将zImage解压,并把解压后的内核拷贝的正确的执行位置。
在解压之前cpu有几项工作要完成:
1.将bootloard传入的参数保存起来
2.进入管理模式,并将中断关闭
3.判断各段代码指针是否有偏移,有偏移的话就要更改指针地址
4.清楚bass段,打开高速缓存,设置栈的开始地址和结束地址,大小为64k
5.接下来要判断解压后各段数据是否有重叠,具体做法是(比较解压后内核的开始地址(执行内核的首地址)是否比设置的栈的结束地址大,如果大则跳转到wont_overwrite,否则比较解压后内核的结束地址是否比Image的开始地址小,如果小则跳转到wont_overwrite。
Wont_overwrite的作用是设置参数解压内核、运行解压后的内核)如果有重叠的话,做一些工作(这些工作很简单在代码中能见到)然后解压内核,解压之后要重新搬移内核到正确的位置,在搬移过程中可能有解压内核和搬移内核的代码相重叠,所以在搬移之前要将这段代码搬移到一个安全的地址,然后可以开始内核的搬移,搬移完内核之后要刷新cache,之后关闭cache然后开始运行内核。
下面是内核自解压过程的完整代码和分析:
/*
*linux/arch/arm/boot/compressed/head.S
*
*Copyright(C)1996-2002RussellKing
*Copyright(C)2004HyokS.Choi(MPUsupport)
*
*Thisprogramisfreesoftware;youcanredistributeitand/ormodify
*itunderthetermsoftheGNUGeneralPublicLicenseversion2as
*publishedbytheFreeSoftwareFoundation.
*/
#include
/*
*Debuggingstuff
*
*Notethatthesemacrosmustnotcontainanycodewhichisnot
*100%relocatable(重定位).Anyattempttodosowillresultinacrash.
*Pleaseselectoneofthefollowingwhenturningondebugging.
*/
#ifdefDEBUG/*调试宏中间层*/
#ifdefined(CONFIG_DEBUG_ICEDCC)/*使用内部调试协处理器*/
#ifdefCONFIG_CPU_V6
.macroloadsp,rb
.endm
.macrowriteb,ch,rb
mcrp14,0,\ch,c0,c5,0
.endm
#elifdefined(CONFIG_CPU_XSCALE)
.macroloadsp,rb
.endm
.macrowriteb,ch,rb
mcrp14,0,\ch,c8,c0,0
.endm
#else
.macroloadsp,rb
.endm
.macrowriteb,ch,rb
mcrp14,0,\ch,c1,c0,0
.endm
#endif
#else
#include/*包含架构相关的调试宏的汇编文件调试宏-底层*/
.macrowriteb,ch,rb
senduart\ch,\rb
.endm
#ifdefined(CONFIG_ARCH_SA1100)
.macroloadsp,rb
mov\rb,#0x80000000@physicalbaseaddress
#ifdefCONFIG_DEBUG_LL_SER3
add\rb,\rb,#0x00050000@Ser3
#else
add\rb,\rb,#0x00010000@Ser1
#endif
.endm
#elifdefined(CONFIG_ARCH_S3C2410)
.macroloadsp,rb
mov\rb,#0x50000000
add\rb,\rb,#0x4000*CONFIG_S3C_LOWLEVEL_UART_PORT
.endm
#else
.macroloadsp,rb
addruart\rb
.endm
#endif
#endif
#endif
.macrokputc,val
movr0,\val
blputc
.endm
.macrokphex,val,len
movr0,\val
movr1,#\len
blphex
.endm
.macrodebug_reloc_start
#ifdefDEBUG
kputc#'\n'
kphexr6,8/*processorid*/
kputc#':
'
kphexr7,8/*architectureid*/
#ifdefCONFIG_CPU_CP15
kputc#':
'
mrcp15,0,r0,c1,c0
kphexr0,8/*controlreg*/
#endif
kputc#'\n'
kphexr5,8/*decompressedkernelstart*/
kputc#'-'
kphexr9,8/*decompressedkernelend*/
kputc#'>'
kphexr4,8/*kernelexecutionaddress*/
kputc#'\n'
#endif
.endm
.macrodebug_reloc_end
#ifdefDEBUG
kphexr5,8/*endofkernel*/
kputc#'\n'
movr0,r4
blmemdump/*dump256bytesatstartofkernel*/
#endif
.endm
.section".start",#alloc,#execinstr
/*
*sortoutdifferentcallingconventions清理不同的调用约定
*/
.align//默认以字节对齐
start:
.typestart,#function
.rept8
movr0,r0
.endr
b1f
.word0x016f2818@Magicnumbers(魔数)tohelptheloader
.wordstart@absoluteload/runzImageaddress(编译时确定)
.word_edata@zImageendaddress
1:
movr7,r1@savearchitectureID(此前有bootloard放入r1)
movr8,r2@saveatagspointer保存内核启动参数到地址r8(此前有bootloard放入r2)这一段的作用是将bootloard传入的参数保存起来。
#ifndef__ARM_ARCH_2__
/*下面这段代码的作用是进入管理模式,并将中断关闭。
*BootingfromAngel-needtoenterSVCmodeanddisable
*FIQs/IRQs(numericdefinitionsfromangelarm.hsource).
*Weonlydothisifwewereinusermodeonentry.
*/
mrsr2,cpsr@getcurrentmode获取当前模式
tstr2,#3@notuser?
判断是不是用户模式,不是则跳转
bnenot_angel
movr0,#0x17@angel_SWIreason_EnterSVC
swi0x123456@angel_SWI_ARM//调用软中断指令进入管理模式
not_angel:
mrsr2,cpsr@turnoffinterruptsto
orrr2,r2,#0xc0@preventangelfromrunning
msrcpsr_c,r2
#else
teqppc,#0x0c000003@turnoffinterrupts(此外bootloader已经设置模式为svc)
#endif
/*
*Notethatsomecacheflushingandotherstuffmay
*beneededhere-isthereanAngelSWIcallforthis?
*/
/*
*somearchitecturespecificcodecanbeinserted(插入)
*bythelinkerhere,butitshouldpreserver7,r8,andr9.(r7,r8,r9要保留,r7保存架构ID,r8保存内核启动参数地址)
*/
.text
/*
*此处确定解压后的内核映像的绝对地址(物理地址),保存于r4
*由于配置的不同可能有的结果
*
(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中存储的正是
*.wordLC0@r1
*.word__bss_start@r2
*.word_end@r3
*.word_load_addr@r4
*.word_start@r5
*.word_got_start@r6
*.word_got_end@ip
*.worduser_stack+40Array6@sp
*因为此时r0是LC0的地址,r1中存放的是初始地址,跟它相减计算