Chinaunix首页 | 论坛 | 博客
  • 博客访问: 633936
  • 博文数量: 75
  • 博客积分: 7001
  • 博客等级: 少将
  • 技术积分: 1465
  • 用 户 组: 普通用户
  • 注册时间: 2007-07-11 17:39
文章分类

全部博文(75)

文章存档

2010年(1)

2009年(25)

2008年(49)

我的朋友

分类: LINUX

2008-06-12 20:17:17

head-armv.S分析
/*
*  linux/arch/arm/kernel/head-armv.S
*
*  Copyright (C) 1994-1999 Russell King
*  Copyright (C) 2002 Motorola Semiconductors HK Ltd
*    - added MX1ADS specific codes
*
* 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.
*
*  32-bit kernel startup code for all architectures
*/
#include
#include
#include
#include
#include
#define K(a,b,c)    ((a)  PAGE_OFFSET + 0x4000
*
* Note that swapper_pg_dir is the virtual address of the page tables, and
* pgtbl gives us a position-independent reference to these tables.  We can
* do this because stext == TEXTADDR
*
* swapper_pg_dir, pgtbl and krnladr are all closely related.
*/
/*ifeq ($(CONFIG_CPU_32),y)
PROCESSOR  = armv
TEXTADDR  = 0xC0008000
LDSCRIPT  = arch/arm/vmlinux-armv.lds.in
endif*/

#if (TEXTADDR & 0xffff) != 0x8000
#error TEXTADDR must start at 0xXXXX8000
#endif
        .globl    SYMBOL_NAME(swapper_pg_dir)
        .equ    SYMBOL_NAME(swapper_pg_dir), TEXTADDR - 0x4000
        .macro    pgtbl, reg, rambase
        adr    \reg, stext
        sub    \reg, \reg, #0x4000
        .endm
/*
* Since the page table is closely related to the kernel start address, we
* can convert the page table base address to the base address of the section
* containing both.
*/
        .macro    krnladr, rd, pgtable, rambase
        bic    \rd, \pgtable, #0x000ff000
        .endm
/*
*  Kernel startup entry point.
*
* The rules are:
*  r0      - should be 0
*  r1      - unique architecture number
*  MMU     - off
*  I-cache - on or off
*  D-cache - off
*
* See linux/arch/arm/tools/mach-types for the complete list of numbers
* for r1.
*/
/*JumpToKernel((void *)0x8008000, 0x083FF000) ;     .global    JumpToKernel//    r0 = jump address//    r1 = pointer to command lineJumpToKernel://    jump to the copy code (get the arguments right)    mov    pc, r0*/
        .section ".text.init",#alloc,#execinstr
        .type    stext, #function
ENTRY(stext)
        mov    r12, #0
#if defined(CONFIG_ARCH_MX1ADS)||defined(CONFIG_ARCH_MX2ADS)
        mov    fp, r1    @ r1 contain pointer to cmdline from bootloader fp == r11
#endif
/*
* NOTE!  Any code which is placed here should be done for one of
* the following reasons:
*
*  1. Compatability with old production boot firmware (ie, users
*     actually have and are booting the kernel with the old firmware)
*     and therefore will be eventually removed.
*  2. Cover the case when there is no boot firmware.  This is not
*     ideal, but in this case, it should ONLY set r0 and r1 to the
*     appropriate value.
*/
#if defined(CONFIG_ARCH_NETWINDER)
/*
* Compatability cruft for old NetWinder NeTTroms.  This
* code is currently scheduled for destruction in 2.5.xx
*/
        .rept    8
        mov    r0, r0
        .endr
        adr    r2, 1f
        ldmdb    r2, {r7, r8}
        and    r3, r2, #0xc000
        teq    r3, #0x8000
        beq    __entry
        bic    r3, r2, #0xc000
        orr    r3, r3, #0x8000
        mov    r0, r3
        mov    r4, #64
        sub    r5, r8, r7
        b    1f
        .word    _stext
        .word    __bss_start
1:
        .rept    4
        ldmia    r2!, {r6, r7, r8, r9}
        stmia    r3!, {r6, r7, r8, r9}
        .endr
        subs    r4, r4, #64
        bcs    1b
        movs    r4, r5
        mov    r5, #0
        movne    pc, r0
        mov    r1, #MACH_TYPE_NETWINDER    @ (will go in 2.5)
        mov    r12, #2 //执行__lookup_processor_type处理器匹配函数之后//r8 = 建立4个1M节MMU页表的标志(0x00000c1e)//r9 = 处理器ID//r10 = 处理器结构体的指针
        teq    r10, #0                @ invalid processor?
        moveq    r0, #'p'            @ yes, error 'p'
        beq    __error
        bl    __lookup_architecture_type
