powerpc 汇编linux,powerpc e500系列,linux初始化的tlb汇编,添加人肉代码注释

powerpc e500的内核启动,关于tlb的初始化可以说是重头戏。看懂这段代码后,powerpc的虚实映射基本不在话下。

这段初始化tlb要考虑的,主要是将boot可能初始化过的tlb全清零,然后自己建立一套PAGE_OFFSET的虚实映射,即为0xc打头的地址

建立映射。

inux kernel 3.10.7将这段初始化代码,全部放到fsl_booke_entry_mapping.S里,这段代码除了linux初始化会用,

也被kexec使用。下面先直接贴出代码,之后分析核心流程。

/* 1. Find the index of the entry we're executing in */

blinvstr/* Find our address */

invstr:mflrr6/* Make it accessible */

mfmsrr7

rlwinmr4,r7,27,31,31/* extract MSR[IS] */

mfsprr7, SPRN_PID0

slwir7,r7,16

orr7,r7,r4

mtsprSPRN_MAS6,r7

tlbsx0,r6/* search MSR[IS], SPID=PID0 */

mfsprr7,SPRN_MAS1

andis.r7,r7,MAS1_VALID@h

bnematch_TLB

mfsprr7,SPRN_MMUCFG

rlwinmr7,r7,21,28,31/* extract MMUCFG[NPIDS] */

cmpwir7,3

bnematch_TLB/* skip if NPIDS != 3 */

mfsprr7,SPRN_PID1

slwir7,r7,16

orr7,r7,r4

mtsprSPRN_MAS6,r7

tlbsx0,r6/* search MSR[IS], SPID=PID1 */

mfsprr7,SPRN_MAS1

andis.r7,r7,MAS1_VALID@h

bnematch_TLB

mfsprr7, SPRN_PID2

slwir7,r7,16

orr7,r7,r4

mtsprSPRN_MAS6,r7

tlbsx0,r6/* Fall through, we had to match */

match_TLB:

mfsprr7,SPRN_MAS0

rlwinmr3,r7,16,20,31/* Extract MAS0(Entry) */

mfsprr7,SPRN_MAS1/* Insure IPROT set */

orisr7,r7,MAS1_IPROT@h

mtsprSPRN_MAS1,r7

tlbwe

/* 2. Invalidate all entries except the entry we're executing in */

mfsprr9,SPRN_TLB1CFG

andi.r9,r9,0xfff //r9 = tlb number

lir6,0/* Set Entry counter to 0 */

1:lisr7,0x1000/* Set MAS0(TLBSEL) = 1 */

rlwimir7,r6,16,4,15/* Setup MAS0 = TLBSEL | ESEL(r6) */

mtsprSPRN_MAS0,r7

tlbre

mfsprr7,SPRN_MAS1

rlwinmr7,r7,0,2,31/* Clear MAS1 Valid and IPROT */

cmpwr3,r6

beqskpinv/* Dont update the current execution TLB */

mtsprSPRN_MAS1,r7

tlbwe

isync

skpinv:addir6,r6,1/* Increment */

cmpwr6,r9/* Are we done? */

bne1b/* If not, repeat */

/* Invalidate TLB0 */

lir6,0x04

tlbivax 0,r6

TLBSYNC

/* Invalidate TLB1 */

lir6,0x0c

tlbivax 0,r6

TLBSYNC

/* 3. Setup a temp mapping and jump to it */

andi.r5, r3, 0x1/* Find an entry not used and is non-zero */

addir5, r5, 0x1

lisr7,0x1000/* Set MAS0(TLBSEL) = 1 */

rlwimir7,r3,16,4,15/* Setup MAS0 = TLBSEL | ESEL(r3) */

mtsprSPRN_MAS0,r7

tlbre

/* grab and fixup the RPN */

mfsprr6,SPRN_MAS1/* extract MAS1[SIZE] */

rlwinmr6,r6,25,27,31

lir8,-1

addir6,r6,10

slwr6,r8,r6/* convert to mask */

bl1f/* Find our address */

1:mflrr7

mfsprr8,SPRN_MAS3

#ifdef CONFIG_PHYS_64BIT

mfsprr23,SPRN_MAS7

#endif

andr8,r6,r8

subficr9,r6,-4096

andr9,r9,r7

orr25,r8,r9

orir8,r25,(MAS3_SX|MAS3_SW|MAS3_SR)

/* Just modify the entry ID and EPN for the temp mapping */

lisr7,0x1000/* Set MAS0(TLBSEL) = 1 */

