|
|
EDA365欢迎您登录!
您需要 登录 才可以下载或查看,没有帐号?注册
x
分析内核顶层Makefile,以及arch/ARM/Makefile可知,从u-boot跳到内核后,第一个启动的文件是arch/arm/kernel/head.S。接下来就围绕这个文件来分析Linux架构/开发板相关的引导过程。9 k9 B2 S( w( c3 |# y; U
8 G/ n/ G2 ?/ w) ~$ A
/******************************以下仅分析重要部分********************************/
X2 S0 H4 N6 a3 k* g& B h
# o6 i! I5 H7 c* U. f9 c) Z" R#include "head-common.S" //下面会调用到这个文件里面的函数
: V6 i! J% C4 i. [! ~
f+ g2 X6 h6 ]$ K......" r. V/ C$ h* r* z# q- C! N
- o7 [% H- x: y& G( Y
/*8 u, V$ r/ g; S) f$ [! J6 v( h/ j
* Kernel startup entry point. L( a, u! Q6 ^" h
* ---------------------------0 g% P2 ]% T) n, h' }
*
, S ^1 Y0 O% F P2 Z/ D7 T* This is normally called from the decompressor code. The requirements
# r3 o8 s; m5 ~0 G1 K1 J* are: MMU = off, D-cache = off, I-cache = dont care, r0 = 0,; ^0 s/ j( B0 @" t
* r1 = machine nr, r2 = atags pointer.
2 m5 c3 Y4 s5 N# Q4 [*
$ ~, }: r% ?, i2 N9 ]8 L8 S* This code is mostly position independent, so if you link the kernel at
! M& _" E }' I7 n6 J* 0xc0008000, you call this at __pa(0xc0008000).
3 }8 d3 V+ S- Q- q# H*
8 j- Y! A- V0 |7 ~7 b* [% G* See linux/arch/arm/tools/mach-types for the complete list of machine
5 R( Q8 b5 ~* e+ u0 D* numbers for r1.
- V. _. O7 t& K. r* ........) @6 C& y) q; e3 g6 V( P
*/
) v$ C! V y, ~- U: I7 }% u* R# p5 b1 v.section ".text.head", "ax" //".text.head"段,在vmlinux.lds链接文件中定义* Y8 d, ?. ]- V( I; Z' P
ENTRY(stext). ~& `; F& }% l
msr cpsr_c, #PSR_F_BIT | PSR_I_BIT | SVC_MODE //确保进入管理模式并禁止中断
2 A" v$ C7 j/ W/ L7 t- E mrc p15, 0, r9, c0, c0 // r9 = CPU ID
1 u. Y/ @) }/ Z1 R1 L9 z2 n* T$ u1 [ bl __lookup_processor_type // r5=procinfo r9=cpuid
- Z+ ?# c& z1 G/ _. `4 ` movs r10, r5 //如果不支持该CPU则r5=0
( `. U( X8 E; ? beq __error_p //如果r5=0,则打印错误信息! c! X& q8 |5 S
bl __lookup_machine_type // r5=machinfo7 P2 K8 D+ {0 k, W
movs r8, r5 // 如果不支持该开发板r5=0& R* v3 e3 c9 D; I0 [( w
beq __error_a //如果r5=0,则打印错误信息
. M: p/ ~" H, e6 c6 k) u bl __vet_atags
; Q: \/ v* c% l" X) E bl __create_page_tables+ e; r+ e1 v/ u
! Q4 Q' W/ o, {* g0 U q% d .......
" o7 J5 Y$ u( G0 E7 { ldr r13, __switch_data @ address to jump to after mmu has been enabled
) r: H9 G& R* i; J- w adr lr, __enable_mmu @ return (PIC) address/ G! H& ?; o/ B( C
add pc, r10, #PROCINFO_INITFUNC" ^9 q! Q" b! U0 v
ENDPROC(stext)
o( P$ Y4 d( v3 g3 e3 i. K" J( d- c% J& c( P
......., S& C7 v5 x6 {# ]5 C& V
0 z$ C) N2 _# w6 X, R, `9 f
架构/开发板相关的引导过程就是由以上蓝色部分的函数来完成的,都是汇编子程序,下面逐个分析。
5 L; _0 l, U& e+ x& c
* t1 `. e7 l+ F: a) s! X# n7 g) O__lookup_processor_type子程序在arch/arm/kernel/head-common.S文件中定义. G5 F% I3 _3 z7 C
! u! Q: K- }! w+ [6 l( x6 |
/*0 \' F, r, O9 B7 N3 H
* r9 = cpuid
; g5 V& ?: `0 Q: Q, m * Returns:
! a+ e4 y: V% ` `0 ?% u * r3, r4, r6 corrupted1 e0 F7 N% L5 b0 i0 ^: l0 m+ o
* r5 = proc_info pointer in physical address space- o0 H2 J9 C F; Q, ?9 v* p5 R
* r9 = cpuid (preserved)
7 U0 T2 n& S5 Y/ R& v9 j */
8 R3 ]2 D+ B# [/ ?$ k/ J% h! W$ }2 d6 S( H3 x
__lookup_processor_type:3 d( e/ j# E1 G4 X
adr r3, 3f //将下面3标号的物理地址存到r3寄存器! P9 h5 U; |+ E% T3 ]% Z6 v( r
* y6 w5 z) I$ ?2 i8 X J# _
/* r5 = __proc_info_begin,r6 = __proc_info_end 的虚拟地址,r7 = 3标号的虚拟地址 */+ N8 ~+ V, H5 ], k
ldmda r3, {r5 - r7}/ e5 Z; E \# d9 E' u' E8 v+ ]; S
sub r3, r3, r7 // r3 = r3 - r7,物理地址与虚拟地址之差
; l7 E# q, g8 {$ d6 S) X9 R add r5, r5, r3 // r5 = __ proc_info_begin 对应的物理地址- ]) K8 q$ b0 s+ j; Q0 C x
add r6, r6, r3 // r6 = __proc_info_end 对应的物理地址% K6 [0 x8 [$ m4 m
1: ldmia r5, {r3, r4} // r3 = cpu_val,r4 = cpu_mask 这两个成员在proc_info_list中定义+ m: O( E0 M( N2 v
and r4, r4, r9 // r4 = r4&r9 = cpu_mask & 最开始从CP15传入的cpu id7 C j2 C* \3 ]; n" i/ M2 p0 G
teq r3, r41 m+ u( V* ?# b) U
beq 2f //相等则返回
; U' u" a6 Q) J& @) o* b1 H add r5, r5, #PROC_INFO_SZ //下一个pro_info_list ,sizeof(proc_info_list)
# x0 F# t8 h! `& p. v& W r cmp r5, r6 //判断是否已经比较完所有的proc_info_list
' N/ d7 H9 v- R. |) ^& C/ q6 o3 Y blo 1b //否则继续比较
9 f3 f1 u1 J1 v+ ` G/ K# R mov r5, #0 //比较完后还是没有匹配的proc_info_list结构,r5 = 0
5 W+ j0 a9 B8 m* q2 y. R2: mov pc, lr // 返回 V" r, A* O/ }+ i& O* I6 E
ENDPROC(__lookup_processor_type)$ F; a2 Q# F( t
( W8 ~( A: |4 y% z9 B......." N0 d4 @/ q) P3 Y
. Y; K9 ~1 W% U4 C* Z1 C3 P8 j/*7 v: l; Y& L* k) t5 P9 a; W# c* y3 U
* Look in <asm/procinfo.h> and arch/arm/kernel/arch.[ch] for
3 r# w8 H7 |9 r( d * more information about the __proc_info and __arch_info structures.
S; }8 X3 Y2 o7 F* R t! B- p0 \ */8 g; M& R- H5 Z: E$ E! i
.long __proc_info_begin //proc_info_list结构体的开始地址(虚拟地址)# }5 K5 e; x) y* r) v8 f
.long __proc_info_end //proc_info_list结构体的结束地址(虚拟地址)
' }( ~2 k% B5 | b6 n3: .long . // 3标号在内存中的的物理地址
/ B. I& l! W) b7 `+ f+ u0 v6 R .long __arch_info_begin 8 j$ ]1 j8 }# B+ j5 \, e
.long __arch_info_end ' w. O1 o0 z9 ?: f* ?! U5 M( g- d
. C0 k: h3 @4 t. a; E8 Q( P$ ]
0 Y3 r, R4 z/ Y" g
. q) V+ }2 c4 E" j7 x' E% y0 {# eproc_info_list结构体在arch/arm/include/asm中定义
7 j3 Y8 e8 j4 i# C D* ?2 @( f* }7 H6 J% e
struct proc_info_list {" f0 l0 ~# N, S/ c2 h
unsigned int cpu_val;+ Q7 q; J) v( t
unsigned int cpu_mask;$ g( [: D& ~# X% z
unsigned long __cpu_mm_mmu_flags; /* used by head.S */
G. J2 T& Z5 o5 j) A4 \7 Y unsigned long __cpu_io_mmu_flags; /* used by head.S */$ w+ Z* ^7 v8 Y- j5 Y
unsigned long __cpu_flush; /* used by head.S */. g0 v# v7 e6 E+ d* M: t
const char *arch_name;
4 J; t2 q7 I2 U, X2 p3 p const char *elf_name;
4 M) ~4 j; u' N/ b' _- r unsigned int elf_hwcap;) K4 M# K; ]* k
const char *cpu_name;
. F9 f0 s9 T! X, ` struct processor *proc;
" E+ C+ }: A: S8 v' w3 \ struct cpu_tlb_fns *tlb;5 ~, Q: ]- _0 i, k% V, N5 y* Z
struct cpu_user_fns *user;
( f# m2 U+ [3 c5 P7 ^) x0 X# I8 ]* [ struct cpu_cache_fns *cache;
' E/ C5 f) [& f) A% x+ a};
! _5 e; m8 A( x/ r, i4 P$ J
2 a0 E# v! |1 F8 Q对于S3C2440开发板的匹配,它的CPU ID是0x41129200,可查询协处理器的CP15获知。. N5 G% x6 C# M' V% o* L
+ l9 f0 Z8 I* Q/ X而在arch/arm/mm/proc_arm920.S中定义的__arm920_proc_info结构如下$ J$ \8 B/ Z% I/ D- F
) z, v+ a7 Y# [- V1 W/ s: x__arm920_proc_info:5 ?, g/ G+ H9 ]& p, N
.long 0x41009200/ P% ^- W( u. E, T6 I5 g! p
.long 0xff00fff0% i% D ]9 [# j
& f/ x! j* b9 J+ B/ h ........0 g }$ U( Q+ a1 I+ t4 ]0 U
/ v1 P7 l$ `5 [3 @& o# S- j; M# y/ _- Q即r3 = cpu_val = 0x41009200,r4 = cpu_mask = 0xff00ff00,刚好匹配。& R$ C! k" J& p( j2 o
0 e2 n9 t# |" A4 r
+ s2 S8 n5 M+ `4 q
' V# C4 Y e& e( S4 v__lookup_machine_type子程序也在arch/arm/kernel/head-common.S文件中定义% x7 L4 H' @, _
; R& w# [: ?0 P3 {/*0 h, \% A/ [+ S
4 a$ R( j- M( Q1 ^4 ^ r * ..../ |. M2 S# L; i' G1 G5 ?6 @
# u0 v" i, k+ N) a * r1 = machine architecture number ?) w' _* r, {! r2 n$ o0 e
* Returns:
; {2 A: s: G6 J* R. B * r3, r4, r6 corrupted8 c/ }4 B D* N, J8 O
* r5 = mach_info pointer in physical address space
8 j2 E; v+ K& z( z; \ Y! U4 N3 R */
5 s0 F* D/ B- v+ t0 g9 J__lookup_machine_type:
$ T- r4 E4 m# P/ z" l* U& Z adr r3, 3b //获得3标号的物理地址3 M% R" v2 r: _
: U* G8 i( y0 A8 E, X. ?/* r4 = __arch_info_begin,r6 = __arch_info_end 的虚拟地址,r7 = 3标号的虚拟地址 *// u- ~9 p1 D$ m2 S# e
8 Y8 r9 Y4 K$ \4 n X/ m/ Q ldmia r3, {r4, r5, r6} O5 i+ |& M# {+ o7 x
sub r3, r3, r4 // r3 = r3 - r4 物理地址与虚拟地址之差7 P b% f) T4 \6 K( g5 m
add r5, r5, r3 // r5 = __arch_info_begin 的物理地址5 v" P+ x9 `# m" a
add r6, r6, r3 // r6 = __arch_info_end 的物理地址
' Z+ R3 }) s8 v1: ldr r3, [r5, #MACHINFO_TYPE] // r5 是machine_desc结构体的地址
( Y1 `3 U/ \6 W0 T' a1 p teq r3, r1 //判断从r1传入的机器ID是否匹配) m% C$ ?4 r5 J- t6 ~: `+ q
beq 2f //匹配则返回8 g* w6 S* h3 y
add r5, r5, #SIZEOF_MACHINE_DESC //否则,指向下一个 machine_desc6 }" k e. s1 M+ a9 ^- X
cmp r5, r6 //是否已经比较完所有的machine_desc结构
. u& p I) r2 d8 Z blo 1b //没有则继续比较
, T' M5 P' S" @0 ~& c1 M o mov r5, #0 //比较完毕之后都没有找到匹配的,r5 = 0
6 \* o6 w2 W. n7 b+ I& g2: mov pc, lr //返回
0 y- J; [+ S5 D* g- f( i8 F2 ~$ FENDPROC(__lookup_machine_type)
1 r- y4 K+ H9 F R6 f/ l9 U2 [
/ j4 W( i8 V, f& U2 f8 f
; C" L4 O( j1 R$ ?8 y9 A% g
" U2 c2 ^2 ^8 N0 \, Tmachine_desc结构在 arch/arm/include/asm/mach/arch.h中定义
) A1 e: E& S: F: [( d- K g( \) w; w9 {
struct machine_desc {
0 s* ]' f( {0 C5 `/ I" n) u! ^1 l /*% O4 R b. L5 d" Q. \4 z7 V6 G
* Note! The first four elements are used1 G0 H8 i4 Y& Q( ^6 w5 u
* by assembler code in head.S, head-common.S
7 v% O# q6 e# X( s3 r */
3 a; }& m2 Z+ [, ~ unsigned int nr; /* architecture number */
$ V6 e- Y9 l3 n2 H- L L: {% Z- E unsigned int phys_io; /* start of physical io */' d# ^4 O0 n: Y3 K1 |! k
unsigned int io_pg_offst; /* byte offset for io
6 @: l# q. s& l+ h J8 w * page tabe entry */5 `( x6 U3 t; b: T- {/ b/ a# H
2 ]8 D9 L9 a( P) Y/ M# s
const char *name; /* architecture name */' S2 i" T4 p: o) U# z
unsigned long boot_params; /* tagged list */# e; [6 r/ E( D9 ^ T5 C
+ I2 h" K0 e. y9 ] unsigned int video_start; /* start of video RAM */" [( Q8 T7 x2 ` S2 `7 p; m4 _
unsigned int video_end; /* end of video RAM */
% A. b6 K2 [" G9 x1 `7 }: U M0 Z0 {$ u+ {, v2 Z/ L2 z' i) D6 r+ h& {
unsigned int reserve_lp0 :1; /* never has lp0 */# d0 g4 k8 f: _& O
unsigned int reserve_lp1 :1; /* never has lp1 */% f0 R2 O! i" f2 g* e
unsigned int reserve_lp2 :1; /* never has lp2 */
3 w. _8 D0 n" z" ~' f# b unsigned int soft_reboot :1; /* soft reboot */; G# Z5 r5 m; _7 h2 A
void (*fixup)(struct machine_desc *,5 |" q' W3 k2 W, P) o
struct tag *, char **,
& a( j- k. \$ z7 j" H" s" a5 R struct meminfo *);
( j3 a6 M- ~9 J% Q' } void (*map_io)(void);/* IO mapping function */
; h( }* j: A F8 ?! Y2 I& ^& t2 P( X void (*init_irq)(void);
% |( E& U& m6 \; g7 ?3 Y struct sys_timer *timer; /* system tick timer */
5 d0 R$ F7 P5 z M+ R6 D void (*init_machine)(void);. [& y# _3 }( B2 n
};! C' j7 ^: y; U' y
- r/ w' l$ T. ~#define MACHINE_START(_type,_name) \" P& ?$ Y; e/ c' H3 a
static const struct machine_desc __mach_desc_##_type \( K T( [$ l5 k
__used \
9 b A" o( O [9 S& u0 u" F( r __attribute__((__section__(".arch.info.init"))) = { \5 @; _# Z& ^# E
.nr = MACH_TYPE_##_type, \
" K4 H6 z9 R) W5 ~2 n .name = _name,: I5 e# N( X1 ]! L
2 C8 O; x* \6 F( x( N- K% b, b
#define MACHINE_END \
* [" y9 {6 @% ]9 p$ }- u2 Q3 U( s};' p% @( k$ I6 U3 B# Z! F$ q
* A% W& t4 ^8 n9 g, X
7 F% F p y; `
1 F0 {+ F" V T9 {2 X# bMACHINE_START(S3C2440, "SMDK2440")8 G9 ~, S* W- l
.phys_io = S3C2410_PA_UART,
3 L$ @& N% l y .io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
# V, b4 W3 z- U2 }' V: ] [0 G .boot_params = S3C2410_SDRAM_PA + 0x100,
/ ^& x9 Q+ q( _8 y6 Y
( }, w7 C6 \: b9 @+ r .init_irq = s3c24xx_init_irq,
+ }" ~! i& A/ I d) [ .map_io = smdk2440_map_io,0 _8 B% d& v0 d b. S9 u* ~
.init_machine = smdk2440_machine_init,
o" c0 j9 I/ y: h# n: ~ .timer = &s3c24xx_timer,
& c! g; A- |1 ~* o7 w1 Y& RMACHINE_END
$ R: I0 `& W! H& m2 D" `; {% k' e: i* d8 v
( O# e) F4 {$ `2 y ^8 K$ u+ {% @$ S4 q0 _6 d
由上面二个定义得到S3C2440 的machine_desc结构体 1 a; q! E7 B; I
7 P) w# k/ u H4 |static const struct machine_desc __mach_desc_S3C24407 C1 j: S! }! l8 P) e0 m
__used
1 X8 S0 c6 @8 T& B8 i& ~ __attribute__((__section__(".arch.info.init"))) =
2 B7 P* i! E, t2 |! P. r- X6 x$ _1 {7 Q- M G2 o
{ $ M3 r) ]/ k3 Z) Z7 A
.nr = MACH_TYPE_S3C2440,
, b9 N/ V- y# x4 J: a" c .name = "SMDK2440",0 o/ U5 X& `2 R( g4 o3 x+ g
.phys_io = S3C2410_PA_UART,& e/ @4 o/ K* O5 A9 p5 ]0 f9 C5 d% b
.io_pg_offst = (((u32)S3C24XX_VA_UART) >> 18) & 0xfffc,
# A) n" o( m2 \0 {3 o% s .boot_params = S3C2410_SDRAM_PA + 0x100,4 ]; y; ^ C; d3 A! B
. m2 W: F7 U0 L; }
.init_irq = s3c24xx_init_irq,
, P. y) N+ j1 p/ R/ g2 _ .map_io = smdk2440_map_io,2 }: d- q" |+ e
.init_machine = smdk2440_machine_init,- m% h; A' B) o7 T! K3 d- j& T& s
.timer = &s3c24xx_timer,
: B4 c5 s' c2 X M
2 o- T+ d$ f9 O9 S8 s4 M( T( S) c};
& ~+ g4 L2 Z- U6 x8 ^3 K: z5 Y. U5 A/ T% Q, b
到此,__lookup_processor_type、__lookup_machine_type函数如果都匹配成功,则将继续执行/ b2 c; l& M, K) ~6 x
. T/ J( k9 m: z/ `( J__vet_atags、(处理u-boot传入的ATAGS)
) J: S# I8 Q: o5 S
^" O; q" x& J! Y/ z* `6 J- F__create_page_tables创建一级页表,在arch/arm/kernel/head.S原文定义/ Q5 |) k8 X8 }
5 x |, {7 b4 |
__switch_data在arch/arm/kernel/head_common.S 定义
; {# D! ^; y/ `0 J$ J/ S/ D) `# N! S' V0 J9 [ Y
__switch_data:4 ]2 e8 A B2 Y& x- ]: m) n
.long __mmap_switched
3 _/ J& U' j w4 V2 s .long __data_loc @ r48 D& v- u5 X. _, C
.long _data @ r56 f V' T& L6 Q5 L8 J. T8 t
.long __bss_start @ r6
- z6 M+ n' s' W& e8 h2 [/ T .long _end @ r71 ?. z- c0 i# f, q u
.long processor_id @ r4
7 f; f V9 t0 F. h .long __machine_arch_type @ r5% @" I/ |( g9 C$ ~4 ^
.long __atags_pointer @ r6
. [ [0 X3 H2 Z, y5 L. m .long cr_alignment @ r7
9 E; t& Z$ |1 h0 K# p+ a$ r, ? .long init_thread_union + THREAD_START_SP @ sp1 ^' r/ a J; S2 Q. j
, T" S% o# M2 ]/ q
......
; `* |) S) r `, p( G
* U0 c+ y* B4 G k. S__mmap_switched:0 E( Z5 K: j* O, A V4 O2 `
adr r3, __switch_data + 4
1 @: \: A' a6 q: e% L) B
" ?3 C5 E' ^9 Q ldmia r3!, {r4, r5, r6, r7}! m; q& s" B* z+ X7 B# j, R, n
cmp r4, r5 //复制数据段
! r6 Q3 Q. L5 x1: cmpne r5, r6
1 K1 ~; F5 o8 g! G ldrne fp, [r4], #4
! Q. `2 U! o4 ^3 N: N2 H strne fp, [r5], #48 k% _1 J. t$ f! O0 p" T, ~
bne 1b4 o8 N K1 T6 X/ X$ U( ^
# ~/ z5 r, }: k) G: n mov fp, #0 //清除BSS段
4 Y( G4 X& w# T. C5 H# q5 x1: cmp r6, r7: t: T$ p1 L7 i0 ^1 E) R
strcc fp, [r6],#4' `% s& `( h% u! R. c
bcc 1b" L, H, d+ z' g$ H6 C. M4 l
$ Q! D2 c: W5 P% R3 \7 _ ldmia r3, {r4, r5, r6, r7, sp}
0 a# m2 w/ L: I* S6 l" f @. S- h str r9, [r4] //保存CPU ID到 r9 寄存器3 t1 I' O9 F$ E" O- c1 k) e4 T
str r1, [r5] //保存机器ID到 r1 寄存器
; C& x& y0 o8 x6 @+ m2 s7 a; @ str r2, [r6] // 保存ATAGS指针到 r2 寄存器
6 }' g: T, z. y% j- q, m. G3 {: ~8 I7 C bic r4, r0, #CR_A @ Clear 'A' bit4 F! x8 ?- E3 K- q
stmia r7, {r0, r4} @ Save control register values
, J1 ~) Q, V4 Q# `5 m( ] b start_kernel //跳到第二阶段的C函数去执行,在init/main.c中定义
. M! x l/ h7 [- y/ w, k% OENDPROC(__mmap_switched)$ G; i! O$ B5 \$ O4 ~) G
! }4 }# @- m9 }3 g) v$ Q* O; J4 l
( p' D- D+ R- C$ g- N1 K9 W' g
__enable_mmu 使能MMU
! N' K+ Z C1 J/ a! f
6 b2 O1 y& u- J8 h) Z2 a__enable_mmu:" J' v- P- Z1 n! N) u! U6 S# y/ ?
#ifdef CONFIG_ALIGNMENT_TRAP
3 u( [1 M* i+ `+ S" _ orr r0, r0, #CR_A
+ u) w. e/ k3 h# |#else5 I" }% G7 s8 B2 f% {
bic r0, r0, #CR_A" ~7 M9 \ p7 Y% \$ ]* r A
#endif# A' n; W- m# g' w; P/ t
#ifdef CONFIG_CPU_DCACHE_DISABLE
L: y/ Y: j, `/ C3 U bic r0, r0, #CR_C
/ @& |& [: Y( V. V; v0 M/ A1 b#endif' z2 h( y7 R2 D" O, E; s
#ifdef CONFIG_CPU_BPREDICT_DISABLE
3 t3 _, \7 l8 d: C bic r0, r0, #CR_Z
4 U7 g- F6 e& j: f: m3 Q7 \' @. j#endif
/ p. G. \" ^ b1 ?. [#ifdef CONFIG_CPU_ICACHE_DISABLE
% ~1 H' r4 ]9 [1 U bic r0, r0, #CR_I$ f$ e! V0 w' j( D" T
#endif
% W3 f6 d) N6 m; U4 K C mov r5, #(domain_val(DOMAIN_USER, DOMAIN_MANAGER) | \
; l" G, Q) `5 N# W! c domain_val(DOMAIN_KERNEL, DOMAIN_MANAGER) | \
[4 X1 p1 S" m" N, S+ _ domain_val(DOMAIN_TABLE, DOMAIN_MANAGER) | \
* e4 s% S) k, u domain_val(DOMAIN_IO, DOMAIN_CLIENT))) ]4 X, H8 V- T9 a! L' {
mcr p15, 0, r5, c3, c0, 0 @ load domain access register& ]$ G1 U5 P+ y; q
mcr p15, 0, r4, c2, c0, 0 @ load page table pointer/ X- F4 y8 W/ Z4 j+ T
b __turn_mmu_on
+ ?& W3 A" w2 s/ S! F! V) D5 {0 |; EENDPROC(__enable_mmu)
* G5 d: n: R; L3 K
0 g( {" G2 {6 e, t' }8 G
7 i( ^; k$ Q$ i- B( U8 p' N ?2 e& X! M, b9 P# T ]# z7 H6 V
.align 5
+ M9 G) J7 c; O, S/ x6 K__turn_mmu_on:4 Y. v+ ^0 [6 T4 S( v
mov r0, r0
4 c, R W' I' n( S( G mcr p15, 0, r0, c1, c0, 0 @ write control reg7 L: e( d8 ]' a5 P5 E' ~; v
mrc p15, 0, r3, c0, c0, 0 @ read id reg
, A4 R& U0 R1 n& q8 M* E mov r3, r3
- f, ?7 Y) U# w+ A. a% c* v mov r3, r35 L+ {; h0 q0 |1 R1 [
mov pc, r13
% w. O) l1 w1 m6 r1 y0 d( ^6 DENDPROC(__turn_mmu_on)
0 E: J. C, {! B. |" m1 r* F* z5 B9 @; K7 o2 k
( B4 }8 l5 G0 s, o- E# G
! Y) W. o) T5 h$ x0 a; z |
|