注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

liuyue18301的个人主页

追逐梦想 光辉岁月

 
 
 

日志

 
 

ARM Linux启动分析----head-armv.S内幕-2  

2009-10-30 17:25:43|  分类: uboot |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

该段子程序完成后,各寄存器情况如下:

R5 = 内存(SDRAM)的起始物理地址

R6 = IO的起始物理地址

R7 = IO虚拟地址在页表中的索引项

?这里有一个疑问。将R7赋值是为了调试的需要,使得串口可以打印调试信息,因此需要操作IO。现在,我的IO起始地址为0x40000000,在这里被映射到了0xFC000000。获得UART的虚拟地址的宏addruart在/arch/arm/kernel/debug-armv.S中被定义,这个宏通过io_p2v宏得到IO的虚拟地址,该宏在include/asm-arm/arch-pxa/hardware.h中被定义,但是它将0x40000000的物理地址映射到了0xF8000000,而不是上面提到的0xFC000000,这是为什么呢?希望能有人解释一下这个问题。

 

__create_page_tables:

      pgtbl  r4, r5           @ page table address

 

      /* Clear the 16K level 1 swapper page table */

      mov        r0, r4

      mov        r3, #0

      add        r2, r0, #0x4000

1:    str        r3, [r0], #4

      str        r3, [r0], #4

      str        r3, [r0], #4

      str        r3, [r0], #4

      teq        r0, r2

      bne        1b

 

      /*

       * Create identity mapping for first MB of kernel to

       * cater for the MMU enable. This identity mapping

       * will be removed by paging_init()

       */

      krnladr r2, r4, r5         @ start of kernel

      add         r3, r8, r2         @ flags + kernel base

      str         r3, [r4, r2, lsr #18]    @ identity mapping

 

      /*

       * Now setup the pagetables for our kernel direct

       * mapped region. We round TEXTADDR down to the

       * nearest megabyte boundary.

       */

      add        r0, r4, #(TEXTADDR & 0xff000000) >> 18 @ start of kernel

      bic        r2, r3, #0x00f00000

      str        r2, [r0]         @ PAGE_OFFSET + 0MB

      add        r0, r0, #(TEXTADDR & 0x00f00000) >> 18

      str        r3, [r0], #4        @ KERNEL + 0MB

      add        r3, r3, #1 << 20

      str        r3, [r0], #4        @ KERNEL + 1MB

      add        r3, r3, #1 << 20

      str        r3, [r0], #4        @ KERNEL + 2MB

      add        r3, r3, #1 << 20

      str        r3, [r0], #4        @ KERNEL + 3MB

 

      /*

       * Ensure that the first section of RAM is present.

       * we assume that:

       * 1. the RAM is aligned to a 32MB boundary

       * 2. the kernel is executing in the same 32MB chunk

       *     as the start of RAM.

       */

      bic        r0, r0, #0x01f00000 >> 18 @ round down

      and        r2, r5, #0xfe000000    @ round down

      add        r3, r8, r2       @ flags + rambase

      str        r3, [r0]

 

      bic        r8, r8, #0x0c       @ turn off cacheable

                                  @ and bufferable bits

代码创建页表目录。首先清空从0xA0004000开始的16K页表项。然后,为了可以访问从0xA0000000开始的内核的1M空间,将该地址对应的页表项赋值。接着映射从TEXTADDR开始的4M的虚拟地址空间,这需要4个页表项。最后,由于SDRAM开始的第一MB的空间存放有启动时的一些参数,所以也需要映射。在这里,该映射和前面的虚拟地址的映射在地址上是相等的。

 

在创建页表目录完成后,代码通过前面主程序的最后一句add pc, r10, #12跳转到实际的CPU的设置子程序__xscale_setup。

__xscale_setup:

   mov        r0, #F_BIT|I_BIT|SVC_MODE

   msr        cpsr_c, r0

   mcr        p15, 0, ip, c7, c7, 0 @ invalidate I, D caches & BTB

   mcr     p15, 0, ip, c7, c10, 4 @ Drain Write (& Fill) Buffer

   mcr        p15, 0, ip, c8, c7, 0     @ invalidate I, D TLBs

   mcr        p15, 0, r4, c2, c0, 0     @ load page table pointer

   mov        r0,  #0x1f       @ Domains 0, 1 = client

   mcr        p15, 0, r0, c3, c0, 0 @ load domain access register

   mov        r0,  #1          @ Allow user space to access

   mcr        p15, 0, r0, c15, c1, 0    @ ... CP 0 only.

#if CACHE_WRITE_THROUGH

   mov        r0, #0x20

#else

   Mov     r0, #0x00

#endif

   mcr        p15, 0, r0, c1, c1, 0     @ set auxiliary control reg

   mrc        p15, 0, r0, c1, c0, 0     @ get control register

   bic     r0,  r0, #0x0200       @ ......R.........

   bic        r0,  r0, #0x0082       @ ........B.....A.

   orr        r0,  r0, #0x0005       @ .............C.M

   orr        r0,  r0, #0x3900       @ ..VIZ..S........

#ifdef CONFIG_XSCALE_CACHE_ERRATA

   bic        r0,  r0, #0x0004       @ see cpu_xscale_proc_init

#endif

   mov     pc,  lr

主要是操作协处理器,设置页表目录项基地址,对CACHE和BUFFER的控制位进行一些操作。具体大家可以看看介绍ARM编程的书。

 

.type __switch_data, %object

__switch_data: .long __mmap_switched

      .long SYMBOL_NAME(__bss_start)

      .long SYMBOL_NAME(_end)

      .long SYMBOL_NAME(processor_id)

      .long SYMBOL_NAME(__machine_arch_type)

      .long SYMBOL_NAME(cr_alignment)

      .long SYMBOL_NAME(init_task_union)+8192

 

      .type __ret, %function

__ret:   ldr   lr, __switch_data

      mcr   p15, 0, r0, c1, c0

      mov   r0, r0

      mov   r0, r0

      mov   r0, r0

      mov   pc, lr

 

      .align 5

__mmap_switched:

      adr   r3, __switch_data + 4

      ldmia r3, {r4, r5, r6, r7, r8, sp} @ r2 = compat

                                          @ sp = stack pointer

 

      mov   fp, #0                @ Clear BSS (and zero fp)

1:    cmp   r4, r5

      strcc fp, [r4],#4

      bcc   1b

 

      str   r9, [r6]              @ Save processor ID

      str   r1, [r7]              @ Save machine type

#ifdef CONFIG_ALIGNMENT_TRAP

      orr   r0, r0, #2            @ ...........A.

#endif

      bic   r2, r0, #2            @ Clear 'A' bit

      stmia r8, {r0, r2}       @ Save control register values

      b SYMBOL_NAME(start_kernel)

最后这段代码的作用主要是在进入C函数前先做一些变量的初始化和保存工作。首先清空BSS区域,然后保存处理器ID和机器类型到各自变量地址,接着保存cr_alignment,最后跳转到init/main.c中的start_kernel函数运行。

 

以上介绍的是head-armv.S文件的主要内容和功能,它是linux运行的第一个文件,具有非常重要的意义。很好的阅读该文件,对于我们理解ARM处理器的工作方式有很大的帮助。同时,在许多linux系统的移植工作中,往往需要对该文件透彻的理解。

  评论这张
 
阅读(336)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2018