arm linux 啓動代碼分析(一)

這次我寫的是Image的啓動過程,也即使zImage解壓縮結束後的啓動代碼,這時候的代碼開始地址仍然是0x30008000,下面我結合代碼來講吧:
Image的啓動代碼是在/arch/arm/kernel/head.S中的:
/*
 *  linux/arch/arm/kernel/head.S
 *  Kernel startup code for all 32-bit CPUs
 */
 /* 內核啓動入口點 
 * Kernel startup entry point. 
 * 這裏通常在解壓後直接調用。 
 * 處理器基本狀態要求: 
 * MMU關閉,D-cach關閉,I-cache不用關係; 
 * r0 = 0,r1 = 系統號(machine number) 
 * 這段代碼幾乎是位置無關的。 
 * 如果鏈接內核在0xc0008000,調用的地址爲相應的物理地址__pa(0xc0008000)。 
 * r1的系統號參考arch/arm/tools/mach-types文件的列表。 
 * 儘量不要在這裏添加系統號相關的代碼,那應該放在bootloader的代碼中。 
 * 保持這裏的代碼的整潔。 
 */
 __INIT
 .type stext, %function
/*―――――――――――――――――――――――――――――――――――――――――――――― 
這個地方就是 kernel 的入口點 
―――――――――――――――――――――――――――――――――――――――――――――― */
ENTRY(stext)
 msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | MODE_SVC @ ensure svc mode
      @ and irqs disabled
/*――――――――――――――――――――――――――――――――――――――――――――――  
   調用 __lookup_processor_type 檢查現在運行的 cpu 的 ID 值和 linux 編譯支持的
id 值是否相等。 
――――――――――――――――――――――――――――――――――――――――――――――*/
 bl __lookup_processor_type  @ r5=procinfo r9=cpuid
/*―――――――――――――――――――――――――――――――――――――――――――――― 
    從該函數返回後,寄存器內容如下: 
    R9  = cpu ID 
    R5 = pointer to processor structure 
 
    詳細的內容請看__lookup_processor_type 的分析 */
  .type __lookup_processor_type, %function
__lookup_processor_type:
/*――――――――――――――――――――――――――――――――――――――――――――――   
   把標號 2 的地址送給 r3, 3f = lable 3 forward  
―――――――――――――――――――――――――――――――――――――――――――――― */
 adr r3, 3f
/*―――――――――――――――――――――――――――――――――――――――――――――― 
   把 r3 指向內存的地址的內容賦值給 r5,r6,r9
    所以,參照標號 3處的聲明,我們可以知道: 
    __proc_info_begin     r5 
    __proc_info_end       r6 
    3b                    r9
 
    __proc_info_end 和 __proc_info_begin 這兩個標號都是在
/linux/arch/arm/vmlinux.ld 這個腳本中定義的。在連接的時候,ld 會把相應cpu信息
proc_info 放到這兩個標號之間。 
        __proc_info_begin = .; 
                        *(.proc.info) 
        __proc_info_end = .; 
――――――――――――――――――――――――――――――――――――――――――――――*/
 ldmda r3, {r5, r6, r9}  @ ldmda彈棧順序是從右到左,[r3]->r9,[r3-4]->r6,[r3-8]->r5
/*r3 = 標號 3 的加載地址地址,r9 = 標號 3 的連接地址 ,r3是根據pc值確定的,r9是鏈接階段就確定的是鏈接地址*/
 sub r3, r3, r9   @ get offset between virt&phys
 // r3 = 加載地址和連接地址的差值 
 //現在,r5 = __proc_info_begin 的加載地址,即在 RAM 中的地址 
 add r5, r5, r3   @ convert virt addresses to
 add r6, r6, r3   @ physical address space
 mrc p15, 0, r9, c0, c0 @ get processor id協處理器指令獲取cpu id號r9=0x41807202(sep4020)