rlwimir7,r5,16,4,15/* Setup MAS0 = TLBSEL | ESEL(r5) */

mtsprSPRN_MAS0,r7

xorir6,r4,1/* Setup TMP mapping in the other Address space */

slwir6,r6,12

orisr6,r6,(MAS1_VALID|MAS1_IPROT)@h

orir6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_4K))@l

mtsprSPRN_MAS1,r6

mfsprr6,SPRN_MAS2

lir7,0/* temp EPN = 0 */

rlwimir7,r6,0,20,31

mtsprSPRN_MAS2,r7

mtsprSPRN_MAS3,r8

tlbwe

xorir6,r4,1

slwir6,r6,5/* setup new context with other address space */

bl1f/* Find our address */

1:mflrr9

rlwimir7,r9,0,20,31

addir7,r7,(2f - 1b)

mtsprSPRN_SRR0,r7

mtsprSPRN_SRR1,r6

rfi

2:

/* 4. Clear out PIDs & Search info */

lir6,0

mtspr SPRN_MAS6,r6

mtsprSPRN_PID0,r6

mfsprr7,SPRN_MMUCFG

rlwinmr7,r7,21,28,31/* extract MMUCFG[NPIDS] */

cmpwir7,3

bne2f/* skip if NPIDS != 3 */

mtsprSPRN_PID1,r6

mtsprSPRN_PID2,r6

/* 5. Invalidate mapping we started in */

2:

lisr7,0x1000/* Set MAS0(TLBSEL) = 1 */

rlwimir7,r3,16,4,15/* Setup MAS0 = TLBSEL | ESEL(r3) */

mtsprSPRN_MAS0,r7

tlbre

mfsprr6,SPRN_MAS1

rlwinmr6,r6,0,2,0/* clear IPROT */

mtsprSPRN_MAS1,r6

tlbwe

/* Invalidate TLB1 */

lir9,0x0c

tlbivax 0,r9

TLBSYNC

/* The mapping only needs to be cache-coherent on SMP */

#ifdef CONFIG_SMP

#define M_IF_SMPMAS2_M

#else

#define M_IF_SMP0

#endif

#if defined(ENTRY_MAPPING_BOOT_SETUP)

/* 6. Setup KERNELBASE mapping in TLB1[0] */

lisr6,0x1000/* Set MAS0(TLBSEL) = TLB1(1), ESEL = 0 */

mtsprSPRN_MAS0,r6

lisr6,(MAS1_VALID|MAS1_IPROT)@h

orir6,r6,(MAS1_TSIZE(BOOK3E_PAGESZ_64M))@l

mtsprSPRN_MAS1,r6

lisr6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@h

orir6,r6,MAS2_VAL(PAGE_OFFSET, BOOK3E_PAGESZ_64M, M_IF_SMP)@l

mtsprSPRN_MAS2,r6

mtsprSPRN_MAS3,r8

tlbwe

/* 7. Jump to KERNELBASE mapping */

lisr6,(KERNELBASE & ~0xfff)@h

orir6,r6,(KERNELBASE & ~0xfff)@l

#elif defined(ENTRY_MAPPING_KEXEC_SETUP)

/*

* 6. Setup a 1:1 mapping in TLB1. Esel 0 is unsued, 1 or 2 contains the tmp

* mapping so we start at 3. We setup 8 mappings, each 256MiB in size. This

* will cover the first 2GiB of memory.

*/

lis r10, (MAS1_VALID|MAS1_IPROT)@h

ori r10,r10, (MAS1_TSIZE(BOOK3E_PAGESZ_256M))@l

li r11, 0

li r0, 8

mtctr r0

next_tlb_setup:

addir0, r11, 3

rlwinm r0, r0, 16, 4, 15 // Compute esel

rlwinm r9, r11, 28, 0, 3 // Compute [ER]PN

oris r0, r0, (MAS0_TLBSEL(1))@h

mtspr SPRN_MAS0,r0

mtspr SPRN_MAS1,r10

mtspr SPRN_MAS2,r9

ori r9, r9, (MAS3_SX|MAS3_SW|MAS3_SR)

mtspr SPRN_MAS3,r9

tlbwe

addi r11, r11, 1

bdnz+ next_tlb_setup

/* 7. Jump to our 1:1 mapping */

mrr6, r25

#else

#error You need to specify the mapping or not use this at all.

#endif

lisr7,MSR_KERNEL@h

orir7,r7,MSR_KERNEL@l

bl1f/* Find our address */

1:mflrr9

rlwimir6,r9,0,20,31

