Chinaunix首页 | 论坛 | 博客
  • 博客访问: 808990
  • 博文数量: 296
  • 博客积分: 5376
  • 博客等级: 大校
  • 技术积分: 2298
  • 用 户 组: 普通用户
  • 注册时间: 2009-03-14 19:02
文章分类

全部博文(296)

文章存档

2023年(2)

2020年(2)

2018年(2)

2017年(26)

2016年(4)

2015年(19)

2014年(12)

2013年(26)

2012年(84)

2011年(50)

2010年(41)

2009年(28)

分类:

2013-01-06 11:36:56

原文地址:ARMv7 linux的启动过程 作者:stanleymiao

VMLINUX

arch/arm/kernel/head.S

59 /*

60 * Kernel startup entry point.

61 * ---------------------------

62 *

63 * This is normally called from the decompressor code. The requirements

64 * are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,

65 * r1 = machine nr, r2 = atags pointer.

66 *

67 * This code is mostly position independent, so if you link the kernel at

68 * 0xc0008000, you call this at __pa(0xc0008000).

69 *

70 * See linux/arch/arm/tools/mach-types for the complete list of machine

71 * numbers for r1.

72 *

73 * We're trying to keep crap to a minimum; DO NOT add any machine specific

74 * crap here - that's what the boot loader (or in extreme, well justified

75 * circumstances, zImage) is for.

76 */

77 __HEAD

78 ENTRY(stext)

79 setmode PSR_F_BIT | PSR_I_BIT | SVC_MODE, r9 @ ensure svc mode

80 @ and irqs disabled


arch/arm/include/asm/assembler.h

170 #ifdef CONFIG_THUMB2_KERNEL

171 .macro setmode, mode, reg

172 mov \reg, #\mode

173 msr cpsr_c, \reg

174 .endm

175 #else

176 .macro setmode, mode, reg

177 msr cpsr_c, #\mode

178 .endm

179 #endif


81 mrc p15, 0, r9, c0, c0 @ get processor id

82 bl __lookup_processor_type @ r5=procinfo r9=cpuid


arch/arm/kernel/head-common.S

147 /*

148 * Read processor ID register (CP#15, CR0), and look up in the linker-built

149 * supported processor list. Note that we can't use the absolute addresses

150 * for the __proc_info lists since we aren't running with the MMU on

151 * (and therefore, we are not in the correct address space). We have to

152 * calculate the offset.

153 *

154 * r9 = cpuid

155 * Returns:

156 * r3, r4, r6 corrupted

157 * r5 = proc_info pointer in physical address space

158 * r9 = cpuid (preserved)

159 */

160 __lookup_processor_type:

161 adr r3, 3f

162 ldmia r3, {r5 - r7}

163 add r3, r3, #8

164 sub r3, r3, r7 @ get offset between virt&phys

165 add r5, r5, r3 @ convert virt addresses to

166 add r6, r6, r3 @ physical address space

167 1: ldmia r5, {r3, r4} @ value, mask

168 and r4, r4, r9 @ mask wanted bits

169 teq r3, r4

170 beq 2f

171 add r5, r5, #PROC_INFO_SZ @ sizeof(proc_info_list)

172 cmp r5, r6

173 blo 1b

174 mov r5, #0 @ unknown processor

175 2: mov pc, lr

176 ENDPROC(__lookup_processor_type)


189 /*

190 * Look in and arch/arm/kernel/arch.[ch] for

191 * more information about the __proc_info and __arch_info structures.

192 */

193 .align 2

194 3: .long __proc_info_begin

195 .long __proc_info_end

196 4: .long .


arch/arm/kernel/vmlinux.lds.S

38 __proc_info_begin = .;

39 *(.proc.info.init)

40 __proc_info_end = .;


arch/arm/mm/proc-v7.S

327 .section ".proc.info.init", #alloc, #execinstr

328

329 /*

330 * Match any ARMv7 processor core.

331 */

332 .type __v7_proc_info, #object

333 __v7_proc_info:

334 .long 0x000f0000 @ Required ID value

335 .long 0x000f0000 @ Mask for ID

336 .long PMD_TYPE_SECT | \

337 PMD_SECT_AP_WRITE | \

338 PMD_SECT_AP_READ | \

339 PMD_FLAGS

340 .long PMD_TYPE_SECT | \

341 PMD_SECT_XN | \

342 PMD_SECT_AP_WRITE | \

343 PMD_SECT_AP_READ

344 b __v7_setup

345 .long cpu_arch_name

346 .long cpu_elf_name

347 .long HWCAP_SWP|HWCAP_HALF|HWCAP_THUMB|HWCAP_FAST_MULT|HWCAP_EDSP

