On 10/19/2021 2:26 PM, xuejinze wrote:
彭总您好,
很抱歉打扰您,有个qemu的问题想向您请教下。
关于commit *8e19c7e6*添加的kunpeng-920的cpu寄存器的定义,我对比了直接从 kunpeng920服务器上直接读出来的寄存器的值,有很多是和patch里面是有出入的。
想请教下修改中这些值是基于什么来定义的。
下面是我这台设备cpuinfo里面的信息:
processor : 95
model name : HUAWEI,Kunpeng 920
BogoMIPS : 200.00
Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics fphp asimdhp cpuid asimdrdm jscvt fcma dcpop asimddp asimdfhm
CPU implementer : 0x48
CPU architecture: 8
CPU variant : 0x1
CPU part : 0xd01
CPU revision : 0
下面是我用的读取寄存器的程序:
/*
- Sample program to demonstrate the MRS emulation ABI.
- Copyright (C) 2015-2016, ARM Ltd
- Author: Suzuki K Poulose suzuki.poulose@arm.com
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
- This program is free software; you can redistribute it and/or modify
- it under the terms of the GNU General Public License version 2 as
- published by the Free Software Foundation.
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
*/
#include <asm/hwcap.h> #include <stdio.h> #include <sys/auxv.h>
#define get_cpu_ftr(id) ({ \ unsigned long __val; \ asm("mrs %0, "#id : "=r" (__val)); \ printf("%-20s: 0x%016lx\n", #id, __val); \ })
int main(void) {
if (!(getauxval(AT_HWCAP) & HWCAP_CPUID)) { fputs("CPUID registers unavailable\n", stderr); return 1; } get_cpu_ftr(ID_AA64ISAR0_EL1); get_cpu_ftr(ID_AA64ISAR1_EL1); get_cpu_ftr(ID_AA64MMFR0_EL1); get_cpu_ftr(ID_AA64MMFR1_EL1); get_cpu_ftr(ID_AA64PFR0_EL1); get_cpu_ftr(ID_AA64PFR1_EL1); get_cpu_ftr(ID_AA64DFR0_EL1); get_cpu_ftr(ID_AA64DFR1_EL1); get_cpu_ftr(MIDR_EL1); get_cpu_ftr(MPIDR_EL1); get_cpu_ftr(REVIDR_EL1); get_cpu_ftr(CTR_EL0);
#if 0 /* Unexposed register access causes SIGILL */ get_cpu_ftr(ID_MMFR0_EL1); #endif
return 0;
}
下面是用以上程序读出来的值:
[root@host203 ~]# ./a.out ID_AA64ISAR0_EL1 : 0x0001100010211120 ID_AA64ISAR1_EL1 : 0x0000000000011001 ID_AA64MMFR0_EL1 : 0x00000000ff000000 ID_AA64MMFR1_EL1 : 0x0000000000000000 ID_AA64PFR0_EL1 : 0x0000000000110011 ID_AA64PFR1_EL1 : 0x0000000000000000 ID_AA64DFR0_EL1 : 0x0000000000000006 ID_AA64DFR1_EL1 : 0x0000000000000000 MIDR_EL1 : 0x00000000481fd010 MPIDR_EL1 : 0x0000000080000000 REVIDR_EL1 : 0x0000000000000000 CTR_EL0 : 0x0000000084448004
我只对ID寄存器清除一点,其他的寄存器我也不是很清楚。所以下面说的都*只*针 对ID寄存器。
内核因为安全的原因,对于用户态的应用读取这些系统寄存器,只会呈现出一部分 值,还有一部分设置为了默认值,每个寄存器呈现出来的field的文档在 linux/Documentation/arm64/cpu-feature-registers.rst,就在这段代码的前面。
如果先要读取完整的寄存器值,可以写个内核模块在内核中读取。例如: #include <linux/module.h>
#define get_idreg(id) printk("%-20s: 0x%016llx\n", #id, read_sysreg_s(SYS_ ##id))
static int __init get_feature_init(void) { get_idreg(ID_AA64ISAR0_EL1); get_idreg(ID_AA64ISAR1_EL1); get_idreg(ID_AA64MMFR0_EL1); get_idreg(ID_AA64MMFR1_EL1); get_idreg(ID_AA64PFR0_EL1); get_idreg(ID_AA64PFR1_EL1); get_idreg(ID_AA64DFR0_EL1); get_idreg(ID_AA64DFR1_EL1);
get_idreg(MIDR_EL1); get_idreg(MPIDR_EL1); get_idreg(REVIDR_EL1); return 0; }
static void __exit get_feature_exit(void) { }
module_init(get_feature_init); module_exit(get_feature_exit); MODULE_LICENSE("GPL");
在我的机器上插入内核模块后会在dmesg中打印如下信息: [38928.608723] ID_AA64ISAR0_EL1 : 0x0001100010211120 [38928.608724] ID_AA64ISAR1_EL1 : 0x0000000000011001 [38928.608725] ID_AA64MMFR0_EL1 : 0x0000000000101125 [38928.608726] ID_AA64MMFR1_EL1 : 0x0000000010211122 [38928.608727] ID_AA64PFR0_EL1 : 0x0000010011111111 [38928.608727] ID_AA64PFR1_EL1 : 0x0000000000000000 [38928.608728] ID_AA64DFR0_EL1 : 0x0000000110305408 [38928.608729] ID_AA64DFR1_EL1 : 0x0000000000000000 [38928.608729] MIDR_EL1 : 0x00000000481fd010 [38928.608730] MPIDR_EL1 : 0x0000000081180300 [38928.608731] REVIDR_EL1 : 0x0000000000000000
具体隐藏的实现逻辑因为有段时间没有看这块代码了,有点记不太清了,所以下面 说的可能会有错误。在linux/arch/arm64/kernel/cpufeature.c中,定义了很多 ftr_id_*的变量,其中如果一个field定义为FTR_HIDDEN,则说明这个field对于用 户态是隐藏的。在init_cpu_ftr_reg中会根据定义的ftr_id_*初始化对应的 user_val、user_mask、sys_val。在用用户态读取这些寄存器的时候,在内核中会 调用到emulate_mrs,在这里面会根据之前初始化好的user_val、user_mask、 sys_val返回给用户态相应的值。
Thanks, Peng