添加系统调用来操作laura的cp2寄存器,但是自测发现要不就是根本不能使用,勉强能使用也是计数不准,今天仔细看了代码,找到了原因。
larua平台的performance相关寄存器在cp2。要读写cp2的相关寄存器首先要使能cp0 status寄存器的CU2(bit[30])。但是默认是不使能CU2。
Linux系统分内核态和用户态,CU0(bit[28])用来区别用户态和内核态。系统陷入内核态时会保存cp0 status寄存器的值并使能CU0,返回用户态时恢复cp0 status寄存器的值并disable CU0。所以使用系统调用使能CU2也不会成功(返回用户态时会自动恢复原来的值)。另外创建进程时会自动disable CU2。
现修改代码,使得:(本修改基于linux-2.6.27.28内核)
1. 系统启动之后默认使能CU2
修改linux-2.6.27.28/arch/mips/kernel/traps.c,把per_cpu_trap_init中Line1419
unsigned int status_set = ST0_CU0;
改为:
unsigned int status_set = ST0_CU0 | ST0_CU2;
本来linux-2.6.27.28/arch/mips/kernel/head.S中也需要修改
即会调用的setup_c0_status中的Line99由
or t0, ST0_CU0|/set|0x1f|/clr
改为:
or t0, ST0_CU2|ST0_CU0|/set|0x1f|/clr
但测试发现由于traps.c的设置在后面,所以head.S不修改也没关系。
2. 创建进程不会disable CU2
修改linux-2.6.27.28/arch/mips/kernel/process.c,把copy_thread函数中Line148/149由
p->thread.cp0_status = read_c0_status() & ~(ST0_CU2|ST0_CU1);
childregs->cp0_status &= ~(ST0_CU2|ST0_CU1);
改为:
p->thread.cp0_status = read_c0_status() & ~(ST0_CU1);
childregs->cp0_status &= ~(ST0_CU1);
这样就可以使用laura的cp2。
mips判断是kernel mode还是user mode的说明:
在stackframe.h里,这个SAVE_SOME宏里,根据cu0的值来判断是kernel mode(为1)还是user mode(为0),对两者采取不同的保存方式:
.macro SAVE_SOME
.set push
.set noat
.set reorder
mfc0 k0, CP0_STATUS
sll k0, 3 /* extract cu0 bit */
.set noreorder
bltz k0, 8f
move k1, sp
.set reorder
/* Called from user mode, new stack. */
get_saved_sp