天天看点

Pmon学习:start.S之TLB初始化

参考资料:

http://xenyinzen.wikidot.com/code-research:pmon:start-functions

https://wenku.baidu.com/view/013ba5f9700abb68a982fb3a.html?sxts=1535682681686&pn=1

因为项目需要在裸机阶段访问到512M以上的物理地址,根据参考手册需要设置TLB进行访问,所以对PMON中TLB初始化的代码段进行了一些探究和简单注释,以便后面需要的时候参考。

TLB的作用是将虚拟地址映射到物理地址,所以需要配置他们的对应关系。

##两个关键寄存器

EntryHi寄存器存放地址入口,也就是需要转换的虚拟地址;EntryLo寄存器存放出口地址,也就是虚拟地址映射到的物理地址。下面是这两个寄存器的具体描述。关于TLB的初始化就是根据这两个寄存器的描述进行配置。

Pmon学习:start.S之TLB初始化

##ls1c中TLB初始化代码注释

ls1c中是将虚拟地址的0xc0000000开始的1G空间映射到物理地址的0xc0000000中,页面大小设置为16M。

LEAF(CPU_TLBInit)
	li	a3, 0			# First TLB index.

	li	a2, PG_SIZE_16M
	MTC0   a2, COP_0_TLB_PG_MASK   # All pages are 16Mb.

1:
	and	a2, a0, PG_SVPN		//PG_SVPN=0xfffff000,所以这里是取a0地址的高20位,舍弃低12位的偏移地址(如果给的地址低位不为零的话),因为后面的EntryHi寄存器需要高位作为虚拟地址
	MTC0   a2, COP_0_TLB_HI	# Set up entry high.

	move	a2, a0 		//再给a2赋值0xc0000000,但是貌似下一句就重新赋值了
	srl	a2, a0, PG_SHIFT  		//PG_SHIFT=6,所以这里是将a0的值逻辑右移6位赋值给a2,a2=0x03000000(这里右移6位目的是将地址高位与EntryLo寄存器的PFN位对齐。需要参考寄存器的定义)
	and	a2, a2, PG_FRAME		//PG_FRAME=0x3fffffc0,这里取a2的值第29-6位,其余位置0,这里实际上a2的值不变(因为EntryLo寄存器的29-6位是PFN,即页帧号,其中29-16位一般作为页帧号的一部分直接写0,不是实际的物理页帧号)
	ori	a2, PG_IOPAGE			//PG_IOPAGE=0x00000017,这里将a2值的第0、1、2、5位置1,所以a2=0x03000017(0000 0011 0000 0000 0000 0000 0001 0111),(这里置1的几位参考寄存器定义,置1表示可用,所以必须这么做)
	MTC0   a2, COP_0_TLB_LO0	# Set up entry low0.		//将a2赋值给EntryLo0寄存器,设置第一个出口物理地址
	addu	a2, (0x01000000 >> PG_SHIFT)		//0x01000000是16M,右移6位后是0x00040000,这里的a2=0x03040017 (这里为什么要将0x01000000右移6位同样是根据EntryLo寄存器的格式来的,右移六位后,在寄存器的PFN中,代表的同样是0x01000000=16M)
	MTC0   a2, COP_0_TLB_LO1	# Set up entry low1.		//a2赋值给EntryLo1,设置第二个出口物理地址

	mtc0    a3, COP_0_TLB_INDEX	# Set the index.		//设置页号
	addiu	a3, 1			//页号加1,为下次循环准备
	li	a2, 0x02000000		//a2=0x02000000(32M)
	subu	a1, a2		//a1=0x40000000(1G),所以这里是将1G的空间每次递减,当1G地址空间设置完毕后即可退出
	nop
	tlbwi				# Write the TLB		//写TLB索引号

	bgtz	a1, 1b		//当a1的值大于0的时候,跳转回上一个1处,否则循环结束
	addu	a0, a2			# Step address 32Mb.	//跳转指令结束后,还会执行下一条指令,所以有的地方跳转指令后跟一个nop,这里利用这个特点将虚拟地址空间累加32M,准备下一次的条目设置

	jr	ra		//循环结束后返回
	nop
END(CPU_TLBInit)
           

继续阅读