ARM Linux启动代码分析
比较的是struct machine_desc的成员nr的值,因此不再分析。这里需要提一下的是,比如对于mini6410(tiny6410),struct machine_desc变量的定义在arch/arm/mach-s3c64xx/mach-mini6410.c文件中,如下所示:
00512 MACHINE_START(MINI6410, "MINI6410")00513 /* Maintainer: Ben Dooks*/00514 .phys_io = S3C_PA_UART & 0xfff00,00515 .io_pg_offst = (((u32)S3C_VA_UART) >> 18) & 0xfffc,00516 .boot_params = S3C64XX_PA_SDRAM + 0x100,00517 00518 .init_irq = s3c6410_init_irq,00519 .map_io = mini6410_map_io,00520 .init_machine = mini6410_machine_init,00521 .timer = &s3c24xx_timer,00522 MACHINE_END
回到head.S,86、87行判断是否支持当前的机器号,不支持就跳到__error_a标号处。
88行,跳到__vet_atags,同样是在arch/arm/kernel/head-common.S中定义:
00250 __vet_atags:00251 tst r2, #0x3 @ aligned?00252 bne 1f00253 00254 ldr r5, [r2, #0] @ is first tag ATAG_CORE?00255 cmp r5, #ATAG_CORE_SIZE00256 cmpne r5, #ATAG_CORE_SIZE_EMPTY00257 bne 1f00258 ldr r5, [r2, #4]00259 ldr r6, =ATAG_CORE00260 cmp r5, r600261 bne 1f00262 00263 mov pc, lr @ atag pointer is ok00264 00265 1: mov r2, #000266 mov pc, lr00267 ENDPROC(__vet_atags)
251行,测试r2的低2位是否为0,也即r2的值是否4字节对齐。
252行,如果r2的低2位不为0,则跳转到265行,将r2的值设为0,然后返回。
下面先看一下bootloader传递参数给内核的结构定义,在arch/arm/include/asm/setup.h文件中:
00146 struct tag {00147 struct tag_header hdr;00148 union {00149 struct tag_core core;00150 struct tag_mem32 mem;00151 struct tag_videotext videotext;00152 struct tag_ramdisk ramdisk;00153 struct tag_initrd initrd;00154 struct tag_serialnr serialnr;00155 struct tag_revision revision;00156 struct tag_videolfb videolfb;00157 struct tag_cmdline cmdline;00158 00159 /*00160 * Acorn specific00161 */00162 struct tag_acorn acorn;00163 00164 /*00165 * DC21285 specific00166 */00167 struct tag_memclk memclk;00168 } u;00169 };
147行,struct tag_header的定义:
24 struct tag_header {25 __u32 size;26 __u32 tag;27 };
从struct tag的定义可以知道,bootloader传递的参数有好几种类型的tag,但是内核规定第一个tag必须是ATAG_CORE类型,最后一个必须是ATAG_NONE类型,每一种类型的tag都有一个编号,例如ATAG_CORE为0x54411,ATAG_NONE为0x00。struct tag_header的tag成员就是用来描述tag的类型,而size成员用来描述整个tag的大小。每个tag连续存放。
那么标号__vet_atags的254行的意思就是获取ATAG_CORE类型tag的size成员的值赋给r5。
255行,将r5的值与ATAG_CORE_SIZE比较,ATAG_CORE_SIZE的值为((2*4 + 3*4) >> 2),即5。
256行,如果255行比较的结果不相等,那么将r5与ATAG_CORE_SIZE_EMPTY进行比较,ATAG_CORE_SIZE_EMPTY的值为((2*4) >> 2),即2。
257行,如果还是不相等,那么跳转到265行执行,同样是将r2设为0,然后返回。
258行,获取struct tag_header的tag成员,将它的值赋给r5。
259行,r6 = ATAG_CORE,即0x54411。
260行,比较r5和r6的值。
261行,如果r5和r6的值不相等则跳转到265行,如果相等则执行263行直接返回。
至此,__vet_atags标号的内容分析完毕。
回到head.S的89行,跳转到__create_page_tables标号处,在head.S里定义:
00219 __create_page_tables:00220 pgtbl r4 @ page table address00221 00 /*00223 * Clear the 16K level 1 swapper page table00224 */00225 mov r0, r400226 mov r3, #000227 add r6, r0, #0x400228 1: str r3, [r0], #400229 str r3, [r0], #400230 str r3, [r0], #400231 str r3, [r0], #400232 teq r0, r600233 bne 1b00234 00235 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags00236 00237 /*00238 * Create identity mapping for first MB of kernel to00239 * cater for the MMU enable. This identity mapping00240 * will be removed by paging_init(). We use our current program00241 * counter to determine corresponding section base address.00242 */00243 mov r6, pc00244 mov r6, r6, lsr #20 @ start of kernel section00245 orr r3, r7, r6, lsl #20 @ flags + kernel base00246 str r3, [r4, r6, lsl #2] @ identity mapping00247 00248 /*00249 * Now setup the pagetables for our kernel direct00250 * mapped region.00251 */00252 add r0, r4, #(KERNEL_START & 0xff) >> 1800253 str r3, [r0, #(KERNEL_START & 0x00f00) >> 18]!00254 ldr r6, =(KERNEL_END - 1)00255 add r0, r0, #400256 add r6, r4, r6, lsr #1800257 1: cmp r0, r600258 add r3, r3, #1 < 2000259 strls r3, [r0], #400260 bls 1b00261 00262 #ifdef CONFIG_XIP_KERNEL00263 /*00264 * Map some ram to cover our .data and .bss areas.00265 */00266 orr r3, r7, #(KERNEL_RAM_PADDR & 0xff)00267 .if (KERNEL_RAM_PADDR & 0x00f00)00268 orr r3, r3, #(KERNEL_RAM_PADDR & 0x00f00)00269 .endif00270 add r0, r4, #(KERNEL_RAM_VADDR & 0xff) >> 1800271 str r3, [r0, #(KERNEL_RAM_VADDR & 0x00f00) >> 18]!00272 ldr r6, =(_end - 1)00273 add r0, r0, #400274 add r6, r4, r6, lsr #1800275 1: cmp r0, r600276 add r3, r3, #1 < 2000277 strls r3, [r0], #400278 bls 1b00279 #endif00280 00281 /*00282 * Then map first 1MB of ram in case it contains our boot params.00283 */00284 add r0, r4, #PAGE_OFFSET >> 1800285 orr r6, r7, #(PHYS_OFFSET & 0xff)00286 .if (PHYS_OFFSET & 0x00f00)00287 orr r6, r6, #(PHYS_OFFSET & 0x00f00)00288 .endif00289 str r6, [r0]00290 00291 #ifdef CONFIG_DEBUG_LL00292 ldr r7, [r10, #PROCINFO_IO_MMUFLAGS] @ io_mmuflags00293 /*00294 * Map in IO space for serial debugging.00295 * This allows debug messages to be output00296 * via a serial console before paging_init.00297 */00298 ldr r3, [r8, #MACHINFO_PGOFFIO]00299 add r0, r4, r300300 rsb r3, r3, #0x4 @ PTRS_PER_PGD*sizeof(long)00301 cmp r3, #0x0800 @ limit to 512MB00302 movhi r3, #0x080000303 add r6, r0, r300304 ldr r3, [r8, #MACHINFO_PHYSIO]00305 orr r3, r3, r700306 1: str r3, [r0], #400307 add r3, r3, #1 < 2000308 teq r0, r600309 bne 1b00310 #if defined(CONFIG_ARCH_NETWINDER) defined(CONFIG_ARCH_CATS)00311 /*00312 * If were using the NetWinder or CATS, we also need to map00313 * in the 16550-type serial port for the debug messages00314 */00315 add r0, r4, #0xff >> 1800316 orr r3, r7, #0x7c00317 str r3, [r0]00318 #endif00319 #ifdef CONFIG_ARCH_RPC00320 /*00321 * Map in screen at 0x02 & SCREEN2_BASE00322 * Similar reasons here - for debug. This is00323 * only for Acorn RiscPC architectures.00324 */00325 add r0, r4, #0x02 >> 1800326 orr r3, r7, #0x0200327 str r3, [r0]00328 add r0, r4, #0xd8 >> 1800329 str r3, [r0]00330 #endif00331 #endif00332 mov pc, lr00 ENDPROC(__create_page_tables)
ARMLinux启动代 相关文章:
- Windows CE 进程、线程和内存管理(11-09)
- RedHatLinux新手入门教程(5)(11-12)
- uClinux介绍(11-09)
- openwebmailV1.60安装教学(11-12)
- Linux嵌入式系统开发平台选型探讨(11-09)
- Windows CE 进程、线程和内存管理(二)(11-09)