2011年1月16日星期日

ARM linux starting up process

ARM linux starting up process:
(from the entry to start_kernel)

something u-boot must do:
     The requirements are:
     MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
     r1 = machine nr, r2 = atags pointer.

lds script:
    arch/arm/kernel/vmlinux.lds
_sinittext = .;
                /**OY:define in  <include/asm-generic/vmlinux.lds>_**/
HEAD_TEXT /* *(.head.text) */
INIT_TEXT
                        /*
                        *(.init.text) \
                        DEV_DISCARD(init.text) \
                        CPU_DISCARD(init.text) \
                        MEM_DISCARD(init.text)
                        */


_einittext = .;
__proc_info_begin = .;
*(.proc.info.init)      
                        /**OY:this defined in arch/arm/mm/proc-[arch].S **/
__proc_info_end = .;
__arch_info_begin = .;
*(.arch.info.init)
                 /**OY: defined in (arch/arm/include/asm/mach/arch.h)
                    #define MACHINE_START(_type,_name) \
                     static const struct machine_desc __mach_desc_##_type \
                     __used \
                     __attribute__((__section__(".arch.info.init"))) = { \
                            .nr = MACH_TYPE_##_type, \
                            .name = _name,


                    #define MACHINE_END \
                    };
**/
__arch_info_end = .;
__tagtable_begin = .;
*(.taglist.init)
__tagtable_end = .;

the real entry:
ENTRY(stext) -- (arch/arm/kernel/head.S)
    1.set the cpu to svc mode:
        setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode
    2.get process id use mrc
        mrc p15, 0, r9, c0, c0 @ get processor id
        r9 <-- cpuid
    3.lookup processor type
        bl __lookup_processor_type  -- arch/arm/kernel/head-common.S
            /*by now, MMU is not enabled, we can use offset only*/
            __proc_info_begin & __proc_info_end
            --here we use an important struct : proc_info_list  --defined <asm/procinfo.h> , it store some info about cpu, it was statically setup in kernel code.
                    struct proc_info_list {
                            unsigned int cpu_val;
                            unsigned int cpu_mask;
                            unsigned long __cpu_mm_mmu_flags; /* used by head.S */
                            unsigned long __cpu_io_mmu_flags; /* used by head.S */
                            unsigned long __cpu_flush; /* used by head.S */
                            const char *arch_name;
                            const char *elf_name;
                            unsigned int elf_hwcap;
                            const char *cpu_name;
                            struct processor *proc;
                            struct cpu_tlb_fns *tlb;
                            struct cpu_user_fns *user;
                            struct cpu_cache_fns *cache;
                    };
            this fun try to mach cpu_val & cpu_mask(a member of struct proc_info_list) with process id, if yes, it will return success
            return: r10 <-- procinfo addr
    4. bl __lookup_machine_type  -- also defined in head-common.S
        __arch_info_begin & __arch_info_end
        read the arch info and compare to r1 (passed by the bootloader -- matchinfo type))
        return: r8 <-- machine info addr
    5.  bl __vet_atags /**OY: check if atags is valid **/ --also defined in head-common.S
        /**OY:r2 <-- atags pointer **/
        check the ATAG is aligned, core struct is ok?
        return: r5 <-- r2+4 --the real begin of atags
    6. bl __create_page_tables (arch/arm/kernel/head.S)
        r4, =(KERNEL_RAM_PADDR - 0x4000)**/ --page table address
        1. clean the page table with 0
        2. use the mm_mmuflags in proc_info_list to set the mmu flags
        3. create a "identity mapping" for first MB of kernel, and will be cleared by paging_init()
             /**OY:identity  mapping ==> logical addr = phy addr**/
        4. build the pagetable for the kernel direct mapped region
        5. other concern like XIP,
6. Then map first 1MB of ram in case it contains our boot params.
        7. debug(Map IO) etc.
        return : r4 page talbe address
    7.  ldr r13, __switch_data @ address to jump to after
        __switch_data: (arch/arm/kernel/head-common.S)
.long __mmap_switched
.long __data_loc @ r4
.long _data @ r5
.long __bss_start @ r6
.long _end @ r7
.long processor_id @ r4
.long __machine_arch_type @ r5
.long __atags_pointer @ r6
.long cr_alignment @ r7
.long init_thread_union + THREAD_START_SP @ sp
        /**OY:in fact r13 = __mmap_switched**/
        __mmap_switched:
            1. config the registers, ie. store data above to registers
            2. Copy data segment if needed
            3. Clear BSS (and zero fp)
            4. save some info to addr processor_id, __machine_arch_type, __atags_pointer, cr_alignment
            5. b start_kernel
    8.  @ mmu has been enabled
adr lr, BSYM(__enable_mmu) @ return (PIC) address
            __enable_mmu -- defined in (arch/arm/kernel/head.S)
                1.tackle some marco configure like disable cache
                2.  b __turn_mmu_on
                    config mmu
                    pc <-- __mmap_switched
    9.  ARM( add pc, r10, #PROCINFO_INITFUNC )
         #define PROCINFO_INITFUNC 16 /* offsetof(struct proc_info_list, __cpu_flush)@ */
         in fact, we call __cpu_flush now.
         for armv7, this defined in (arch/arm/mm/proc-v7.S)
             __cpu_flush = b v7_setup;

    NOTE: in fact, from step 7 to 9, the real call sequence is -->
        v7_setup --> __enable_mmu --> __mmap_switched

没有评论:

发表评论