/*―――――――――――――――――――――――――――――――――――――――――――――― 
    在本例中, r5  =  _arm720_proc_info 這 個 標記定義在 
linux/arch/arm/mm/proc-arm720.S 
__arm720_proc_info: 
        .long   0x41807200       r3 = cpu_value 
        .long   0xffffff00       r4 = cpu_mask 
        .long   0x00000c1e       mmuflags,一級段描述符 
        b       __arm720_setup 
                      . 
                      . 
―――――――――――――――――――――――――――――――――――――――――――――― */
//ldmia彈棧順序是從左到右,[r5]->r3,[r5+4]->r4 ,即低地址的內容放到低編號的寄存器,高地址的內容放到高編號的寄存器,指令結束後r5的指依然爲_arm720_proc_info
1: ldmia r5, {r3, r4}   @ value, mask  
 and r4, r4, r9   @ mask wanted bits
//將r9屏上0xffffff00看sep4020是否是arm720t的內核
 teq r3, r4
 beq 2f     @若是arm720t內核則直接跳轉到標籤2
/*―――――――――――――――――――――――――――――――――――――――――――――― 
   proc_info_list 定義在 linux/include/asm-arm/procinfo.h 
 
    struct proc_info_list {
 unsigned int  cpu_val;
 unsigned int  cpu_mask;
 unsigned long  __cpu_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;
};
    每一項都是 4 個字節,所以 sizeof(proc_info_list) = 48 byte 
――――――――――――――――――――――――――――――――――――――――――――――*/
 add r5, r5, #PROC_INFO_SZ  @ sizeof(proc_info_list)=48
 cmp r5, r6
 blo 1b
 mov r5, #0    @ unknown processor
2: mov pc, lr
/*
 * This provides a C-API version of the above function.
 */
ENTRY(lookup_processor_type)
 stmfd sp!, {r4 - r6, r9, lr}
 bl __lookup_processor_type
 mov r0, r5
 ldmfd sp!, {r4 - r6, r9, pc}
/*
 * Look in include/asm-arm/procinfo.h and arch/arm/kernel/arch.[ch] for
 * more information about the __proc_info and __arch_info structures.
 */
 .long __proc_info_begin
 .long __proc_info_end
3: .long .
 .long __arch_info_begin
 .long __arch_info_end
    
/*―――――――――――――從__lookup_processor_type返回――――――――――――――――――――――――――――――――― */
 movs r10, r5    @ 是有效720t核嗎  (r5=0)?
 beq __error_p   @ yes, error 'p'
/*―――――――――――――――――――――――――――――――――――――――――――――― 
   __lookup_machine_type 通過 R1 寄存器,判斷體系類型,R1 = machine 
architecture number 
―――――――――――――――――――――――――――――――――――――――――――――― */
 bl __lookup_machine_type  @ r5=machinfo
/*―――――――――――――――――――――――――――――――――――――――――――――― */
/*  r1 = machine architecture number
 * Returns:
 *  r3, r4, r6 corrupted
 *  r5 = mach_info pointer in physical address space
 */
 .type __lookup_machine_type, %function
__lookup_machine_type:
 adr r3, 3b
/*―――――――――――――――――――――――――――――――――――――――――――――― 
   把 r3 指向內存的地址的內容賦值給 r4,r5,r6
    所以,參照標號 3處的聲明,我們可以知道: 
    3b                   r4
    __arch_info_begin r5
  __arch_info_end  r6
  
    __arch_info_end 和 __arch_info_begin 這兩個標號都是在
/linux/arch/arm/vmlinux.ld 這個腳本中定義的。在連接的時候,ld 會把相應體系架構
arch_info 放到這兩個標號之間。 
        __arch_info_begin = .;
       *(.arch.info.init)
    __arch_info_end = .;
――――――――――――――――――――――――――――――――――――――――――――――*/
 ldmia r3, {r4, r5, r6}
 sub r3, r3, r4   @ get offset between virt&phys
 //r5=__arch_info_begin的加載地址
 add r5, r5, r3   @ convert virt addresses to
 add r6, r6, r3   @ physical address space
