|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
分析内核顶层Makefile,以及arch/ARM/Makefile可知,从u-boot跳到内核后,第一个启动的文件是arch/arm/kernel/head.S。接下来就围绕这个文件来分析Linux架构/开发板相关的引导过程。- E, K5 }2 J# O" \* A% P* U! E
: `$ G' O6 s6 d7 Q/******************************以下仅分析重要部分********************************/2 \% J, z; T) @# e9 _( |
5 w' v4 V/ y! y#include "head-common.S" //下面会调用到这个文件里面的函数
; b9 Q) p2 u+ W$ o% p" a, y1 g0 c9 g, W* L8 w
......
9 ~# E) O1 Y( P! C3 M7 B) j
* v) q" A/ Y" e/*; n" j5 ?+ ^; P, M6 P6 `
* Kernel startup entry point.8 k( ^# k0 B1 G4 ^, p8 Y
* ---------------------------4 G& O1 q, v/ i6 h( E: |
*
# {9 c' `/ V# E5 T6 m* This is normally called from the decompressor code. The requirements( X! A3 e8 w# R& ~, S |
* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,
. n6 q9 E o! F; z7 O* r1 = machine nr, r2 = atags pointer.) p0 Z9 z2 s/ l! E/ B% H
*3 W/ R& f7 S6 G
* This code is mostly position independent, so if you link the kernel at+ a t) ?) Q0 U8 W1 E* f2 I0 S) h3 c
* 0xc0008000, you call this at __pa(0xc0008000).
0 e. v" R( B2 \9 O*
( L8 T/ }7 _. R- Y" U! |" t* See linux/arch/arm/tools/mach-types for the complete list of machine
# p9 D; ~$ w1 C, q* numbers for r1., _% p5 y- o" ]* q
* ........
, z4 h+ M+ Y7 D, }1 E*/0 }) r; k K3 V7 Y4 e$ \+ R6 p
.section ".text.head", "ax" //".text.head"段,在vmlinux.lds链接文件中定义8 i7 q% |0 ?2 w
ENTRY(stext)/ e3 O# w: ?' S$ p
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE //确保进入管理模式并禁止中断
8 k! H, m/ Q3 D mrc p15, 0, r9, c0, c0 // r9 = CPU ID/ Y$ s8 u3 l% f/ B# T( z* ]) c i
bl __lookup_processor_type // r5=procinfo r9=cpuid
. O( A7 z9 Z* b! F7 F* s movs r10, r5 //如果不支持该CPU则r5=0# i; Q3 f% Z4 b; s4 p- {
beq __error_p //如果r5=0,则打印错误信息
* g- l4 \( L: X. u$ Y+ x bl __lookup_machine_type // r5=machinfo" t+ \. j# g) C8 M+ C
movs r8, r5 // 如果不支持该开发板r5=0
+ K U- Z# p9 s7 ?; k beq __error_a //如果r5=0,则打印错误信息
2 `4 D3 T- D$ D bl __vet_atags" s% K" t* v1 b* N3 T
bl __create_page_tables" R/ m* I. [! S3 C+ J
+ m6 M5 v' Q% z' a .......& x' f- r8 l+ I' s
ldr r13, __switch_data @ address to jump to after mmu has been enabled/ Y0 J! t: x; c$ N" Q
adr lr, __enable_mmu @ return (PIC) address
' b7 e. A3 c, C8 d; o* [% M add pc, r10, #PROCINFO_INITFUNC
* u+ d( }! W& [; zENDPROC(stext)" X, F2 d Q( _+ i8 k8 J0 X
. e4 Y- T0 [# x4 A% V2 D.......
6 ?# u$ F- d7 k, o% d0 A/ r
- r! \) `3 o( n& B1 m1 y- J架构/开发板相关的引导过程就是由以上蓝色部分的函数来完成的,都是汇编子程序,下面逐个分析。' d# X- A/ u, ^4 Z( C/ O0 E: Q: K0 P
2 F( U5 n8 \- |5 r8 t4 h( J__lookup_processor_type子程序在arch/arm/kernel/head-common.S文件中定义
1 \: k' q- W8 V% Q5 x6 x2 D+ L& t6 |4 _( O4 r# P% O7 B1 ?
/*% Q, d" R1 C, G5 V4 Q4 h4 y/ Q" p- M
* r9 = cpuid
2 {% g" |2 [$ @' p * Returns:
5 |3 H1 A+ c, h1 o! y# p& F2 i0 _ * r3, r4, r6 corrupted
, m; j3 A6 c5 f; x1 r. n( G, J * r5 = proc_info pointer in physical address space
* g/ h% t- Z9 `0 p * r9 = cpuid (preserved)
# r# ] G! A. R/ _. C1 l9 V */3 P3 G/ w# W1 q, T h2 {3 G
. ]0 t5 r. r3 s__lookup_processor_type:
$ Y4 z& I8 J o adr r3, 3f //将下面3标号的物理地址存到r3寄存器; ^, E" Y3 x, t. K1 ? B+ D* z
8 R! s. j/ W( k* K3 U8 Z5 N/* r5 = __proc_info_begin,r6 = __proc_info_end 的虚拟地址,r7 = 3标号的虚拟地址 */
6 s- a0 _+ H9 A7 H2 q ldmda r3, {r5 - r7}7 Z2 L3 p' ?: Y0 h
sub r3, r3, r7 // r3 = r3 - r7,物理地址与虚拟地址之差0 D& R) E/ \/ ~" u
add r5, r5, r3 // r5 = __ proc_info_begin 对应的物理地址
, R3 w9 |5 q- S6 U: H/ ^ add r6, r6, r3 // r6 = __proc_info_end 对应的物理地址
% Z- {2 G+ c8 |: L! m1: ldmia r5, {r3, r4} // r3 = cpu_val,r4 = cpu_mask 这两个成员在proc_info_list中定义
6 }! Y) I# X' q/ z# Y and r4, r4, r9 // r4 = r4&r9 = cpu_mask & 最开始从CP15传入的cpu id4 l# Y5 P1 S }: f# p+ P
teq r3, r4
6 A; h# ~+ u& X& W/ a4 E7 _7 E) Z4 [- f beq 2f //相等则返回0 q4 d0 d) @; f( C
add r5, r5, #PROC_INFO_SZ //下一个pro_info_list ,sizeof(proc_info_list)
# C* d' S' f1 N2 k1 S+ o cmp r5, r6 //判断是否已经比较完所有的proc_info_list
. D( N Z5 {9 t, n! L( j blo 1b //否则继续比较
9 E% _; J, P* M% o/ I/ D: u# P4 y mov r5, #0 //比较完后还是没有匹配的proc_info_list结构,r5 = 00 Q! ~5 O6 X9 F, N$ @
2: mov pc, lr // 返回
" R1 F# t2 e' |- i% X& J6 v2 XENDPROC(__lookup_processor_type)% W! n+ Q$ A7 y7 a5 M. d
( }. S8 `6 N! A- Y8 K' _/ @.......- |6 r# n: C: c' j+ `
+ C% r) O0 v3 N! f
/*4 {& R1 r$ G/ C
* Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for" m% \( j) _+ J) R1 D# j# G
* more information about the __proc_info and __arch_info structures.
- z6 X \; q$ C/ N- Q */
' G, U& f1 Q" o# _6 p .long __proc_info_begin //proc_info_list结构体的开始地址(虚拟地址)& q. K- b0 d- Z a
.long __proc_info_end //proc_info_list结构体的结束地址(虚拟地址)
. B1 q/ v! V, w3: .long . // 3标号在内存中的的物理地址) b+ n5 T0 z5 \5 b+ k$ @
.long __arch_info_begin $ d6 }; z& I J0 k( ]) V
.long __arch_info_end - m8 Q! O, g6 U1 m7 h3 o
6 a7 T; U7 P5 F2 S8 A! _
$ N) r* i! B" H! Q4 D; ?+ N7 M: k @) h
proc_info_list结构体在arch/arm/include/asm中定义
. y* n; N$ g. f) w% X
, [, ~( I1 v3 C. `- B6 ]7 i( @struct proc_info_list {
1 G& i4 ^7 P& N1 M7 K5 h unsigned int cpu_val;
0 G2 u2 y; N- C7 j unsigned int cpu_mask;
Q3 H; \" F$ [7 ^% `3 m* v( k- ] unsigned long __cpu_mm_mmu_flags; /* used by head.S */
6 J+ b+ G f# Y9 R/ q unsigned long __cpu_io_mmu_flags; /* used by head.S */" a& ^4 Z# h- Z; P+ I( j j
unsigned long __cpu_flush; /* used by head.S */
% _2 Q# s' k3 K6 x L6 Z* S const char *arch_name;
' l, _6 ~4 ?8 ]6 ` const char *elf_name;
~, [& h- R: O" }$ u2 S unsigned int elf_hwcap;. m8 ^. x) T$ }# o6 r
const char *cpu_name;
2 z- E' c; A( u, @2 a struct processor *proc;6 _. z1 ]7 ^# T) a; {7 P! \( O
struct cpu_tlb_fns *tlb;% U+ \4 `3 [* j) x; N' h
struct cpu_user_fns *user;1 o6 V5 `( M) M
struct cpu_cache_fns *cache;' S. ]: K% b/ v! x# Z7 [* \
};, P" K3 u7 {8 Y: p5 g/ j/ A
# w+ r$ {9 s: @ ~7 M+ r$ \对于S3C2440开发板的匹配,它的CPU ID是0x41129200,可查询协处理器的CP15获知。" k: l0 R9 f# W8 j* a& d" Y# ^
, @4 M) R9 T! B8 ^1 d而在arch/arm/mm/proc_arm920.S中定义的__arm920_proc_info结构如下! h2 F) [8 B8 I
7 D4 c, ?# d6 O/ X__arm920_proc_info:* j- E* d+ V) ?
.long 0x410092007 j( z, w8 @: @! ~$ M3 I( n$ @
.long 0xff00fff0
; t% h1 g' l( y7 F% E- A
9 j* g. z. G. z& E3 l J, A ........
4 T3 G. k" w8 m6 X6 O! ?- _7 s% o+ W' t5 F) s/ c/ u t
即r3 = cpu_val = 0x41009200,r4 = cpu_mask = 0xff00ff00,刚好匹配。
# w* S7 `$ |) D) O3 U
2 Q$ q2 Y7 Y9 ?6 o4 Z# v
( y4 Y9 q7 o7 ]6 L0 m
7 y. v! v& h- G__lookup_machine_type子程序也在arch/arm/kernel/head-common.S文件中定义/ Q, X4 K; [6 _+ g0 `; I
1 p/ P$ x% p, h+ I/*% i$ _4 \0 {5 Y: o
# j* L$ z' d3 B
* ....3 \3 T+ \5 @1 `1 B: m7 P: S' X
6 ?% ~' r: P( x% b
* r1 = machine architecture number7 y" a9 S) n7 K) w" y0 K, l" u
* Returns:
3 l6 f" k5 H1 C- V+ r% f' @ * r3, r4, r6 corrupted9 g0 Z- ^9 U- g$ p
* r5 = mach_info pointer in physical address space
& G1 ?+ Z2 F7 | e2 t */
* V/ _% `; j+ }__lookup_machine_type:6 v* S- I8 _0 L, w, m; l8 ^3 P
adr r3, 3b //获得3标号的物理地址
) [6 E6 F, D9 h0 B3 \* K
0 q0 a: j. f; I) n# _" l0 e) W; n/* r4 = __arch_info_begin,r6 = __arch_info_end 的虚拟地址,r7 = 3标号的虚拟地址 */
# P% D- p4 F6 a& o, M$ E
/ v# w `, {1 _9 J ldmia r3, {r4, r5, r6} - q/ V3 C6 x1 _1 ]) ^/ O- J- _
sub r3, r3, r4 // r3 = r3 - r4 物理地址与虚拟地址之差
: o8 M" M7 l: i) A; |$ d: s add r5, r5, r3 // r5 = __arch_info_begin 的物理地址
; V; `9 [3 y; ` add r6, r6, r3 // r6 = __arch_info_end 的物理地址+ O( K7 u/ H8 u0 \* P8 E; [
1: ldr r3, [r5, #MACHINFO_TYPE] // r5 是machine_desc结构体的地址4 @3 j) M/ t% {9 h9 g
teq r3, r1 //判断从r1传入的机器ID是否匹配) a3 s0 J; q( j9 }
beq 2f //匹配则返回9 ~: ^8 B+ J" r. m
add r5, r5, #SIZEOF_MACHINE_DESC //否则,指向下一个 machine_desc- Z! ]4 T9 t( f9 {# |2 ~% h
cmp r5, r6 //是否已经比较完所有的machine_desc结构
5 S& I! t8 c- v+ g blo 1b //没有则继续比较
% M* w# @6 Z; p0 k mov r5, #0 //比较完毕之后都没有找到匹配的,r5 = 0# c1 }4 o0 w- J+ }* ^- }. J% C
2: mov pc, lr //返回
C4 @# Z$ ^) Y; N3 W3 sENDPROC(__lookup_machine_type)+ l& R/ ]+ A+ C# Z5 `
: [( x/ _9 ]# [: {
/ K4 N( s2 b" ?0 u1 `! \3 x! b2 ^
machine_desc结构在 arch/arm/include/asm/mach/arch.h中定义
4 h5 V8 _% G5 @( G7 r# Y7 ^/ f9 T4 v& ~4 Y+ i- K) ~$ f- y
struct machine_desc {
, u5 ^" N) ^5 d6 j/ }2 B$ R /*+ s# |- v/ V6 Y5 M( K- F- p2 l. k
* Note! The first four elements are used" t& W! B3 J' I3 Z
* by assembler code in head.S, head-common.S, N- k6 o8 G2 v8 I1 O
*/
. e/ k$ D: L+ b, Y/ f8 X unsigned int nr; /* architecture number */
4 s# g# }$ @' s& \ X unsigned int phys_io; /* start of physical io */. x) @% t6 a G) w
unsigned int io_pg_offst; /* byte offset for io ( m1 \8 `/ x4 U5 l- U3 y, Q
* page tabe entry *// W( ^ c6 w* Q: A3 t+ { m
: D( X# L% W4 b) c C4 h const char *name; /* architecture name */
& E: b Z; n6 L2 Y. ? unsigned long boot_params; /* tagged list */# A% R+ }2 `* y% g! x
& \2 b2 V+ [* ?9 X- l/ R! v
unsigned int video_start; /* start of video RAM */2 c2 Q' y3 k# y j' U# ~
unsigned int video_end; /* end of video RAM */0 I' f! b# x4 z" y8 m
4 i/ p; {8 e' b/ [' o! z5 S) M2 n# H unsigned int reserve_lp0 :1; /* never has lp0 */5 B! X/ B0 b* q
unsigned int reserve_lp1 :1; /* never has lp1 */
$ z# i4 v' U" `% s; C unsigned int reserve_lp2 :1; /* never has lp2 */
2 R0 d& |6 j; E" K unsigned int soft_reboot :1; /* soft reboot */% h1 e: N- v8 M7 O: K, d1 L
void (*fixup)(struct machine_desc *,- p0 m2 H3 e c ^& l( \+ `1 w
struct tag *, char **,! w! N4 g1 x; y- W4 ~& T; z) \
struct meminfo *);
. ~/ r: x0 `4 k5 }- T void (*map_io)(void);/* IO mapping function */
% R% f: Z( }' Y% ~8 z void (*init_irq)(void);
( B1 c9 k5 c) L( D struct sys_timer *timer; /* system tick timer */6 D. u( M- R$ ?, B4 L
void (*init_machine)(void);0 u4 n1 V! \5 {3 @: X& @
};
! f) {# M/ e# s e* e7 T& N5 q& Q
3 t9 q& S; T- f: T#define MACHINE_START(_type,_name) \. G: {) P$ D2 r5 v* y3 H1 p4 b3 J/ _6 I
static const struct machine_desc __mach_desc_##_type \
9 b3 b5 u8 T+ d* @ __used \
+ N/ |! b1 T: T: ^. l: r0 o+ i __attribute__((__section__(".arch.info.init"))) = { \# ~: R" O) @2 V# ? \8 x8 \' q
.nr = MACH_TYPE_##_type, \
J+ C6 W8 r3 ?7 B# j2 O .name = _name,. e# s! B# H# a$ L
+ `6 B$ F2 y" a* b5 F( F0 W8 m#define MACHINE_END \
( _. U& R- A) ~: [$ C};
* j$ ?$ C2 z: z# E/ j+ B+ o. U/ ]6 ]+ a {! z
! Q) D0 e+ k" P+ y+ S. b& T$ ?6 N+ [/ y3 y3 K
MACHINE_START(S3C2440, "SMDK2440")
* b/ k7 f# |% i- @, u7 a .phys_io = S3C2410_PA_UART,
; _; a6 [' I' ?( s7 f% H; Z; E .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,0 h! K* d' O; J" j! f/ D
.boot_params = S3C2410_SDRAM_PA + 0x100,
/ ~+ Q8 }! J8 U, B3 h& d9 W( u2 U" J/ q2 P
.init_irq = s3c24xx_init_irq,8 t$ z! A: f: F+ m% j. r3 s
.map_io = smdk2440_map_io,
5 F5 C7 J; J2 y1 Y( J .init_machine = smdk2440_machine_init,: u$ I2 |7 ?2 M3 i' p y
.timer = &s3c24xx_timer,( i3 i& W2 m) ]7 s
MACHINE_END
& `8 N0 X( t; }' n) E w1 s# ?. H
2 p- \) z$ T& ]+ \% Q- n" O7 U3 D& q
, s9 p: F1 S$ {# t
# C( z" @) E3 N3 i' J& H, b由上面二个定义得到S3C2440 的machine_desc结构体
0 _; c/ o. x4 y" K$ W' r! r4 g, `" o/ f1 T7 Z( }& {4 N$ o. Z
static const struct machine_desc __mach_desc_S3C2440
; b$ I5 {( n& P$ n8 K* ^# n __used 8 D- b$ c+ j" m/ L5 d
__attribute__((__section__(".arch.info.init"))) =5 l W4 E7 {2 \1 x. `' }
; _& i; E1 I: I* Y0 U$ L/ _) c' F3 i2 K{
# H. o) i, R- K$ U9 Y .nr = MACH_TYPE_S3C2440, - {$ D+ L9 x% L& }
.name = "SMDK2440",
) w7 n+ W5 [5 g. ^0 Y$ f6 M0 t .phys_io = S3C2410_PA_UART,
) a2 a9 }& U* Q$ `4 J0 F' `/ [ .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,2 i2 E" m* i9 T0 R- x
.boot_params = S3C2410_SDRAM_PA + 0x100,
% S. r2 s O h
1 t( K3 r" N! H M) q .init_irq = s3c24xx_init_irq,& V( A4 {' d1 C, C
.map_io = smdk2440_map_io,: |/ j) N. u W
.init_machine = smdk2440_machine_init,
$ E* L7 i/ J$ A, F. [/ k- ]3 ~ .timer = &s3c24xx_timer,
1 v) o2 y/ x E2 Z3 _+ z
4 {; K5 d: [+ U ?};
: R5 T% V6 a) C* ^0 O8 d
0 ~3 \& y3 x6 s2 Y到此,__lookup_processor_type、__lookup_machine_type函数如果都匹配成功,则将继续执行
+ P3 ~! W% y: X( `2 a6 j+ E K, h" C; M; O/ W7 m
__vet_atags、(处理u-boot传入的ATAGS)1 }" ]) Z7 r5 q3 r* C; A/ T
: @, l1 k% A$ l/ C__create_page_tables创建一级页表,在arch/arm/kernel/head.S原文定义
5 p9 T" O9 M, @1 T4 D9 n
. F& U* x. i$ `5 U' }4 ]$ e__switch_data在arch/arm/kernel/head_common.S 定义
0 l% Z1 V' [" s1 _+ `$ I8 L7 D0 @. u
__switch_data:
) y6 P# @, J. p& z4 L3 T1 n( n .long __mmap_switched
6 y' [/ T6 M* D5 }4 s( @5 A .long __data_loc @ r4
" h+ s6 U2 E) \+ N% ?9 @ .long _data @ r57 t' B: _6 M2 M2 r4 ~$ F. l
.long __bss_start @ r6- C$ \: b5 c, K( A( d9 R8 G4 o! E
.long _end @ r7
3 r7 N" R+ m$ |* J1 E" X- d. @ .long processor_id @ r41 X- m- M& T0 ~+ V: z% e# y
.long __machine_arch_type @ r5
% x' k" G: a8 I: D% M; l. e% i .long __atags_pointer @ r6
5 F5 z; N3 Z3 |. j3 g9 R2 g1 A. q .long cr_alignment @ r7' j' p& O% Z \# @
.long init_thread_union + THREAD_START_SP @ sp
! w9 X& [' i# r) i
9 `! a2 f6 M# ]* ]& _......3 h& n2 m0 \! k* V
. v- G! M6 F% z2 H/ V1 T
__mmap_switched:
. c0 X3 X2 k/ _8 Z adr r3, __switch_data + 4
; [. y3 U8 _: a1 _: `& H
# j u; |4 f) o5 k/ S+ W$ a ldmia r3!, {r4, r5, r6, r7}2 A' b" c. v" k# Y; U* [$ c
cmp r4, r5 //复制数据段0 q2 B' D0 P h" }# j
1: cmpne r5, r6
& t; p8 o% @: w2 N6 Y ldrne fp, [r4], #4
; Y8 h8 u! |1 h strne fp, [r5], #4- {- \8 y& L/ M* x+ S3 [' b
bne 1b: k9 k2 W! t9 A0 W/ B* b6 v
7 q5 v2 D5 H! E9 q; G0 Q! U9 P+ j+ T
mov fp, #0 //清除BSS段
1 ~# d# t% l: L1 L% E% L/ ~/ Z' i1: cmp r6, r7( J1 z7 t7 `5 z& X/ B
strcc fp, [r6],#4
# h3 ^& w0 Y! t& U bcc 1b1 W: C* [+ G% F* t% i" M8 k" a
* ?: ]2 _6 c( o* a8 t
ldmia r3, {r4, r5, r6, r7, sp}; t9 m; a; \; x6 d9 m6 h* s
str r9, [r4] //保存CPU ID到 r9 寄存器
^2 |" v5 i7 ]9 Y/ I str r1, [r5] //保存机器ID到 r1 寄存器4 E% W1 ~; T q3 n
str r2, [r6] // 保存ATAGS指针到 r2 寄存器
) ]& q- m! Z t. G7 Q7 _ bic r4, r0, #CR_A @ Clear 'A' bit
6 B" ^% y2 q" l; o( T stmia r7, {r0, r4} @ Save control register values
Z( }: U" G, {1 ^ b start_kernel //跳到第二阶段的C函数去执行,在init/main.c中定义& j, U& u+ E* |7 c0 {* k
ENDPROC(__mmap_switched)% \: [9 q2 {9 d4 s
) f6 B3 }$ y" H# a$ k2 y
/ j; ^* F; y6 J# Q ~# m4 Y Y) I2 ?7 D( C5 ~7 y7 Z
__enable_mmu 使能MMU
9 W, Z9 O2 S; Y" a! |2 o; J; L, g( W- }& X0 [ @: q
__enable_mmu:
. ?3 l, Q" ]: O6 n5 q/ j9 {2 T#ifdef CONFIG_ALIGNMENT_TRAP& e6 u/ W4 }7 F) d
orr r0, r0, #CR_A; @3 z6 B9 x0 K6 L5 b* y
#else7 n" c; K5 {/ V' e# T; ^
bic r0, r0, #CR_A9 P7 E1 T; `+ w! ]% t8 U* j
#endif
) e) g* \( w: f0 K/ I( y/ L#ifdef CONFIG_CPU_DCACHE_DISABLE
* J/ i8 t. V, f+ p0 c7 e2 }5 k3 K0 @ bic r0, r0, #CR_C+ }5 g% k2 ~! F/ C4 @
#endif1 a/ j) d; |! s
#ifdef CONFIG_CPU_BPREDICT_DISABLE# G+ V/ f# ^& G6 d( X
bic r0, r0, #CR_Z
1 L6 ^, S8 p, m5 q5 g#endif
# i4 D* t P$ r) t0 B#ifdef CONFIG_CPU_ICACHE_DISABLE
) U+ ?- M! o1 I bic r0, r0, #CR_I
1 |$ [, K( w8 k) l: I#endif6 t" w7 X1 i+ y( W6 _' R9 T
mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \% s; P, o( Y# H
domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \8 L: h# l' `3 v' h& f, k4 z- H/ f
domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \0 l% K* \, \* q: t6 R- C3 D+ X4 Y
domain_val(DOMAIN_IO, DOMAIN_CLIENT))0 Z, B0 a6 O! R" S
mcr p15, 0, r5, c3, c0, 0 @ load domain access register
. e2 m" G# w+ p+ N7 O' } mcr p15, 0, r4, c2, c0, 0 @ load page table pointer+ @, [9 }# i. Z0 @" d/ p. v
b __turn_mmu_on
& {7 _6 R% m- K" R: {, eENDPROC(__enable_mmu)" x1 O) P. j: _# D9 S! N1 B' ?" L/ L
1 O+ z; u: Y# c
6 J' ?( r6 \5 j' r! y4 y
3 C; l2 |# T# [" J- L5 Y0 x .align 5
. G* s. @& v' d, i__turn_mmu_on:
; R0 B& @7 K# F% ~6 r: g) S mov r0, r0
! G- D8 K$ A7 o k; Z9 n mcr p15, 0, r0, c1, c0, 0 @ write control reg0 a I. D/ ? q8 C7 r& g( {5 Q; W. t
mrc p15, 0, r3, c0, c0, 0 @ read id reg0 i p: u/ v8 H( D
mov r3, r3
# G- ~& _4 S! s: j) ]2 e2 E! } mov r3, r3
3 c1 B3 |! m* B' w0 p9 [. ` mov pc, r13
@/ ^) ]' d4 |6 u. w) a# CENDPROC(__turn_mmu_on)' ~# B! a7 o5 T4 E( P
% S. G$ O1 p2 x* b% D
2 Y) R& C- @& _& \: \$ x0 z( ~( ?3 F- V- P) M* ^! R
|
|