//执行__lookup_architecture_type体系结构匹配函数之后//BOOT_MEM(0x08000000, 0x00200000, 0xf0200000)//r5 = 体系结构指针下对应的machine_desc->phys_ram物理内存地址 0x08000000//r6 = 体系结构指针下对应的machine_desc->phys_io物理寄存器地址 0x00200000//r7 = 体系结构指针下对应的machine_desc->io_pg_offst物理寄存器地址对应的虚拟地址对应的节基址 0x00003c08(io_pg_offst: ((_vio)>>18)&0xfffc)
        teq    r7, #0                @ invalid architecture?
        moveq    r0, #'a'            @ yes, error 'a'
        beq    __error
        bl    __create_page_tables
//执行__create_page_tables函数之后
//r4 = 0x08004000 该函数在物理内存地址0x08004000--0x08008000之间建立了一级页表,包含的表项是段项,bit[10]=10
        adr    lr, __ret            @ return address
        add    pc, r10, #12            @ initialise processor
                            @ (return control reg)
//转入函数__arm920_setup,在文档proc-arm920.S中,
/*.section ".text.init", #alloc, #execinstr

__arm920_setup:
mov r0, #0

//c7是只写寄存器,用来控制cache和write buffer
mcr p15, 0, r0, c7, c7  @ 使指令和数据cache无效
mcr p15, 0, r0, c7, c10, 4  @ drain write buffer on v4:在将write buffer中的任何数据写入主存之前,停止执行后面的代码
mcr p15, 0, r0, c8, c7  @ 使任何TLB无效
mcr p15, 0, r4, c2, c0  @ 将一级页表的起始地址写入C2寄存器

//有两种控制能够管理一个任务的存储器访问权限:域(domain)用于主控制,页表中的访问权限用于次控制。其中:11:表示访问不受控制,不产生权限中止;01:表示访问受页表项中配置的权限值控制。
//在一级页表项中能够指定该段内存属于哪个域,其中C3寄存器能够表示16个域
mov r0, #0x1f   @ 域0,域1:为管理者(11),域2:为用户(01)
mcr p15, 0, r0, c3, c0  @ load domain access register
mrc p15, 0, r0, c1, c0  @ get control register v4
/*
* Clear out 'unwanted' bits (then put them in if we need them)
*/
//M: MMU使能控制, A:Aligment使能控制, C:数据Cache使能控制,W:Write Buffer使能控制, P、D、L:应该为1, B:大小端控制,0,表示小端模式,1,表示大端模式, S,R:分别被称为系统位和ROM位,和二级页表项中的AP标志位相同,用来控制存储器的访问权限,配置控制如下:(在AP位域为00的前提下)SR:00 特权模式不可访问,用户模式不可访问;SR:01 特权模式只读,用户模式只读; SR:10 特权模式只读,用户模式不可访问,SR:11 特权模式不可预料,用户模式不可预料, F:和具体的处理器相关, Z:分支预取使能控制, I:指令Cache使能控制, V: 中断向量表映射,1,0xffff0000--0xffff001c, 0,0x00000000--0x0000001c
      @   VI ZFRS BLDP WCAM
      @   11 0001 0111 0101
bic r0, r0, #0x0e00
bic r0, r0, #0x0002
bic r0, r0, #0x000c
bic r0, r0, #0x1000   @ ...0 000. .... 000.
/*
* Turn on what we want
*/
orr r0, r0, #0x0031
orr r0, r0, #0x2100   @ ..1. ...1 ..11 ...1
#ifdef CONFIG_CPU_ARM920_D_CACHE_ON
orr r0, r0, #0x0004   @ .... .... .... .1..
#endif
#ifdef CONFIG_CPU_ARM920_I_CACHE_ON
orr r0, r0, #0x1000   @ ...1 .... .... ....
#endif
mov pc, lr

.text
*/
        .type    __switch_data, %object
__switch_data:    .long    __mmap_switched
        .long    SYMBOL_NAME(compat)
        .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
/* .bss : {
  __bss_start = .; /* BSS    */
  *(.bss)
  *(COMMON)
  _end = . ;
}*/

#if defined(CONFIG_ARCH_MX1ADS)||defined(CONFIG_ARCH_MX2ADS)
        .long    SYMBOL_NAME(cmdline_from_bootloader)
#endif
        .type    __ret, %function
__ret:  ldr    lr, __switch_data  //将__mmap_switched函数虚拟地址放入lr
        mcr    p15, 0, r0, c1, c0 //开启MMU功能
        mov    r0, r0
        mov    r0, r0
        mov    r0, r0 //三条无效指令填充流水线
        mov    pc, lr
        /*
         * This code follows on after the page
         * table switch and jump above.
         *
         * r0  = processor control register
         * r1  = machine ID
         * r9  = processor ID
         */
        .align    5
__mmap_switched:
        adr    r3, __switch_data + 4
        ldmia    r3, {r2, r4, r5, r6, r7, r8, sp}@ r2 = compat
                            @ sp = stack pointer
        str    r12, [r2]