addir6,r6,(2f - 1b)

mtsprSPRN_SRR0,r6

mtsprSPRN_SRR1,r7

rfi/* start execution out of TLB1[0] entry */

/* 8. Clear out the temp mapping */

2:lisr7,0x1000/* Set MAS0(TLBSEL) = 1 */

rlwimir7,r5,16,4,15/* Setup MAS0 = TLBSEL | ESEL(r5) */

mtsprSPRN_MAS0,r7

tlbre

mfsprr8,SPRN_MAS1

rlwinmr8,r8,0,2,0/* clear IPROT */

mtsprSPRN_MAS1,r8

tlbwe

/* Invalidate TLB1 */

lir9,0x0c

tlbivax 0,r9

TLBSYNC

首先要说明的是,走到这里有一个前提条件,系统已经有一个1:1的tlb映射,包含正在跑的这段代码。

line2, bl是相对跳转,跳转到invstr标签处,将此标签虚拟地址存入r6;

line10,调用tlbsx 0,r6查找出当前的1:1映射tlb条目的编号,跳转至match_tlb处;

line35,先将MAS0的值存入r7,然后将r7逻辑循环左移16位,然后提取32+20至32+31的内容

存入r3,剩下的bit位全部清零。其实就是取得MAS0的ESEL字段。其中,ESEL字段位于bit44-bit47,

将MAS0的高32位循环左移16位后,就位于bit52-bit63。

(powerpc是大端,左移指的是将数据往低地址方向移动。)

这里第一次说到M-Form的rlwinm指令,

该指令主要用来提取寄存器的某些位,然后放到结果寄存器里。

rlwinm r1, r2, SH, A, B (A < B)

如:r2 = 0x12345678, SH=8, A=3,B=9 则:r1 = 0x1440 0000.

计算过程:MASK(A,B) = 0x1fc0 0000. r2

line10执行完后,r3保存tlb entry编号;

line38到line41,将r3对应的tlb条目置一个IPROT属性保护起来。

line44到line60,遍历所有的tlb1,主要编号不是r3的,就将其保护位IPROT清除;

line62到line69,将tlb0和tlb1的所有tlb置无效,目前只剩一个我们正在执行的tlb条目了;

接下来,在另外一个地址空间,建立一个临时的tlb,让代码跳转过去临时跑一会:

line72到line73,找一个不同的tlb,算法是r5=(r3&1)+1,假如r3是偶数,则r5=1;假如r3是奇数,则r5是2;

line74到line77,将r3对应的tlb信息读出到MAS系列寄存器;

line80到line84,对RPN进行调整对齐之类的操作;

line100到line114,填充临时tlb的信息:

line102,指定写r5对应的tlb,line104到line108,置MAS1的ts位为非当前空间,置IPROT保护位,置页面大小为4k;

line109获取当前MAS2的内容,存放到r6,然后获取r6的bit52-bit63位,平移到r7中,然后写回MAS2。这句的意思就是

保留tlb条目的cache属性,然后将epn清零。

line113将RPN按页对齐调整过后的值写入MAS3,然后写入此temp tlb;

line116到line117,将MSR的TS置为与当前空间相反,与line102相对应;

line121将当前地址的bit52-bit63更新到r7(即把之前r7存放的MAS2里的cache属性位覆盖),

而其余位仍然是r7的原值(这是与rlwinm唯一不同的地方),原值就是epn为0,并取当前运行地址的

bit52-bit63位,即低4k。也就是说,这个临时空间要求代码段被拷贝在物理地址0-4k内;

line123算出2f的偏移,并在line124将地址存入SPR0,将MSR存入SPR1;

line126跳转至临时空间;

到了line143,这时候可以放心大胆的清除刚进内核时的唯一一个tlb条目了,这里不再罗嗦;

line166-line175,在空间0建立一个64M、虚拟映射为PAGE_OFFSET:0的tlb条目;

line178至line179,为r6存放一个内核态偏移,然后line218将当前运行地址的低4k,平移到r6中,

最后line222跳转至此地址,即从此运行在PAGE_OFFSET:0的地址空间了;

line225至line236,清除最先我们建立在另一个空间的临时映射;

line181至line209是kexec跳转前,为2G的物理地址空间建立1:1映射,这样做有两个好处,一个是

kexec e500架构下的最终内核页面拷贝都是假设关闭了mmu的,另一个好处是,我们在最前面说到,

powerpc内核假设boot是为其建立好了一个1:1映射的。如果不这么做,会出现不可预知的问题。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值