348 .long cpu_v7_name

349 .long v7_processor_functions

350 .long v7wbi_tlb_fns

351 .long v6_user_fns

352 .long v7_cache_fns

353 .size __v7_proc_info, . - __v7_proc_info


arch/arm/include/asm/procinfo.h

29 struct proc_info_list {

30 unsigned int cpu_val;

31 unsigned int cpu_mask;

32 unsigned long __cpu_mm_mmu_flags; /* used by head.S */

33 unsigned long __cpu_io_mmu_flags; /* used by head.S */

34 unsigned long __cpu_flush; /* used by head.S */

35 const char *arch_name;

36 const char *elf_name;

37 unsigned int elf_hwcap;

38 const char *cpu_name;

39 struct processor *proc;

40 struct cpu_tlb_fns *tlb;

41 struct cpu_user_fns *user;

42 struct cpu_cache_fns *cache;

43 };


83 movs r10, r5 @ invalid processor (r5=0)?

84 beq __error_p @ yes, error 'p'

85 bl __lookup_machine_type @ r5=machinfo


arch/arm/kernel/head-common.S

196 4: .long .

197 .long __arch_info_begin

198 .long __arch_info_end


arch/arm/kernel/vmlinux.lds.S

41 __arch_info_begin = .;

42 *(.arch.info.init)

43 __arch_info_end = .;


arch/arm/include/asm/mach/arch.h

17 struct machine_desc {

18 /*

19 * Note! The first four elements are used

20 * by assembler code in head.S, head-common.S

21 */

22 unsigned int nr; /* architecture number */

23 unsigned int phys_io; /* start of physical io */

24 unsigned int io_pg_offst; /* byte offset for io

25 * page tabe entry */

26

27 const char *name; /* architecture name */

28 unsigned long boot_params; /* tagged list */

29

30 unsigned int video_start; /* start of video RAM */

31 unsigned int video_end; /* end of video RAM */

32

33 unsigned int reserve_lp0 :1; /* never has lp0 */

34 unsigned int reserve_lp1 :1; /* never has lp1 */

35 unsigned int reserve_lp2 :1; /* never has lp2 */

36 unsigned int soft_reboot :1; /* soft reboot */

37 void (*fixup)(struct machine_desc *,

38 struct tag *, char **,

39 struct meminfo *);

40 void (*map_io)(void);/* IO mapping function */

41 void (*init_irq)(void);

42 struct sys_timer *timer; /* system tick timer */

43 void (*init_machine)(void);

44 };

45

46 /*

47 * Set of macros to define architecture features. This is built into

48 * a table by the linker.

49 */

50 #define MACHINE_START(_type,_name) \

51 static const struct machine_desc __mach_desc_##_type \

52 __used \

53 __attribute__((__section__(".arch.info.init"))) = { \

54 .nr = MACH_TYPE_##_type, \

55 .name = _name,

56

57 #define MACHINE_END

58 };


arch/arm/include/asm/assembler.h

749 MACHINE_START(OMAP3517EVM, "OMAP3517/AM3517 EVM")

750 .phys_io = 0x48000000,

751 .io_pg_offst = ((0xd8000000) >> 18) & 0xfffc,

752 .boot_params = 0x80000100,

753 .map_io = am3517_evm_map_io,

754 .init_irq = am3517_evm_init_irq,

755 .init_machine = am3517_evm_init,

756 .timer = &omap_timer,

757 MACHINE_END


200 /*

201 * Lookup machine architecture in the linker-build list of architectures.

202 * Note that we can't use the absolute addresses for the __arch_info

203 * lists since we aren't running with the MMU on (and therefore, we are

204 * not in the correct address space). We have to calculate the offset.

205 *

206 * r1 = machine architecture number

207 * Returns:

208 * r3, r4, r6 corrupted

209 * r5 = mach_info pointer in physical address space

210 */

211 __lookup_machine_type:

212 adr r3, 4b

213 ldmia r3, {r4, r5, r6}

214 sub r3, r3, r4 @ get offset between virt&phys

215 add r5, r5, r3 @ convert virt addresses to

216 add r6, r6, r3 @ physical address space