#if defined( CONFIG_ARCH_MX1ADS)||defined(CONFIG_ARCH_MX2ADS)
        mov    r12, fp                @ fp/r11 gets used below (it originally contain pointer to
                                        @ cmdline from bootloader)
#endif
        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
#if defined(CONFIG_ARCH_MX1ADS)||defined(CONFIG_ARCH_MX2ADS)
        /* now save a pointer to the cmdline_from_bootloader */
        adr    r3, __switch_data + 32        @ cmdline_from_bootloader
        ldmia    r3, {r4}            @ r4 = address of above
        str    r12, [r4]
#endif
#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
// 在文档entry-armv.S中,
/* .globl SYMBOL_NAME(cr_alignment)
  .globl SYMBOL_NAME(cr_no_alignment)
SYMBOL_NAME(cr_alignment):
  .space 4
SYMBOL_NAME(cr_no_alignment):
  .space 4     
*/
//上面的语句就是使:r0 = 11 0001 0111 0111 r2= 11 0001 0111 0101   
        b    SYMBOL_NAME(start_kernel)
/*
* Setup the initial page tables.  We only setup the barest
* amount which are required to get the kernel running, which
* generally means mapping in the kernel code.
*
* We only map in 4MB of RAM, which should be sufficient in
* all cases.
*
* r5 = physical address of start of RAM
* r6 = physical IO address
* r7 = byte offset into page tables for IO
* r8 = page table flags
*/
__create_page_tables:
        pgtbl    r4, r5                @ page table address
       /*        .macro    pgtbl, reg, rambase        adr    \reg, stext //注意adr是伪汇编,得到相对于PC的stext的地址,也就是0x8008000        sub    \reg, \reg, #0x4000        .endm       */
        /*
         * Clear the 16K level 1 swapper page table
         */
        mov    r0, r4   //r4 = 0x08004000
        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
        /*        .macro    krnladr, rd, pgtable, rambase        bic    \rd, \pgtable, #0x000ff000  //r2 = 0x08000000        .endm        */
        add    r3, r8, r2            @ flags + kernel base //r8 = 0x00000c1e
        str    r3, [r4, r2, lsr #18]        @ identity mapping
        //右移18位,剩余14位,而不是12位,是高12位节基址*4字节存储地址的结果,是bit31~bit20节基址索引×4字节的结果,也就是说,这里的一级页表的基地址是0x08004000,而页表内的索引项为0x0200[高12左移2位]
        //映射一级页表
        //对于表的查找,要知道这个表的基地址和偏移地址,在具备MMU功能的处理器中,整合了一个被称          为CP15的协处理器,该协处理器的C2寄存器中用于保存页表的基地址
        //ARM920T内部采用哈佛结构,将内部指令总线和数据总线分开,分别连接到ICache和DCache,          再通过AMBA总线接口连接到ASB总线上去访问内存。
        // 0x08000c1e --> [0x08004200]
        // r2 = 0x08000000
        // r3 = 0x08000c1e         
        // r4 = 0x08004000        // r8 = 0x00000c1e  
        /*
         * 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
        //r0 = 0x08007000
        bic    r2, r3, #0x00f00000
        //r2 = 0x08000c1e
        str    r2, [r0]            @ PAGE_OFFSET + 0MB
        // 0x08000c1e --> [0x08007000]
        add    r0, r0, #(TEXTADDR & 0x00f00000) >> 18
        //r0 = 0x08007000
        str    r3, [r0], #4            @ KERNEL + 0MB
        // 0x08000c1e --> [0x08007000]
        add    r3, r3, #1 // 0x08100c1e --> [0x08007004]
        add    r3, r3, #1 // 0x08200c1e --> [0x08007008]
        add    r3, r3, #1 // 0x08300c1e --> [0x0800700c]
        /*
         * 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
        //r0 = 0x08007000
        and    r2, r5, #0xfe000000        @ round down
        //0x01f00000和0xfe000000都为了32M空间对齐
        add    r3, r8, r2            @ flags + rambase
        str    r3, [r0]
        // 0x08000c1e --> [0x08007000]
        bic    r8, r8, #0x0c            @ turn off cacheable
                            @ and bufferable bits
        // r8 = 0x00000c12
#ifdef CONFIG_DEBUG_LL
        /*
         * Map in IO space for serial debugging.
         * This allows debug messages to be output
         * via a serial console before paging_init.
         */
        // r4 = 0x08004000        // r7 = 0x00003c08
        add    r0, r4, r7
        rsb    r3, r7, #0x4000    @ PTRS_PER_PGD*sizeof(long)
        // rsb 反向减法指令
        // r0 = 0x08007c08
        // r3 = 0x000003f8
        cmp    r3, #0x0800
        addge    r2, r0, #0x0800
        addlt    r2, r0, r3
        //r2 = 0x08008000
        orr    r3, r6, r8
        // r3 = 0x00200c12
1:        str    r3, [r0], #4  //0x00200c12 --> [0x08007c08]
        add    r3, r3, #1
阅读(1101) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~