/*―――――――――――――――――――――――――――――――――――――――――――――― 
    __arch_info_begin 和__arch_info_end  的類型都是 struct  machine_desc。其實
就是指向一個 machine_desc 結構首尾的兩個地址標號。 
    struct machine_desc 定義在 linux/include/asm-arm/mach/arch.h 中 
    struct machine_desc { 
        /* 
         * Note! The first four elements are used 
         * by assembler code in head.S 
         */ 
    unsigned int  nr;  /* architecture number */
 unsigned int __deprecated phys_ram; /* start of physical ram */
 unsigned int  phys_io; /* start of physical io */
 unsigned int  io_pg_offst; /* byte offset for io 
       * page tabe entry */
 const char  *name;  /* architecture name */
 unsigned long  boot_params; /* tagged list  */
 unsigned int  video_start; /* start of video RAM */
 unsigned int  video_end; /* end of video RAM */
 unsigned int  reserve_lp0 :1; /* never has lp0 */
 unsigned int  reserve_lp1 :1; /* never has lp1 */
 unsigned int  reserve_lp2 :1; /* never has lp2 */
 unsigned int  soft_reboot :1; /* soft reboot  */
 void   (*fixup)(struct machine_desc *,
      struct tag *, char **,
      struct meminfo *);
 void   (*map_io)(void);/* IO mapping function */
 void   (*init_irq)(void);
 struct sys_timer *timer;  /* system tick timer */
 void   (*init_machine)(void);
}; 
而對於我們的SEP4020其真正的定義是在/arch/arm/mach-sep4020/4020.c中
MACHINE_START(GFD4020, "4020 board")
 .phys_io = 0x10000000,
 .io_pg_offst = ((0xe0000000) >> 18) & 0xfffc,
 .boot_params = 0x30000100,
 .fixup  = fixup_gfd4020,
 .map_io  = sep4020_map_io,
 .init_irq =  sep4020_init_irq,
 .init_machine = sep4020_init,
 .timer  = &sep4020_timer,
MACHINE_END
    看到這裏,我們就不難明白下邊這條指令了,struct machine_desc 中第一個就是
nr,即 architecture number 
r3 = MACH_TYPE_GFD4020
――――――――――――――――――――――――――――――――――――――――――――――*/
1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type ,MACHINFO_TYPE = 0
//r1是由解壓縮程序/arch/arm/boot/compressed/head.S最後傳過來的,或者是uboot傳過來的體系結構號
 teq r3, r1    @ matches loader number?
 beq 2f    @ found
 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc
 cmp r5, r6
 blo 1b
 mov r5, #0    @ unknown machine
2: mov pc, lr
/*―――――――――――――――――從__lookup_machine_type返回――――――――――――――――――――――――――――― */
 movs r8, r5    @ invalid machine (r5=0)?是不是我們的SEP4020系統結構
 beq __error_a   @ yes, error 'a'
/*―――――――――――――――――――――――――――――――――――――――――――――― 
   設置 mmu 之前,設置臨時內核頁表 
―――――――――――――――――――――――――――――――――――――――――――――― */
 bl __create_page_tables
/*―――――――――――――――――――――――――――――――――――――――――――――― 
/*  我們在這裏只映射內核啓動的臨時頁表
 * 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.
 *
 * r8  = machinfo  體系結構信息
 * r9  = cpuid     cpu 的ID
 * r10 = procinfo  cpu信息
 *
 * Returns:
 *  r0, r3, r6, r7 corrupted
 *  r4 = physical page table address
 */
 .type __create_page_tables, %function
__create_page_tables:
/*―――――――――――――――――――――――――――――――――――――――――――――― */
// Page offset: 3GB  內核頁表的偏移在/inculde/asm/memory.h
#define PAGE_OFFSET  UL(0xc0000000)
#ifndef __virt_to_phys
#define __virt_to_phys(x) ((x) - PAGE_OFFSET + PHYS_OFFSET)
#define __phys_to_virt(x) ((x) - PHYS_OFFSET + PAGE_OFFSET)
#endif
而這其中的PHYS_OFFSET則是我們需要在我們的SEP4020的定義自己的主存ram的基址的物理地址,我們是在/include/asm-arm/arch-sep4020/memory.h中定義的
#define PHYS_OFFSET UL(0x30000000)
/*TEXT_OFFSET 是在在arch/arm/Makefile第140行,有
TEXT_OFFSET := $(textofs-y) 
第90行有 
textofs-y := 0x00008000 
所以TEXT_OFFSET := 0x00008000 
在153行有export TEXT_OFFSET將此變量輸出。*/
#define KERNEL_RAM_ADDR (PAGE_OFFSET + TEXT_OFFSET)  @其中TEXT_OFFSET = 0x8000
//swapper_pg_dir是放啓動時的臨時頁表的頁表基址(虛地址)
 .globl swapper_pg_dir
 .equ swapper_pg_dir, KERNEL_RAM_ADDR - 0x4000