217 1: ldr r3, [r5, #MACHINFO_TYPE] @ get machine type


arch/arm/kernel/asm-offsets.c

99 DEFINE(SIZEOF_MACHINE_DESC, sizeof(struct machine_desc));

100 DEFINE(MACHINFO_TYPE, offsetof(struct machine_desc, nr));

101 DEFINE(MACHINFO_NAME, offsetof(struct machine_desc, name));


218 teq r3, r1 @ matches loader number?

219 beq 2f @ found

220 add r5, r5, #SIZEOF_MACHINE_DESC @ next machine_desc

221 cmp r5, r6

222 blo 1b

223 mov r5, #0 @ unknown machine

224 2: mov pc, lr

225 ENDPROC(__lookup_machine_type)


86 movs r8, r5 @ invalid machine (r5=0)?

87 beq __error_a @ yes, error 'a'

88 bl __vet_atags

89 bl __create_page_tables

arch/arm/kernel/head.S

206 /*

207 * Setup the initial page tables. We only setup the barest

208 * amount which are required to get the kernel running, which

209 * generally means mapping in the kernel code.

210 *

211 * r8 = machinfo

212 * r9 = cpuid

213 * r10 = procinfo

214 *

215 * Returns:

216 * r0, r3, r6, r7 corrupted

217 * r4 = physical page table address

218 */

219 __create_page_tables:

220 pgtbl r4 @ page table address


arch/arm/kernel/head.S

33 /*

34 * swapper_pg_dir is the virtual address of the initial page table.

35 * We place the page tables 16K below KERNEL_RAM_VADDR. Therefore, we must

36 * make sure that KERNEL_RAM_VADDR is correctly set. Currently, we expect

37 * the least significant 16 bits to be 0x8000, but we could probably

38 * relax this restriction to KERNEL_RAM_VADDR >= PAGE_OFFSET + 0x4000.

39 */

40 #if (KERNEL_RAM_VADDR & 0xffff) != 0x8000

41 #error KERNEL_RAM_VADDR must start at 0xXXXX8000

42 #endif

43

44 .globl swapper_pg_dir

45 .equ swapper_pg_dir, KERNEL_RAM_VADDR - 0x4000

46

47 .macro pgtbl, rd

48 ldr \rd, =(KERNEL_RAM_PADDR - 0x4000)

49 .endm


29 #define KERNEL_RAM_VADDR (PAGE_OFFSET + TEXT_OFFSET)

30 #define KERNEL_RAM_PADDR (PHYS_OFFSET + TEXT_OFFSET)


arch/arm/plat-omap/include/plat/memory.h

36 /*

37 * Physical DRAM offset.

38 */

39 #if defined(CONFIG_ARCH_OMAP1)

40 #define PHYS_OFFSET UL(0x10000000)

41 #else

42 #define PHYS_OFFSET UL(0x80000000)

43 #endif


arch/arm/Makefile

204 # The byte offset of the kernel image in RAM from the start of RAM.

205 TEXT_OFFSET := $(textofs-y)


112 textofs-y := 0x00008000


222 /*

223 * Clear the 16K level 1 swapper page table

224 */

225 mov r0, r4

226 mov r3, #0

227 add r6, r0, #0x4000

228 1: str r3, [r0], #4

229 str r3, [r0], #4

230 str r3, [r0], #4

231 str r3, [r0], #4

232 teq r0, r6

233 bne 1b

234

235 ldr r7, [r10, #PROCINFO_MM_MMUFLAGS] @ mm_mmuflags

236

237 /*

238 * Create identity mapping for first MB of kernel to

239 * cater for the MMU enable. This identity mapping

240 * will be removed by paging_init(). We use our current program

241 * counter to determine corresponding section base address.

242 */

243 mov r6, pc

244 mov r6, r6, lsr #20 @ start of kernel section

245 orr r3, r7, r6, lsl #20 @ flags + kernel base

246 str r3, [r4, r6, lsl #2] @ identity mapping

247

248 /*

249 * Now setup the pagetables for our kernel direct

250 * mapped region.

251 */

252 add r0, r4, #(KERNEL_START & 0xff000000) >> 18

253 str r3, [r0, #(KERNEL_START & 0x00f00000) >> 18]!


55 #define KERNEL_START KERNEL_RAM_VADDR

56 #define KERNEL_END _end


254 ldr r6, =(KERNEL_END - 1)

255 add r0, r0, #4

256 add r6, r4, r6, lsr #18

257 1: cmp r0, r6

258 add r3, r3, #1 << 20

259 strls r3, [r0], #4

260 bls 1b

281 /*

282 * Then map first 1MB of ram in case it contains our boot params.

283 */

284 add r0, r4, #PAGE_OFFSET >> 18

285 orr r6, r7, #(PHYS_OFFSET & 0xff000000)

286 .if (PHYS_OFFSET & 0x00f00000)

287 orr r6, r6, #(PHYS_OFFSET & 0x00f00000)

288 .endif

289 str r6, [r0]

334 mov pc, lr

335 ENDPROC(__create_page_tables)


91 /*

92 * The following calls CPU specific code in a position independent

93 * manner. See arch/arm/mm/proc-*.S for details. r10 = base of

94 * xxx_proc_info structure selected by __lookup_machine_type

95 * above. On return, the CPU will be ready for the MMU to be

96 * turned on, and r0 will hold the CPU control register value.

97 */

98 ldr r13, __switch_data @ address to jump to after

99 @ mmu has been enabled

100 adr lr, BSYM(__enable_mmu) @ return (PIC) address

101 ARM( add pc, r10, #PROCINFO_INITFUNC )


arch/arm/kernel/asm-offsets.c

106 DEFINE(PROCINFO_INITFUNC, offsetof(struct proc_info_list, __cpu_flush));


102 THUMB( add r12, r10, #PROCINFO_INITFUNC )

103 THUMB( mov pc, r12 )

104 ENDPROC(stext)



First, PROCINFO_INITFUNC will be called. Take ARMV7 as an example.


arch/arm/mm/proc-v7.S

177 /*

178 * __v7_setup

179 *

180 * Initialise TLB, Caches, and MMU state ready to switch the MMU

181 * on. Return in r0 the new CP15 C1 control register setting.

182 *

183 * We automatically detect if we have a Harvard cache, and use the

184 * Harvard cache control instructions insead of the unified cache

185 * control instructions.

186 *

187 * This should be able to cover all ARMv7 cores.

188 *

189 * It is assumed that:

190 * - cache type register is implemented

191 */

192 __v7_setup:

193 #ifdef CONFIG_SMP

194 mrc p15, 0, r0, c1, c0, 1

195 tst r0, #(1 << 6) @ SMP/nAMP mode enabled?

196 orreq r0, r0, #(1 << 6) | (1 << 0) @ Enable SMP/nAMP mode and

197 mcreq p15, 0, r0, c1, c0, 1 @ TLB ops broadcasting

198 #endif

199 adr r12, __v7_setup_stack @ the local stack


300 __v7_setup_stack:

301 .space 4 * 11 @ 11 registers


200 stmia r12, {r0-r5, r7, r9, r11, lr}

201 bl v7_flush_dcache_all


arch/arm/mm/cache-v7.S

20 /*

21 * v7_flush_dcache_all()

22 *

23 * Flush the whole D-cache.

24 *

25 * Corrupted registers: r0-r7, r9-r11 (r6 only in Thumb mode)

26 *

27 * - mm - mm_struct describing address space

28 */

29 ENTRY(v7_flush_dcache_all)

30 dmb @ ensure ordering with previous memory accesses

31 mrc p15, 1, r0, c0, c0, 1 @ read clidr


The Cache Level ID Register, which is introduced in ARMv7, identifies the type of cache, or caches, implemented at each level, up to a maximum of eight levels, and the Level of Coherency and Level of Unification for the cache hierarchy. See page B3-92 in armv7_arm.


32 ands r3, r0, #0x7000000 @ extract loc from clidr


LoC, bits [26:24], Level of Coherency for the cache hierarchy, see Clean, Invalidate, and Clean and Invalidate on page B2-11 in armv7_arm.


33 mov r3, r3, lsr #23 @ left align loc bit field

34 beq finished @ if loc is 0, then no need to clean

35 mov r10, #0 @ start clean at cache level 0

36 loop1:

37 add r2, r10, r10, lsr #1 @ work out 3x current cache level

38 mov r1, r0, lsr r2 @ extract cache type bits from clidr

39 and r1, r1, #7 @ mask of the bits for current cache only

40 cmp r1, #2 @ see what cache we have at this level


CtypeX value | Meaning, cache implemented at this level

000 No cache

001 Instruction cache only

010 Data cache only

011 Separate instruction and data caches

100 Unified cache

101, 11X Reserved


41 blt skip @ skip if no cache, or just i-cache

42 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr


Cache Size Selection Register, CSSELR. See page B3-95 in armv7_arm.


43 isb @ isb to sych the new cssr&csidr


An ISB instruction flushes the pipeline in the processor, so that all instructions that come after the ISB instruction in program order are fetched from cache or memory only after the ISB instruction has completed. Using an ISB ensures that the effects of context altering operations executed before the ISB are visible to the instructions fetched after the ISB instruction. See A3-49 in armv7_arm


44 mrc p15, 1, r1, c0, c0, 0 @ read the new csidr


The Cache Size ID Registers, CCSIDR, provide information about the architecture of the caches. See page B3-91 in armv7_arm.


45 and r2, r1, #7 @ extract the length of the cache lines


LineSize, bits [2:0], (Log2(Number of words in cache line)) -2. For example:

For a line length of 4 words: Log2(4) = 2, LineSize entry = 0. This is the minimum line length.

For a line length of 8 words: Log2(8) = 3, LineSize entry = 1.


46 add r2, r2, #4 @ add 4 (line length offset)

47 ldr r4, =0x3ff

48 ands r4, r4, r1, lsr #3 @ find maximum number on the way size


Associativity, bits [12:3], (Associativity of cache) - 1, therefore a value of 0 indicates an associativity of 1. The associativity does not have to be a power of 2.


49 clz r5, r4 @ find bit position of way size increment


Count Leading Zeros returns the number of binary zero bits before the first binary one bit in a value. See page A8-72 in armv7_arm.


50 ldr r7, =0x7fff

51 ands r7, r7, r1, lsr #13 @ extract max number of the index size


NumSets, bits [27:13], (Number of sets in cache) - 1, therefore a value of 0 indicates 1 set in the cache. The number of sets does not have to be a power of 2.


52 loop2:

53 mov r9, r4 @ create working copy of max way size

54 loop3:

55 ARM( orr r11, r10, r9, lsl r5 ) @ factor way and cache number into r11


r10, the cache level. From 0 to 7.

r9, Associativity of cache.

r5, The number of binary zero bits before the first binary one bit in r9.


56 THUMB( lsl r6, r9, r5 )

57 THUMB( orr r11, r10, r6 ) @ factor way and cache number into r11

58 ARM( orr r11, r11, r7, lsl r2 ) @ factor index number into r11


r7, Number of sets in cache.

r2, Log2(Number of words in cache line)

r11, Associativity of cache & the cache level


59 THUMB( lsl r6, r7, r2 )

60 THUMB( orr r11, r11, r6 ) @ factor index number into r11

61 mcr p15, 0, r11, c7, c14, 2 @ clean & invalidate by set/way

62 subs r9, r9, #1 @ decrement the way

63 bge loop3

64 subs r7, r7, #1 @ decrement the index

65 bge loop2

66 skip:

67 add r10, r10, #2 @ increment cache number

68 cmp r3, r10

69 bgt loop1

70 finished:

71 mov r10, #0 @ swith back to cache level 0

72 mcr p15, 2, r10, c0, c0, 0 @ select current cache level in cssr

73 dsb

74 isb

75 mov pc, lr

76 ENDPROC(v7_flush_dcache_all)


202 ldmia r12, {r0-r5, r7, r9, r11, lr}

203

204 mrc p15, 0, r0, c0, c0, 0 @ read main ID register


The Main ID Register, MIDR, provides identification information for the processor, including an implementer code for the device and a device ID number. See page B3-81 in armv7_arm.


205 and r10, r0, #0xff000000 @ ARM?

206 teq r10, #0x41000000


Bits [31:24] ASCII character Implementer

0x41 A ARM Limited

0x44 D Digital Equipment Corporation

0x4D M Motorola, Freescale Semiconductor Inc.

0x51 Q QUALCOMM Inc.

0x56 V Marvell Semiconductor Inc.

0x69 i Intel Corporation


207 bne 2f

208 and r5, r0, #0x00f00000 @ variant


Bits [23:20] Major revision number


209 and r6, r0, #0x0000000f @ revision


Bits [3:0] Minor revision number,


210 orr r0, r6, r5, lsr #20-4 @ combine variant and revision


233 2: mov r10, #0

234 #ifdef HARVARD_CACHE

235 mcr p15, 0, r10, c7, c5, 0 @ I+BTB cache invalidate

236 #endif

237 dsb


Data Synchronization Barrier. See page A3-49 in armv7_arm.


238 #ifdef CONFIG_MMU

239 mcr p15, 0, r10, c8, c7, 0 @ invalidate I + D TLBs

240 mcr p15, 0, r10, c2, c0, 2 @ TTB control register

241 orr r4, r4, #TTB_FLAGS


r4 is page table address.


arch/arm/mm/proc-v7.S

33 #ifndef CONFIG_SMP

34 /* PTWs cacheable, inner WB not shareable, outer WB not shareable */

35 #define TTB_FLAGS TTB_IRGN_WB|TTB_RGN_OC_WB

36 #define PMD_FLAGS PMD_SECT_WB

37 #else

38 /* PTWs cacheable, inner WBWA shareable, outer WBWA not shareable */

39 #define TTB_FLAGS TTB_IRGN_WBWA|TTB_S|TTB_NOS|TTB_RGN_OC_WBWA

40 #define PMD_FLAGS PMD_SECT_WBWA|PMD_SECT_S

41 #endif


242 mcr p15, 0, r4, c2, c0, 1 @ load TTB1


Translation Table Base Register 1. See page B3-116 in armv7_arm.


243 mov r10, #0x1f @ domains 0, 1 = manager

244 mcr p15, 0, r10, c3, c0, 0 @ load domain access register


The Domain Access Control Register, DACR, defines the access permission for each of the sixteen memory domains. See page B3-119 in armv7_arm.


245 /*

246 * Memory region attributes with SCTLR.TRE=1

247 *

248 * n = TEX[0],C,B

249 * TR = PRRR[2n+1:2n] - memory type

250 * IR = NMRR[2n+1:2n] - inner cacheable property

251 * OR = NMRR[2n+17:2n+16] - outer cacheable property

252 *

253 * n TR IR OR

254 * UNCACHED 000 00

255 * BUFFERABLE 001 10 00 00

256 * WRITETHROUGH 010 10 10 10

257 * WRITEBACK 011 10 11 11

258 * reserved 110

259 * WRITEALLOC 111 10 01 01

260 * DEV_SHARED 100 01

261 * DEV_NONSHARED 100 01

262 * DEV_WC 001 10

263 * DEV_CACHED 011 10

264 *

265 * Other attributes:

266 *

267 * DS0 = PRRR[16] = 0 - device shareable property

268 * DS1 = PRRR[17] = 1 - device shareable property

269 * NS0 = PRRR[18] = 0 - normal shareable property

270 * NS1 = PRRR[19] = 1 - normal shareable property

271 * NOS = PRRR[24+n] = 1 - not outer shareable

272 */

273 ldr r5, =0xff0a81a8 @ PRRR

274 ldr r6, =0x40e040e0 @ NMRR

275 mcr p15, 0, r5, c10, c2, 0 @ write PRRR

276 mcr p15, 0, r6, c10, c2, 1 @ write NMRR

277 #endif

278 adr r5, v7_crval


290 /* AT

291 * TFR EV X F I D LR S

292 * .EEE ..EE PUI. .T.T 4RVI ZWRS BLDP WCAM

293 * rxxx rrxx xxx0 0101 xxxx xxxx x111 xxxx < forced

294 * 1 0 110 0011 1100 .111 1101 < we want

295 */

296 .type v7_crval, #object

297 v7_crval:

298 crval clear=0x0120c302, mmuset=0x10c03c7d, ucset=0x00c01c7c


279 ldmia r5, {r5, r6}

280 #ifdef CONFIG_CPU_ENDIAN_BE8

281 orr r6, r6, #1 << 25 @ big-endian page tables

282 #endif


EE, bit [25] Exception Endianness bit


283 mrc p15, 0, r0, c1, c0, 0 @ read control register


System Control Register, See page B3-96 in armv7_arm.


284 bic r0, r0, r5 @ clear bits them

285 orr r0, r0, r6 @ set them

286 THUMB( orr r0, r0, #1 << 30 ) @ Thumb exceptions

287 mov pc, lr @ return to head.S:__ret

288 ENDPROC(__v7_setup)



__enable_mmu was stored in the register lr.


arch/arm/kernel/head.S

155 /*

156 * Setup common bits before finally enabling the MMU. Essentially

157 * this is just loading the page table pointer and domain access

158 * registers.

159 */

160 __enable_mmu:

161 #ifdef CONFIG_ALIGNMENT_TRAP

162 orr r0, r0, #CR_A

163 #else

164 bic r0, r0, #CR_A

165 #endif

166 #ifdef CONFIG_CPU_DCACHE_DISABLE

167 bic r0, r0, #CR_C

168 #endif


Cache enable bit: This is a global enable bit for data and unified caches.


169 #ifdef CONFIG_CPU_BPREDICT_DISABLE

170 bic r0, r0, #CR_Z

171 #endif


Branch prediction enable bit.


172 #ifdef CONFIG_CPU_ICACHE_DISABLE

173 bic r0, r0, #CR_I

174 #endif


Instruction cache enable bit: This is a global enable bit for instruction caches.


175 mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \

176 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \

177 domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \

178 domain_val(DOMAIN_IO, DOMAIN_CLIENT))


arch/arm/include/asm/domain.h

13 /*

14 * Domain numbers

15 *

16 * DOMAIN_IO - domain 2 includes all IO only

17 * DOMAIN_USER - domain 1 includes all user memory only

18 * DOMAIN_KERNEL - domain 0 includes all kernel memory only

19 *

20 * The domain numbering depends on whether we support 36 physical

21 * address for I/O or not. Addresses above the 32 bit boundary can

22 * only be mapped using supersections and supersections can only

23 * be set for domain 0. We could just default to DOMAIN_IO as zero,

24 * but there may be systems with supersection support and no 36-bit

25 * addressing. In such cases, we want to map system memory with

26 * supersections to reduce TLB misses and footprint.

27 *

28 * 36-bit addressing and supersections are only available on

29 * CPUs based on ARMv6+ or the Intel XSC3 core.

30 */

31 #ifndef CONFIG_IO_36

32 #define DOMAIN_KERNEL 0

33 #define DOMAIN_TABLE 0

34 #define DOMAIN_USER 1

35 #define DOMAIN_IO 2

36 #else

37 #define DOMAIN_KERNEL 2

38 #define DOMAIN_TABLE 2

39 #define DOMAIN_USER 1

40 #define DOMAIN_IO 0

41 #endif

42

43 /*

44 * Domain types

45 */

46 #define DOMAIN_NOACCESS 0

47 #define DOMAIN_CLIENT 1

48 #define DOMAIN_MANAGER 3

49

50 #define domain_val(dom,type) ((type) << (2*(dom)))


179 mcr p15, 0, r5, c3, c0, 0 @ load domain access register

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


Translation Table Base Register 0. See page B3-113 in armv7_arm.

181 b __turn_mmu_on

182 ENDPROC(__enable_mmu)

183

184 /*

185 * Enable the MMU. This completely changes the structure of the visible

186 * memory space. You will not be able to trace execution through this.

187 * If you have an enquiry about this, *please* check the linux-arm-kernel

188 * mailing list archives BEFORE sending another post to the list.

189 *

190 * r0 = cp#15 control register

191 * r13 = *virtual* address to jump to upon completion

192 *

193 * other registers depend on the function called upon completion

194 */

195 .align 5

196 __turn_mmu_on:

197 mov r0, r0

198 mcr p15, 0, r0, c1, c0, 0 @ write control reg

199 mrc p15, 0, r3, c0, c0, 0 @ read id reg

200 mov r3, r3

201 mov r3, r13

202 mov pc, r3

203 ENDPROC(__turn_mmu_on)



__switch_data was stored in the register r13.


arch/arm/kernel/head-common.S

18 .align 2

19 .type __switch_data, %object

20 __switch_data:

21 .long __mmap_switched

22 .long __data_loc @ r4

23 .long _data @ r5

24 .long __bss_start @ r6

25 .long _end @ r7

26 .long processor_id @ r4

27 .long __machine_arch_type @ r5

28 .long __atags_pointer @ r6

29 .long cr_alignment @ r7

30 .long init_thread_union + THREAD_START_SP @ sp


arch/arm/kernel/init_task.c

17 /*

18 * Initial thread structure.

19 *

20 * We need to make sure that this is 8192-byte aligned due to the

21 * way process stacks are handled. This is done by making sure

22 * the linker maps this in the .text segment right after head.S,

23 * and making head.S ensure the proper alignment.

24 *

25 * The things we do for performance..

26 */

27 union thread_union init_thread_union __init_task_data =

28 { INIT_THREAD_INFO(init_task) };


We created the first thread manually!


arch/arm/include/asm/thread_info.h

71 #define INIT_THREAD_INFO(tsk) \

72 { \

73 .task = &tsk, \

74 .exec_domain = &default_exec_domain, \

75 .flags = 0, \

76 .preempt_count = INIT_PREEMPT_COUNT, \

77 .addr_limit = KERNEL_DS, \

78 .cpu_domain = domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \

79 domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \

80 domain_val(DOMAIN_IO, DOMAIN_CLIENT), \

81 .restart_block = { \

82 .fn = do_no_restart_syscall, \

83 }, \

84 }


include/linux/init_task.h

106 /*

107 * INIT_TASK is used to set up the first task table, touch at

108 * your own risk!. Base=0, limit=0x1fffff (=2MB)

109 */

110 #define INIT_TASK(tsk) \

111 { \

112 .state = 0, \

113 .stack = &init_thread_info, \

114 .usage = ATOMIC_INIT(2), \

115 .flags = PF_KTHREAD, \

116 .lock_depth = -1, \

117 .prio = MAX_PRIO-20, \

118 .static_prio = MAX_PRIO-20, \

119 .normal_prio = MAX_PRIO-20, \

120 .policy = SCHED_NORMAL, \

121 .cpus_allowed = CPU_MASK_ALL, \

122 .mm = NULL, \

123 .active_mm = &init_mm, \

124 .se = { \

125 .group_node = LIST_HEAD_INIT(tsk.se.group_node), \

126 }, \

127 .rt = { \

128 .run_list = LIST_HEAD_INIT(tsk.rt.run_list), \

129 .time_slice = HZ, \

130 .nr_cpus_allowed = NR_CPUS, \

131 }, \

132 .tasks = LIST_HEAD_INIT(tsk.tasks), \

133 .pushable_tasks = PLIST_NODE_INIT(tsk.pushable_tasks, MAX_PRIO), \

134 .ptraced = LIST_HEAD_INIT(tsk.ptraced), \

135 .ptrace_entry = LIST_HEAD_INIT(tsk.ptrace_entry), \

136 .real_parent = &tsk, \

137 .parent = &tsk, \

138 .children = LIST_HEAD_INIT(tsk.children), \

139 .sibling = LIST_HEAD_INIT(tsk.sibling), \

140 .group_leader = &tsk, \

141 .real_cred = &init_cred, \

142 .cred = &init_cred, \

143 .cred_guard_mutex = \

144 __MUTEX_INITIALIZER(tsk.cred_guard_mutex), \

145 .comm = "swapper", \

146 .thread = INIT_THREAD, \

147 .fs = &init_fs, \

148 .files = &init_files, \

149 .signal = &init_signals, \

150 .sighand = &init_sighand, \

151 .nsproxy = &init_nsproxy, \

152 .pending = { \

153 .list = LIST_HEAD_INIT(tsk.pending.list), \

154 .signal = {{0}}}, \

155 .blocked = {{0}}, \

156 .alloc_lock = __SPIN_LOCK_UNLOCKED(tsk.alloc_lock), \

157 .journal_info = NULL, \

158 .cpu_timers = INIT_CPU_TIMERS(tsk.cpu_timers), \

159 .fs_excl = ATOMIC_INIT(0), \

160 .pi_lock = __RAW_SPIN_LOCK_UNLOCKED(tsk.pi_lock), \

161 .timer_slack_ns = 50000, /* 50 usec default slack */ \

162 .pids = { \

163 [PIDTYPE_PID] = INIT_PID_LINK(PIDTYPE_PID), \

164 [PIDTYPE_PGID] = INIT_PID_LINK(PIDTYPE_PGID), \

165 [PIDTYPE_SID] = INIT_PID_LINK(PIDTYPE_SID), \

166 }, \

167 .dirties = INIT_PROP_LOCAL_SINGLE(dirties), \

168 INIT_IDS \

169 INIT_PERF_EVENTS(tsk) \

170 INIT_TRACE_IRQFLAGS \

171 INIT_LOCKDEP \

172 INIT_FTRACE_GRAPH \

173 INIT_TRACE_RECURSION \

174 INIT_TASK_RCU_PREEMPT(tsk) \

175 }


31

32 /*

33 * The following fragment of code is executed with the MMU on in MMU mode,

34 * and uses absolute addresses; this is not position independent.

35 *

36 * r0 = cp#15 control register

37 * r1 = machine ID

38 * r2 = atags pointer

39 * r9 = processor ID

40 */

41 __mmap_switched:

42 adr r3, __switch_data + 4

43

44 ldmia r3!, {r4, r5, r6, r7}

45 cmp r4, r5 @ Copy data segment if needed

46 1: cmpne r5, r6

47 ldrne fp, [r4], #4

48 strne fp, [r5], #4

49 bne 1b

50

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

52 1: cmp r6, r7

53 strcc fp, [r6],#4

54 bcc 1b

55

56 ARM( ldmia r3, {r4, r5, r6, r7, sp})


We got the sp. It means we are in the thread 0 now, because the macro “current” returns task 0.


arch/arm/include/asm/thread_info.h

94 static inline struct thread_info *current_thread_info(void)

95 {

96 register unsigned long sp asm ("sp");

97 return (struct thread_info *)(sp & ~(THREAD_SIZE - 1));

98 }


arch/arm/include/asm/current.h

8 static inline struct task_struct *get_current(void)

9 {

10 return current_thread_info()->task;

11 }

12

13 #define current (get_current())


57 THUMB( ldmia r3, {r4, r5, r6, r7} )

58 THUMB( ldr sp, [r3, #16] )

59 str r9, [r4] @ Save processor ID

60 str r1, [r5] @ Save machine type

61 str r2, [r6] @ Save atags pointer

62 bic r4, r0, #CR_A @ Clear 'A' bit

63 stmia r7, {r0, r4} @ Save control register values

64 b start_kernel

65 ENDPROC(__mmap_switched)





Now we enter the C code finally.

阅读(2270) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~