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