//這個宏就是根據內核ram首址(虛擬地址)計算出我們內核頁表的頁表基址(物理地址)
 .macro pgtbl, rd
 ldr \rd, =(__virt_to_phys(KERNEL_RAM_ADDR - 0x4000))
 .endm
―――――――――――――――――――――――――――――――――――――――――――――― */
 pgtbl r4    @ page table address
//這樣r4 = 內核頁表的頁表基址(物理地址)
 /*
  * Clear the 16K level 1 swapper page table
  */
 mov r0, r4
 mov r3, #0
 //r6 = 內核的KERNEL_RAM_ADDR
 add r6, r0, #0x4000
 //首先對16k的一級頁表內容清0
1: str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
 str r3, [r0], #4
 teq r0, r6
 bne 1b
//PROCINFO_MMUFLAGS = 8;這樣 r7 = 0x00000c1e       mmuflags,一級段描述符 ,在proc-arm720.S 中定義
 ldr r7, [r10, #PROCINFO_MMUFLAGS] @ mmuflags
 /*
  * Create identity mapping for first MB of kernel to
  * cater for the MMU enable.  This identity mapping
  * will be removed by paging_init().  We use our current program
  * counter to determine corresponding section base address.
  這次一致映射主要是映射kernel前1MB的地址,這個映射最終會被後面paging_init()更新頁表
  */
  //獲取當前程序的段地址 = r6
 mov r6, pc, lsr #20   @ start of kernel section
 //將段地址 或上mmuflags,然後賦值給r3
 orr r3, r7, r6, lsl #20  @ flags + kernel base
 //開始放內核代碼的段映射描述符,段表基址爲r4,段表內的索引爲r6<<2;
 str r3, [r4, r6, lsl #2]  @ identity mapping
//這樣做是爲了解決後面剛開MMU是防止pc值飛掉了,在__turn_mmu_on函數中
 /*
  * Now setup the pagetables for our kernel direct
  * mapped region.  We round TEXTADDR down to the
  * nearest megabyte boundary.  It is assumed that
  * the kernel fits within 4 contigous 1MB sections.
  將kernel往後的4MB的地址建立虛實映射
  */
//#define TEXTADDR  KERNEL_RAM_ADDR即等於0xc0008000
//這裏的TEXTADDR是0xc0008000段對應的代碼和前面的pc對應的段地址是同一代碼,這樣做是爲了解決後面剛開MMU是防止pc值飛掉了
 add r0, r4,  #(TEXTADDR & 0xff000000) >> 18 @ start of kernel
 //把start of kernel(0xc0008000)的虛擬地址映射起來,即將它的段描述符保存到段表的相應索引處位置
 str r3, [r0, #(TEXTADDR & 0x00f00000) >> 18]!
 //建立start of kernel+1MB的虛擬地址映射
 add r3, r3, #1 << 20
 str r3, [r0, #4]!   @ KERNEL + 1MB
 //建立start of kernel+2MB的虛擬地址映射
 add r3, r3, #1 << 20
 str r3, [r0, #4]!   @ KERNEL + 2MB
 //建立start of kernel+3MB的虛擬地址映射
 add r3, r3, #1 << 20
 str r3, [r0, #4]   @ KERNEL + 3MB
 /*
  * Then map first 1MB of ram in case it contains our boot params.
  建立PAGE_OFFSET=0XC0000000地址的映射,因爲這個地址附近包含我們的uboot傳給linux的啓動參數
  */
 add r0, r4, #PAGE_OFFSET >> 18
 orr r6, r7, #PHYS_OFFSET
 str r6, [r0]
 mov pc, lr
―――――――――――――從__create_page_tables返回――――――――――――――――――――――――――――――――― */
 /*
  * The following calls CPU specific code in a position independent
  * manner.  See arch/arm/mm/proc-*.S for details.  r10 = base of
  * xxx_proc_info structure selected by __lookup_machine_type
  * above.  On return, the CPU will be ready for the MMU to be
  * turned on, and r0 will hold the CPU control register value.
  */
//__switch_data是一個標籤(即是一個地址),這個即是r13 = __mmap_switched(函數指針)
 ldr r13, __switch_data  @ address to jump to after
      @ mmu has been enabled
//將__enable_mmu(這是個與地址無關代碼)賦值給lr,等會返回執行,模擬一個函數棧
 adr lr, __enable_mmu  @ return (PIC) address
/*********************************************************************************************************
//#define PROCINFO_INITFUNC 12,在這裏跳轉執行arm720t架構的相應初始化代碼
__arm720_proc_info:
  .long 0x41807200    @ cpu_val
  .long 0xffffff00    @ cpu_mask
  .long   PMD_TYPE_SECT | \
   PMD_SECT_BUFFERABLE | \
   PMD_SECT_CACHEABLE | \
   PMD_BIT4 | \
   PMD_SECT_AP_WRITE | \
   PMD_SECT_AP_READ
  b __arm720_setup    @ cpu_flush
  
****************************************************************************************************/
 add pc, r10, #PROCINFO_INITFUNC
/*********************************************************************************************************/
//轉到__arm720_setup函數來執行
 .type __arm720_setup, #function
__arm720_setup:
 mov r0, #0
 //寫CP15的c7寄存器使cache的數據無效
 mcr p15, 0, r0, c7, c7, 0  @ invalidate caches
 //使整個TLB內部的地址變換條目無效
 mcr p15, 0, r0, c8, c7, 0  @ flush TLB (v4)
 //把CP15的寄存器c1傳給r0
 mrc p15, 0, r0, c1, c0  @ get control register
/*********************************************************************************************************
arm720_cr1_clear,arm720_cr1_set宏的定義
 .type arm710_cr1_clear, #object
 .type arm710_cr1_set, #object
arm710_cr1_clear:
 .word 0x0f3f
arm710_cr1_set:
 .word 0x013d(mmu使能,禁用地址對齊,cache使能,寫緩衝使能,小印地安序,系統保護,rom不保護)
****************************************************************************************************/
 ldr r5, arm720_cr1_clear
 bic r0, r0, r5
 ldr r5, arm720_cr1_set
//r0 = 0x013d(mmu使能,禁用地址對齊,cache使能,寫緩衝使能,小印地安序,系統保護,rom不保護)
 orr r0, r0, r5
//跳轉到__enable_mmu,相當於執行函數__enable_mmu
 mov pc, lr    @ __ret (head.S)
 .size __arm720_setup, . - __arm720_setup
/****************************************從__arm720_setup返回************************************************************/
/*********************************************************************************************************
/*
 * Setup common bits before finally enabling the MMU.  Essentially
 * this is just loading the page table pointer and domain access
 * registers.
 */
 .type __enable_mmu, %function
__enable_mmu:
//#define CONFIG_ALIGNMENT_TRAP 1是在/include/linux/Autoconfig.h定義
//Autoconfig.h是在make時根據Kconfig文件產生的
#ifdef CONFIG_ALIGNMENT_TRAP
 orr r0, r0, #CR_A    @CR_A=1 地址對齊
#else
 bic r0, r0, #CR_A
#endif
#ifdef CONFIG_CPU_DCACHE_DISABLE
 bic r0, r0, #CR_C  @CR_C= 2 D cache使能
#endif
#ifdef CONFIG_CPU_BPREDICT_DISABLE
 bic r0, r0, #CR_Z  @CR_Z = 11 分支預測
#endif
#ifdef CONFIG_CPU_ICACHE_DISABLE
 bic r0, r0, #CR_I   @CR_I = 12 I cache使能
#endif
//#define domain_val(dom,type) ((type) << (2*(dom)))在/include/asm-arm/Domain.h定義
//MMU中的域是一些段,大頁或小頁的集合,而在MMU的頁表描述符中有些位表示該描述符的域,指明該存儲空間所屬的域號0~15
 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
        domain_val(DOMAIN_IO, DOMAIN_CLIENT))
//配置cp15的域訪問控制寄存器
 mcr p15, 0, r5, c3, c0, 0  @ load domain access register
//配置cp15的頁表基址寄存器c2,r4就是頁表的首地址
 mcr p15, 0, r4, c2, c0, 0  @ load page table pointer
 b __turn_mmu_on
/*
 * Enable the MMU.  This completely changes the structure of the visible
 * memory space.  You will not be able to trace execution through this.
 * If you have an enquiry about this, *please* check the linux-arm-kernel
 * mailing list archives BEFORE sending another post to the list.
 *
 *  r0  = cp #15 control register
 *  r13 = *virtual* address to jump to upon completion
 *  r13是開MMU後將執行的第一個函數
 * other registers depend on the function called upon completion
 開啓MMU,這時你看到的世界將徹底是虛擬世界了,
 */
 .align 5
 .type __turn_mmu_on, %function
__turn_mmu_on:
 mov r0, r0
 //配置cp15的c1,開啓MMU
 mcr p15, 0, r0, c1, c0, 0  @ write control reg
 //因爲 ARM 720T 是三級流水線,所以運行三條指令,讓流水線充滿指令 
 //讀取id寄存器
 mrc p15, 0, r3, c0, c0, 0  @ read id reg
 //這時候剛開MMU的虛擬地址和實地址是一一映射,pc就不需要跳轉了
 mov r3, r3
 mov r3, r3
 //跳轉到__mmap_switched函數執行
 mov pc, r13
/****************************************從__enable_mmu返回************************************************************/
/******************************************__mmap_switched***************************************************************
/*
 * The following fragment of code is executed with the MMU on, and uses
 * absolute addresses; this is not position independent.
 *這段代碼是在開啓MMU後執行的,用的是絕對地址,不是地址無關的代碼
 *  r0  = cp#15 control register
 *  r1  = machine ID  是Uboot傳過來的體系架構號
 *  r9  = processor ID  CPU的id號
 */
 .type __mmap_switched, %function
__mmap_switched:
//這是把__data_loc對應的地址賦值給r3
 adr r3, __switch_data + 4
/*********************************************************************************************************
__switch_data這個數據塊就在其後定義的
.type __switch_data, %object
__switch_data:
 .long __mmap_switched
 .long __data_loc   @ r4,__data_loc ,__data_start,__bss_start都是在vmlinux.lds中定義的
 .long __data_start   @ r5
 .long __bss_start   @ r6
 .long _end    @ r7
 .long processor_id   @ r4
 .long __machine_arch_type  @ r5
 .long cr_alignment   @ r6
 .long init_thread_union + THREAD_START_SP @ sp
*********************************************************************************************************/ 
 ldmia r3!, {r4, r5, r6, r7}
 cmp r4, r5    @ Copy data segment if needed
 //把動態數據拷貝到全局數據區
1: cmpne r5, r6
 ldrne fp, [r4], #4  @fp是幀指針,即r11
 strne fp, [r5], #4
 bne 1b
//把BSS區清零
 mov fp, #0    @ Clear BSS (and zero fp)
1: cmp r6, r7
 strcc fp, [r6],#4  @cc是無符號小於
 bcc 1b
 ldmia r3, {r4, r5, r6, sp}
 //將cpu id保存到r4中
 str r9, [r4]   @ Save processor ID
 //將機器號保存到r5當中
 str r1, [r5]   @ Save machine type
/********************************************************************************************************* 
cr_alignment是爲中斷向量表是放在高地址還是放在低地址服務的,在中斷分析中會見到的
 .globl cr_alignment
 .globl cr_no_alignment
cr_alignment:
 .space 4
cr_no_alignment:
 .space 4
 //將MMU control寄存器分別保存到cr_alignment,和cr_no_alignment中
*********************************************************************************************************/ 
 bic r4, r0, #CR_A   @ Clear 'A' bit
 stmia r6, {r0, r4}   @ Save control register values
 //進入偉大的start_kernel函數
 b start_kernel
/****************************************從__enable_mmu返回************************************************************/
 
 .type __switch_data, %object
__switch_data:
 .long __mmap_switched
 .long __data_loc   @ r4
 .long __data_start   @ r5
 .long __bss_start   @ r6
 .long _end    @ r7
 .long processor_id   @ r4
 .long __machine_arch_type  @ r5
 .long cr_alignment   @ r6
 .long init_thread_union + THREAD_START_SP @ sp
 
發佈了20 篇原創文章 · 獲贊 8 · 訪問量 3萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章