* [RFC v2 0/7] kvm: arm64: emulate ID registers @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will In AArch64, guest will read the same values of the ID regsiters with host. Both of them read the values from arm64_ftr_regs. This patch series add support to emulate and configure ID registers so that we can control the value of ID registers that guest read. v1 -> v2: - save the ID registers in sysreg file instead of a new struct - apply a checker before setting the value to the register - add doc for new KVM_CAP_ARM_CPU_FEATURE Peng Liang (7): arm64: add a helper function to traverse arm64_ftr_regs arm64: introduce check_features kvm: arm64: save ID registers to sys_regs file kvm: arm64: introduce check_user kvm: arm64: implement check_user for ID registers kvm: arm64: make ID registers configurable kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension Documentation/virt/kvm/api.rst | 8 + arch/arm64/include/asm/cpufeature.h | 4 + arch/arm64/include/asm/kvm_coproc.h | 2 + arch/arm64/include/asm/kvm_host.h | 3 + arch/arm64/kernel/cpufeature.c | 36 +++ arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- arch/arm64/kvm/sys_regs.h | 6 + include/uapi/linux/kvm.h | 1 + 9 files changed, 532 insertions(+), 12 deletions(-) -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 0/7] kvm: arm64: emulate ID registers @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang In AArch64, guest will read the same values of the ID regsiters with host. Both of them read the values from arm64_ftr_regs. This patch series add support to emulate and configure ID registers so that we can control the value of ID registers that guest read. v1 -> v2: - save the ID registers in sysreg file instead of a new struct - apply a checker before setting the value to the register - add doc for new KVM_CAP_ARM_CPU_FEATURE Peng Liang (7): arm64: add a helper function to traverse arm64_ftr_regs arm64: introduce check_features kvm: arm64: save ID registers to sys_regs file kvm: arm64: introduce check_user kvm: arm64: implement check_user for ID registers kvm: arm64: make ID registers configurable kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension Documentation/virt/kvm/api.rst | 8 + arch/arm64/include/asm/cpufeature.h | 4 + arch/arm64/include/asm/kvm_coproc.h | 2 + arch/arm64/include/asm/kvm_host.h | 3 + arch/arm64/kernel/cpufeature.c | 36 +++ arch/arm64/kvm/arm.c | 3 + arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- arch/arm64/kvm/sys_regs.h | 6 + include/uapi/linux/kvm.h | 1 + 9 files changed, 532 insertions(+), 12 deletions(-) -- 2.26.2 ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:00 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will If we want to emulate ID registers, we need to initialize ID registers firstly. This commit is to add a helper function to traverse arm64_ftr_regs so that we can initialize ID registers from arm64_ftr_regs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 89b4f0142c28..2ba7c4f11d8a 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -79,6 +79,8 @@ struct arm64_ftr_reg { extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); + /* * CPU capabilities: * diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 6424584be01e..698b32705544 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) return regp->sys_val; } +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { + ret = (*op)(arm64_ftr_regs[i].sys_id, + arm64_ftr_regs[i].reg->sys_val, argp); + if (ret < 0) + return ret; + } + return 0; +} + #define read_sysreg_case(r) \ case r: return read_sysreg_s(r) -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang If we want to emulate ID registers, we need to initialize ID registers firstly. This commit is to add a helper function to traverse arm64_ftr_regs so that we can initialize ID registers from arm64_ftr_regs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ 2 files changed, 15 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 89b4f0142c28..2ba7c4f11d8a 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -79,6 +79,8 @@ struct arm64_ftr_reg { extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); + /* * CPU capabilities: * diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 6424584be01e..698b32705544 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) return regp->sys_val; } +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) +{ + int i, ret; + + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { + ret = (*op)(arm64_ftr_regs[i].sys_id, + arm64_ftr_regs[i].reg->sys_val, argp); + if (ret < 0) + return ret; + } + return 0; +} + #define read_sysreg_case(r) \ case r: return read_sysreg_s(r) -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 7:18 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:18 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: > If we want to emulate ID registers, we need to initialize ID registers > firstly. This commit is to add a helper function to traverse > arm64_ftr_regs so that we can initialize ID registers from > arm64_ftr_regs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/cpufeature.h | 2 ++ > arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ > 2 files changed, 15 insertions(+) > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > index 89b4f0142c28..2ba7c4f11d8a 100644 > --- a/arch/arm64/include/asm/cpufeature.h > +++ b/arch/arm64/include/asm/cpufeature.h > @@ -79,6 +79,8 @@ struct arm64_ftr_reg { > > extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; > > +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); > + > /* > * CPU capabilities: > * > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > index 6424584be01e..698b32705544 100644 > --- a/arch/arm64/kernel/cpufeature.c > +++ b/arch/arm64/kernel/cpufeature.c > @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) > return regp->sys_val; > } > > +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) > +{ > + int i, ret; > + > + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { > + ret = (*op)(arm64_ftr_regs[i].sys_id, > + arm64_ftr_regs[i].reg->sys_val, argp); > + if (ret < 0) > + return ret; > + } > + return 0; > +} > + > #define read_sysreg_case(r) \ > case r: return read_sysreg_s(r) > > -- > 2.26.2 > Skimming the rest of the patches to see how this is used I only saw a single callsite. Why wouldn't we just put this simple for-loop right there at that callsite? Or, IOW, I think this traverse function should be dropped. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs @ 2020-09-18 7:18 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:18 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: > If we want to emulate ID registers, we need to initialize ID registers > firstly. This commit is to add a helper function to traverse > arm64_ftr_regs so that we can initialize ID registers from > arm64_ftr_regs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/cpufeature.h | 2 ++ > arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ > 2 files changed, 15 insertions(+) > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > index 89b4f0142c28..2ba7c4f11d8a 100644 > --- a/arch/arm64/include/asm/cpufeature.h > +++ b/arch/arm64/include/asm/cpufeature.h > @@ -79,6 +79,8 @@ struct arm64_ftr_reg { > > extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; > > +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); > + > /* > * CPU capabilities: > * > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > index 6424584be01e..698b32705544 100644 > --- a/arch/arm64/kernel/cpufeature.c > +++ b/arch/arm64/kernel/cpufeature.c > @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) > return regp->sys_val; > } > > +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) > +{ > + int i, ret; > + > + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { > + ret = (*op)(arm64_ftr_regs[i].sys_id, > + arm64_ftr_regs[i].reg->sys_val, argp); > + if (ret < 0) > + return ret; > + } > + return 0; > +} > + > #define read_sysreg_case(r) \ > case r: return read_sysreg_s(r) > > -- > 2.26.2 > Skimming the rest of the patches to see how this is used I only saw a single callsite. Why wouldn't we just put this simple for-loop right there at that callsite? Or, IOW, I think this traverse function should be dropped. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs 2020-09-18 7:18 ` Andrew Jones @ 2020-09-18 9:24 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:24 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:18 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: >> If we want to emulate ID registers, we need to initialize ID registers >> firstly. This commit is to add a helper function to traverse >> arm64_ftr_regs so that we can initialize ID registers from >> arm64_ftr_regs. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/include/asm/cpufeature.h | 2 ++ >> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ >> 2 files changed, 15 insertions(+) >> >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >> index 89b4f0142c28..2ba7c4f11d8a 100644 >> --- a/arch/arm64/include/asm/cpufeature.h >> +++ b/arch/arm64/include/asm/cpufeature.h >> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { >> >> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; >> >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); >> + >> /* >> * CPU capabilities: >> * >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >> index 6424584be01e..698b32705544 100644 >> --- a/arch/arm64/kernel/cpufeature.c >> +++ b/arch/arm64/kernel/cpufeature.c >> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) >> return regp->sys_val; >> } >> >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) >> +{ >> + int i, ret; >> + >> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { >> + ret = (*op)(arm64_ftr_regs[i].sys_id, >> + arm64_ftr_regs[i].reg->sys_val, argp); >> + if (ret < 0) >> + return ret; >> + } >> + return 0; >> +} >> + >> #define read_sysreg_case(r) \ >> case r: return read_sysreg_s(r) >> >> -- >> 2.26.2 >> > > Skimming the rest of the patches to see how this is used I only saw a > single callsite. Why wouldn't we just put this simple for-loop right > there at that callsite? Or, IOW, I think this traverse function should > be dropped. > > Thanks, > drew > > . > arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, which is not a virtualization-related file. Putting this simple for-loop right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs @ 2020-09-18 9:24 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:24 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:18 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: >> If we want to emulate ID registers, we need to initialize ID registers >> firstly. This commit is to add a helper function to traverse >> arm64_ftr_regs so that we can initialize ID registers from >> arm64_ftr_regs. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/include/asm/cpufeature.h | 2 ++ >> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ >> 2 files changed, 15 insertions(+) >> >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >> index 89b4f0142c28..2ba7c4f11d8a 100644 >> --- a/arch/arm64/include/asm/cpufeature.h >> +++ b/arch/arm64/include/asm/cpufeature.h >> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { >> >> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; >> >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); >> + >> /* >> * CPU capabilities: >> * >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >> index 6424584be01e..698b32705544 100644 >> --- a/arch/arm64/kernel/cpufeature.c >> +++ b/arch/arm64/kernel/cpufeature.c >> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) >> return regp->sys_val; >> } >> >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) >> +{ >> + int i, ret; >> + >> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { >> + ret = (*op)(arm64_ftr_regs[i].sys_id, >> + arm64_ftr_regs[i].reg->sys_val, argp); >> + if (ret < 0) >> + return ret; >> + } >> + return 0; >> +} >> + >> #define read_sysreg_case(r) \ >> case r: return read_sysreg_s(r) >> >> -- >> 2.26.2 >> > > Skimming the rest of the patches to see how this is used I only saw a > single callsite. Why wouldn't we just put this simple for-loop right > there at that callsite? Or, IOW, I think this traverse function should > be dropped. > > Thanks, > drew > > . > arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, which is not a virtualization-related file. Putting this simple for-loop right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs 2020-09-18 9:24 ` Peng Liang @ 2020-09-18 10:28 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 10:28 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Fri, Sep 18, 2020 at 05:24:27PM +0800, Peng Liang wrote: > On 9/18/2020 3:18 PM, Andrew Jones wrote: > > On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: > >> If we want to emulate ID registers, we need to initialize ID registers > >> firstly. This commit is to add a helper function to traverse > >> arm64_ftr_regs so that we can initialize ID registers from > >> arm64_ftr_regs. > >> > >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> > >> --- > >> arch/arm64/include/asm/cpufeature.h | 2 ++ > >> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ > >> 2 files changed, 15 insertions(+) > >> > >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > >> index 89b4f0142c28..2ba7c4f11d8a 100644 > >> --- a/arch/arm64/include/asm/cpufeature.h > >> +++ b/arch/arm64/include/asm/cpufeature.h > >> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { > >> > >> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; > >> > >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); > >> + > >> /* > >> * CPU capabilities: > >> * > >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > >> index 6424584be01e..698b32705544 100644 > >> --- a/arch/arm64/kernel/cpufeature.c > >> +++ b/arch/arm64/kernel/cpufeature.c > >> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) > >> return regp->sys_val; > >> } > >> > >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) > >> +{ > >> + int i, ret; > >> + > >> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { > >> + ret = (*op)(arm64_ftr_regs[i].sys_id, > >> + arm64_ftr_regs[i].reg->sys_val, argp); > >> + if (ret < 0) > >> + return ret; > >> + } > >> + return 0; > >> +} > >> + > >> #define read_sysreg_case(r) \ > >> case r: return read_sysreg_s(r) > >> > >> -- > >> 2.26.2 > >> > > > > Skimming the rest of the patches to see how this is used I only saw a > > single callsite. Why wouldn't we just put this simple for-loop right > > there at that callsite? Or, IOW, I think this traverse function should > > be dropped. > > > > Thanks, > > drew > > > > . > > > > arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, > which is not a virtualization-related file. Putting this simple for-loop > right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? Well, the fact that arm64_ftr_regs is static to cpufeature.c is a clue that your implementation is likely playing with internal arm64_ftr state that it shouldn't be. If there's not an accessor function that works for you, then you can try adding one. Providing general functions like this, that are effectively just an odd way of removing 'static' from arm64_ftr_regs, breaks the encapsulation. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs @ 2020-09-18 10:28 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 10:28 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Fri, Sep 18, 2020 at 05:24:27PM +0800, Peng Liang wrote: > On 9/18/2020 3:18 PM, Andrew Jones wrote: > > On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: > >> If we want to emulate ID registers, we need to initialize ID registers > >> firstly. This commit is to add a helper function to traverse > >> arm64_ftr_regs so that we can initialize ID registers from > >> arm64_ftr_regs. > >> > >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> > >> --- > >> arch/arm64/include/asm/cpufeature.h | 2 ++ > >> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ > >> 2 files changed, 15 insertions(+) > >> > >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > >> index 89b4f0142c28..2ba7c4f11d8a 100644 > >> --- a/arch/arm64/include/asm/cpufeature.h > >> +++ b/arch/arm64/include/asm/cpufeature.h > >> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { > >> > >> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; > >> > >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); > >> + > >> /* > >> * CPU capabilities: > >> * > >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > >> index 6424584be01e..698b32705544 100644 > >> --- a/arch/arm64/kernel/cpufeature.c > >> +++ b/arch/arm64/kernel/cpufeature.c > >> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) > >> return regp->sys_val; > >> } > >> > >> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) > >> +{ > >> + int i, ret; > >> + > >> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { > >> + ret = (*op)(arm64_ftr_regs[i].sys_id, > >> + arm64_ftr_regs[i].reg->sys_val, argp); > >> + if (ret < 0) > >> + return ret; > >> + } > >> + return 0; > >> +} > >> + > >> #define read_sysreg_case(r) \ > >> case r: return read_sysreg_s(r) > >> > >> -- > >> 2.26.2 > >> > > > > Skimming the rest of the patches to see how this is used I only saw a > > single callsite. Why wouldn't we just put this simple for-loop right > > there at that callsite? Or, IOW, I think this traverse function should > > be dropped. > > > > Thanks, > > drew > > > > . > > > > arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, > which is not a virtualization-related file. Putting this simple for-loop > right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? Well, the fact that arm64_ftr_regs is static to cpufeature.c is a clue that your implementation is likely playing with internal arm64_ftr state that it shouldn't be. If there's not an accessor function that works for you, then you can try adding one. Providing general functions like this, that are effectively just an odd way of removing 'static' from arm64_ftr_regs, breaks the encapsulation. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs 2020-09-18 10:28 ` Andrew Jones @ 2020-09-18 11:58 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 11:58 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 6:28 PM, Andrew Jones wrote: > On Fri, Sep 18, 2020 at 05:24:27PM +0800, Peng Liang wrote: >> On 9/18/2020 3:18 PM, Andrew Jones wrote: >>> On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: >>>> If we want to emulate ID registers, we need to initialize ID registers >>>> firstly. This commit is to add a helper function to traverse >>>> arm64_ftr_regs so that we can initialize ID registers from >>>> arm64_ftr_regs. >>>> >>>> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >>>> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >>>> --- >>>> arch/arm64/include/asm/cpufeature.h | 2 ++ >>>> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ >>>> 2 files changed, 15 insertions(+) >>>> >>>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >>>> index 89b4f0142c28..2ba7c4f11d8a 100644 >>>> --- a/arch/arm64/include/asm/cpufeature.h >>>> +++ b/arch/arm64/include/asm/cpufeature.h >>>> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { >>>> >>>> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; >>>> >>>> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); >>>> + >>>> /* >>>> * CPU capabilities: >>>> * >>>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >>>> index 6424584be01e..698b32705544 100644 >>>> --- a/arch/arm64/kernel/cpufeature.c >>>> +++ b/arch/arm64/kernel/cpufeature.c >>>> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) >>>> return regp->sys_val; >>>> } >>>> >>>> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) >>>> +{ >>>> + int i, ret; >>>> + >>>> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { >>>> + ret = (*op)(arm64_ftr_regs[i].sys_id, >>>> + arm64_ftr_regs[i].reg->sys_val, argp); >>>> + if (ret < 0) >>>> + return ret; >>>> + } >>>> + return 0; >>>> +} >>>> + >>>> #define read_sysreg_case(r) \ >>>> case r: return read_sysreg_s(r) >>>> >>>> -- >>>> 2.26.2 >>>> >>> >>> Skimming the rest of the patches to see how this is used I only saw a >>> single callsite. Why wouldn't we just put this simple for-loop right >>> there at that callsite? Or, IOW, I think this traverse function should >>> be dropped. >>> >>> Thanks, >>> drew >>> >>> . >>> >> >> arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, >> which is not a virtualization-related file. Putting this simple for-loop >> right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? > > Well, the fact that arm64_ftr_regs is static to cpufeature.c is a clue > that your implementation is likely playing with internal arm64_ftr > state that it shouldn't be. If there's not an accessor function that > works for you, then you can try adding one. Providing general functions > like this, that are effectively just an odd way of removing 'static' > from arm64_ftr_regs, breaks the encapsulation. > > Thanks, > drew > > . > I found get_arm64_ftr_reg_nowarn and get_arm64_ftr_reg in cpufeature.c which will search and return the arm64_ftr_reg* according to the sys_id. But they are all static. Hence, I think cpufeature.c don't want other modules to access the arm64_ftr_reg*. So I add arm64_cpu_ftr_regs_traverse to traverse the arm64_ftr_regs and pass the id and value to op instead of the arm64_ftr_reg*. Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs @ 2020-09-18 11:58 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 11:58 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 6:28 PM, Andrew Jones wrote: > On Fri, Sep 18, 2020 at 05:24:27PM +0800, Peng Liang wrote: >> On 9/18/2020 3:18 PM, Andrew Jones wrote: >>> On Thu, Sep 17, 2020 at 08:00:55PM +0800, Peng Liang wrote: >>>> If we want to emulate ID registers, we need to initialize ID registers >>>> firstly. This commit is to add a helper function to traverse >>>> arm64_ftr_regs so that we can initialize ID registers from >>>> arm64_ftr_regs. >>>> >>>> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >>>> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >>>> --- >>>> arch/arm64/include/asm/cpufeature.h | 2 ++ >>>> arch/arm64/kernel/cpufeature.c | 13 +++++++++++++ >>>> 2 files changed, 15 insertions(+) >>>> >>>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >>>> index 89b4f0142c28..2ba7c4f11d8a 100644 >>>> --- a/arch/arm64/include/asm/cpufeature.h >>>> +++ b/arch/arm64/include/asm/cpufeature.h >>>> @@ -79,6 +79,8 @@ struct arm64_ftr_reg { >>>> >>>> extern struct arm64_ftr_reg arm64_ftr_reg_ctrel0; >>>> >>>> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp); >>>> + >>>> /* >>>> * CPU capabilities: >>>> * >>>> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >>>> index 6424584be01e..698b32705544 100644 >>>> --- a/arch/arm64/kernel/cpufeature.c >>>> +++ b/arch/arm64/kernel/cpufeature.c >>>> @@ -1112,6 +1112,19 @@ u64 read_sanitised_ftr_reg(u32 id) >>>> return regp->sys_val; >>>> } >>>> >>>> +int arm64_cpu_ftr_regs_traverse(int (*op)(u32, u64, void *), void *argp) >>>> +{ >>>> + int i, ret; >>>> + >>>> + for (i = 0; i < ARRAY_SIZE(arm64_ftr_regs); i++) { >>>> + ret = (*op)(arm64_ftr_regs[i].sys_id, >>>> + arm64_ftr_regs[i].reg->sys_val, argp); >>>> + if (ret < 0) >>>> + return ret; >>>> + } >>>> + return 0; >>>> +} >>>> + >>>> #define read_sysreg_case(r) \ >>>> case r: return read_sysreg_s(r) >>>> >>>> -- >>>> 2.26.2 >>>> >>> >>> Skimming the rest of the patches to see how this is used I only saw a >>> single callsite. Why wouldn't we just put this simple for-loop right >>> there at that callsite? Or, IOW, I think this traverse function should >>> be dropped. >>> >>> Thanks, >>> drew >>> >>> . >>> >> >> arm64_ftr_regs is defined as a static array in arch/arm64/kernel/cpufeature.c, >> which is not a virtualization-related file. Putting this simple for-loop >> right there will make cpufeature.c depend on kvm_host.h. Is this a good idea? > > Well, the fact that arm64_ftr_regs is static to cpufeature.c is a clue > that your implementation is likely playing with internal arm64_ftr > state that it shouldn't be. If there's not an accessor function that > works for you, then you can try adding one. Providing general functions > like this, that are effectively just an odd way of removing 'static' > from arm64_ftr_regs, breaks the encapsulation. > > Thanks, > drew > > . > I found get_arm64_ftr_reg_nowarn and get_arm64_ftr_reg in cpufeature.c which will search and return the arm64_ftr_reg* according to the sys_id. But they are all static. Hence, I think cpufeature.c don't want other modules to access the arm64_ftr_reg*. So I add arm64_cpu_ftr_regs_traverse to traverse the arm64_ftr_regs and pass the id and value to op instead of the arm64_ftr_reg*. Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 2/7] arm64: introduce check_features 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:00 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will To emulate ID registers, we need to validate the value of the register defined by user space. For most ID registers, we need to check whether each field defined by user space is no more than that of host (whether host support the corresponding features) and whether the fields are supposed to be exposed to guest. Introduce check_features to do those jobs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 2ba7c4f11d8a..954adc5ca72f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); u64 read_sanitised_ftr_reg(u32 id); +int check_features(u32 sys_reg, u64 val); + static inline bool cpu_supports_mixed_endian_el0(void) { return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 698b32705544..e58926992a70 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, return sprintf(buf, "Vulnerable\n"); } + +int check_features(u32 sys_reg, u64 val) +{ + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); + const struct arm64_ftr_bits *ftrp; + u64 exposed_mask = 0; + + if (!reg) + return -ENOENT; + + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { + if (arm64_ftr_value(ftrp, reg->sys_val) < + arm64_ftr_value(ftrp, val)) { + return -EINVAL; + } + exposed_mask |= arm64_ftr_mask(ftrp); + } + + if (val & ~exposed_mask) + return -EINVAL; + + return 0; +} -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 2/7] arm64: introduce check_features @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang To emulate ID registers, we need to validate the value of the register defined by user space. For most ID registers, we need to check whether each field defined by user space is no more than that of host (whether host support the corresponding features) and whether the fields are supposed to be exposed to guest. Introduce check_features to do those jobs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/cpufeature.h | 2 ++ arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ 2 files changed, 25 insertions(+) diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 2ba7c4f11d8a..954adc5ca72f 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); u64 read_sanitised_ftr_reg(u32 id); +int check_features(u32 sys_reg, u64 val); + static inline bool cpu_supports_mixed_endian_el0(void) { return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index 698b32705544..e58926992a70 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, return sprintf(buf, "Vulnerable\n"); } + +int check_features(u32 sys_reg, u64 val) +{ + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); + const struct arm64_ftr_bits *ftrp; + u64 exposed_mask = 0; + + if (!reg) + return -ENOENT; + + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { + if (arm64_ftr_value(ftrp, reg->sys_val) < + arm64_ftr_value(ftrp, val)) { + return -EINVAL; + } + exposed_mask |= arm64_ftr_mask(ftrp); + } + + if (val & ~exposed_mask) + return -EINVAL; + + return 0; +} -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 2/7] arm64: introduce check_features 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 7:30 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:30 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:56PM +0800, Peng Liang wrote: > To emulate ID registers, we need to validate the value of the register > defined by user space. For most ID registers, we need to check whether > each field defined by user space is no more than that of host (whether > host support the corresponding features) and whether the fields are > supposed to be exposed to guest. Introduce check_features to do those > jobs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/cpufeature.h | 2 ++ > arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ > 2 files changed, 25 insertions(+) > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > index 2ba7c4f11d8a..954adc5ca72f 100644 > --- a/arch/arm64/include/asm/cpufeature.h > +++ b/arch/arm64/include/asm/cpufeature.h > @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); > > u64 read_sanitised_ftr_reg(u32 id); > > +int check_features(u32 sys_reg, u64 val); > + > static inline bool cpu_supports_mixed_endian_el0(void) > { > return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > index 698b32705544..e58926992a70 100644 > --- a/arch/arm64/kernel/cpufeature.c > +++ b/arch/arm64/kernel/cpufeature.c > @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, > > return sprintf(buf, "Vulnerable\n"); > } > + > +int check_features(u32 sys_reg, u64 val) > +{ > + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); > + const struct arm64_ftr_bits *ftrp; > + u64 exposed_mask = 0; > + > + if (!reg) > + return -ENOENT; > + > + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { > + if (arm64_ftr_value(ftrp, reg->sys_val) < > + arm64_ftr_value(ftrp, val)) { > + return -EINVAL; This assumes that 0b1111 is invalid if the host has e.g. 0b0001, but, IIRC, there are some ID registers where 0b1111 means the feature is disabled. > + } > + exposed_mask |= arm64_ftr_mask(ftrp); > + } > + > + if (val & ~exposed_mask) > + return -EINVAL; > + > + return 0; > +} > -- > 2.26.2 > I don't think we should be trying to do the verification at the ftr_bits level, at least not generally. Trying to handle all ID registers the same way is bound to fail, for the 0b1111 vs. 0b0000 reason pointed out above, and probably other reasons. As I stated before, we should be validating each feature of each ID register on a case by case basis, and we should be using higher level CPU feature checking APIs to get that right. Also, what about validating that all VCPUs have consistent features exposed? Each VCPU could select a valid feature mask by this check, but different ones, which will obviously create a completely broken guest. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 2/7] arm64: introduce check_features @ 2020-09-18 7:30 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:30 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:56PM +0800, Peng Liang wrote: > To emulate ID registers, we need to validate the value of the register > defined by user space. For most ID registers, we need to check whether > each field defined by user space is no more than that of host (whether > host support the corresponding features) and whether the fields are > supposed to be exposed to guest. Introduce check_features to do those > jobs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/cpufeature.h | 2 ++ > arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ > 2 files changed, 25 insertions(+) > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > index 2ba7c4f11d8a..954adc5ca72f 100644 > --- a/arch/arm64/include/asm/cpufeature.h > +++ b/arch/arm64/include/asm/cpufeature.h > @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); > > u64 read_sanitised_ftr_reg(u32 id); > > +int check_features(u32 sys_reg, u64 val); > + > static inline bool cpu_supports_mixed_endian_el0(void) > { > return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > index 698b32705544..e58926992a70 100644 > --- a/arch/arm64/kernel/cpufeature.c > +++ b/arch/arm64/kernel/cpufeature.c > @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, > > return sprintf(buf, "Vulnerable\n"); > } > + > +int check_features(u32 sys_reg, u64 val) > +{ > + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); > + const struct arm64_ftr_bits *ftrp; > + u64 exposed_mask = 0; > + > + if (!reg) > + return -ENOENT; > + > + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { > + if (arm64_ftr_value(ftrp, reg->sys_val) < > + arm64_ftr_value(ftrp, val)) { > + return -EINVAL; This assumes that 0b1111 is invalid if the host has e.g. 0b0001, but, IIRC, there are some ID registers where 0b1111 means the feature is disabled. > + } > + exposed_mask |= arm64_ftr_mask(ftrp); > + } > + > + if (val & ~exposed_mask) > + return -EINVAL; > + > + return 0; > +} > -- > 2.26.2 > I don't think we should be trying to do the verification at the ftr_bits level, at least not generally. Trying to handle all ID registers the same way is bound to fail, for the 0b1111 vs. 0b0000 reason pointed out above, and probably other reasons. As I stated before, we should be validating each feature of each ID register on a case by case basis, and we should be using higher level CPU feature checking APIs to get that right. Also, what about validating that all VCPUs have consistent features exposed? Each VCPU could select a valid feature mask by this check, but different ones, which will obviously create a completely broken guest. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 2/7] arm64: introduce check_features 2020-09-18 7:30 ` Andrew Jones @ 2020-09-18 9:25 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:25 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:30 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:56PM +0800, Peng Liang wrote: >> To emulate ID registers, we need to validate the value of the register >> defined by user space. For most ID registers, we need to check whether >> each field defined by user space is no more than that of host (whether >> host support the corresponding features) and whether the fields are >> supposed to be exposed to guest. Introduce check_features to do those >> jobs. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/include/asm/cpufeature.h | 2 ++ >> arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ >> 2 files changed, 25 insertions(+) >> >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >> index 2ba7c4f11d8a..954adc5ca72f 100644 >> --- a/arch/arm64/include/asm/cpufeature.h >> +++ b/arch/arm64/include/asm/cpufeature.h >> @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); >> >> u64 read_sanitised_ftr_reg(u32 id); >> >> +int check_features(u32 sys_reg, u64 val); >> + >> static inline bool cpu_supports_mixed_endian_el0(void) >> { >> return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >> index 698b32705544..e58926992a70 100644 >> --- a/arch/arm64/kernel/cpufeature.c >> +++ b/arch/arm64/kernel/cpufeature.c >> @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, >> >> return sprintf(buf, "Vulnerable\n"); >> } >> + >> +int check_features(u32 sys_reg, u64 val) >> +{ >> + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); >> + const struct arm64_ftr_bits *ftrp; >> + u64 exposed_mask = 0; >> + >> + if (!reg) >> + return -ENOENT; >> + >> + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { >> + if (arm64_ftr_value(ftrp, reg->sys_val) < >> + arm64_ftr_value(ftrp, val)) { >> + return -EINVAL; > > This assumes that 0b1111 is invalid if the host has e.g. 0b0001, > but, IIRC, there are some ID registers where 0b1111 means the > feature is disabled. I think arm64_ftr_value will handle it correctly. If the value of the field is 0b1111 and the field is signed, arm64_ftr_value will return -1. > >> + } >> + exposed_mask |= arm64_ftr_mask(ftrp); >> + } >> + >> + if (val & ~exposed_mask) >> + return -EINVAL; >> + >> + return 0; >> +} >> -- >> 2.26.2 >> > > I don't think we should be trying to do the verification at the ftr_bits > level, at least not generally. Trying to handle all ID registers the > same way is bound to fail, for the 0b1111 vs. 0b0000 reason pointed > out above, and probably other reasons. As I stated before, we should be > validating each feature of each ID register on a case by case basis, > and we should be using higher level CPU feature checking APIs to get > that right. > > Also, what about validating that all VCPUs have consistent features > exposed? Each VCPU could select a valid feature mask by this check, > but different ones, which will obviously create a completely broken > guest. > > Thanks, > drew > > . > Thank you for pointing this. I haven't thought about it yet... Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 2/7] arm64: introduce check_features @ 2020-09-18 9:25 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:25 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:30 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:56PM +0800, Peng Liang wrote: >> To emulate ID registers, we need to validate the value of the register >> defined by user space. For most ID registers, we need to check whether >> each field defined by user space is no more than that of host (whether >> host support the corresponding features) and whether the fields are >> supposed to be exposed to guest. Introduce check_features to do those >> jobs. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/include/asm/cpufeature.h | 2 ++ >> arch/arm64/kernel/cpufeature.c | 23 +++++++++++++++++++++++ >> 2 files changed, 25 insertions(+) >> >> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h >> index 2ba7c4f11d8a..954adc5ca72f 100644 >> --- a/arch/arm64/include/asm/cpufeature.h >> +++ b/arch/arm64/include/asm/cpufeature.h >> @@ -579,6 +579,8 @@ void check_local_cpu_capabilities(void); >> >> u64 read_sanitised_ftr_reg(u32 id); >> >> +int check_features(u32 sys_reg, u64 val); >> + >> static inline bool cpu_supports_mixed_endian_el0(void) >> { >> return id_aa64mmfr0_mixed_endian_el0(read_cpuid(ID_AA64MMFR0_EL1)); >> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c >> index 698b32705544..e58926992a70 100644 >> --- a/arch/arm64/kernel/cpufeature.c >> +++ b/arch/arm64/kernel/cpufeature.c >> @@ -2850,3 +2850,26 @@ ssize_t cpu_show_meltdown(struct device *dev, struct device_attribute *attr, >> >> return sprintf(buf, "Vulnerable\n"); >> } >> + >> +int check_features(u32 sys_reg, u64 val) >> +{ >> + struct arm64_ftr_reg *reg = get_arm64_ftr_reg(sys_reg); >> + const struct arm64_ftr_bits *ftrp; >> + u64 exposed_mask = 0; >> + >> + if (!reg) >> + return -ENOENT; >> + >> + for (ftrp = reg->ftr_bits; ftrp->width; ftrp++) { >> + if (arm64_ftr_value(ftrp, reg->sys_val) < >> + arm64_ftr_value(ftrp, val)) { >> + return -EINVAL; > > This assumes that 0b1111 is invalid if the host has e.g. 0b0001, > but, IIRC, there are some ID registers where 0b1111 means the > feature is disabled. I think arm64_ftr_value will handle it correctly. If the value of the field is 0b1111 and the field is signed, arm64_ftr_value will return -1. > >> + } >> + exposed_mask |= arm64_ftr_mask(ftrp); >> + } >> + >> + if (val & ~exposed_mask) >> + return -EINVAL; >> + >> + return 0; >> +} >> -- >> 2.26.2 >> > > I don't think we should be trying to do the verification at the ftr_bits > level, at least not generally. Trying to handle all ID registers the > same way is bound to fail, for the 0b1111 vs. 0b0000 reason pointed > out above, and probably other reasons. As I stated before, we should be > validating each feature of each ID register on a case by case basis, > and we should be using higher level CPU feature checking APIs to get > that right. > > Also, what about validating that all VCPUs have consistent features > exposed? Each VCPU could select a valid feature mask by this check, > but different ones, which will obviously create a completely broken > guest. > > Thanks, > drew > > . > Thank you for pointing this. I haven't thought about it yet... Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 3/7] kvm: arm64: save ID registers to sys_regs file 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:00 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will To emulate the ID registers, we need a place to storage the values of the ID regsiters. Maybe putting them in sysreg file is a good idea. This commit has no functional changes but only code refactor. When initializing a vCPU, get the values of the ID registers from arm64_ftr_regs and storage them in sysreg file. And we just read the value from sysreg file when getting/setting the value of the ID regs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/kvm_coproc.h | 2 ++ arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/arm.c | 2 ++ arch/arm64/kvm/sys_regs.c | 33 +++++++++++++++++++++++++---- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h index d6bb40122fdb..76e8c3cb0662 100644 --- a/arch/arm64/include/asm/kvm_coproc.h +++ b/arch/arm64/include/asm/kvm_coproc.h @@ -35,4 +35,6 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu); +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_COPROC_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 905c2b87e05a..50152e364c4f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -184,6 +184,9 @@ enum vcpu_sysreg { CNTP_CVAL_EL0, CNTP_CTL_EL0, + ID_REG_BASE, + ID_REG_END = ID_REG_BASE + 55, + /* 32bit specific registers. Keep them at the end of the range */ DACR32_EL2, /* Domain Access Control Register */ IFSR32_EL2, /* Instruction Fault Status Register */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index b588c3b5c2f0..6d961e192268 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -274,6 +274,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (err) return err; + kvm_arm_sys_reg_init(vcpu); + return create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 077293b5115f..2b0fa8d5ac62 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1119,13 +1119,16 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, return true; } +#define ID_REG_INDEX(id) \ + (ID_REG_BASE + (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))) + /* Read a sanitised cpufeature ID register by sys_reg_desc */ -static u64 read_id_reg(const struct kvm_vcpu *vcpu, +static u64 read_id_reg(struct kvm_vcpu *vcpu, struct sys_reg_desc const *r, bool raz) { u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); - u64 val = raz ? 0 : read_sanitised_ftr_reg(id); + u64 val = raz ? 0 : __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)); if (id == SYS_ID_AA64PFR0_EL1) { if (!vcpu_has_sve(vcpu)) @@ -1265,7 +1268,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, * are stored, and for set_id_reg() we don't allow the effective value * to be changed. */ -static int __get_id_reg(const struct kvm_vcpu *vcpu, +static int __get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { @@ -1275,7 +1278,7 @@ static int __get_id_reg(const struct kvm_vcpu *vcpu, return reg_to_user(uaddr, &val, id); } -static int __set_id_reg(const struct kvm_vcpu *vcpu, +static int __set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { @@ -2854,3 +2857,25 @@ void kvm_sys_reg_table_init(void) /* Clear all higher bits. */ cache_levels &= (1 << (i*3))-1; } + +static int get_cpu_ftr(u32 id, u64 val, void *argp) +{ + struct kvm_vcpu *vcpu = argp; + + /* + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), + * where 1<=crm<8, 0<=op2<8. + */ + if (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) > 0 && + sys_reg_CRm(id) < 8) { + __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)) = val; + } + + return 0; +} + +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu) +{ + arm64_cpu_ftr_regs_traverse(get_cpu_ftr, vcpu); +} -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 3/7] kvm: arm64: save ID registers to sys_regs file @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang To emulate the ID registers, we need a place to storage the values of the ID regsiters. Maybe putting them in sysreg file is a good idea. This commit has no functional changes but only code refactor. When initializing a vCPU, get the values of the ID registers from arm64_ftr_regs and storage them in sysreg file. And we just read the value from sysreg file when getting/setting the value of the ID regs. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/include/asm/kvm_coproc.h | 2 ++ arch/arm64/include/asm/kvm_host.h | 3 +++ arch/arm64/kvm/arm.c | 2 ++ arch/arm64/kvm/sys_regs.c | 33 +++++++++++++++++++++++++---- 4 files changed, 36 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h index d6bb40122fdb..76e8c3cb0662 100644 --- a/arch/arm64/include/asm/kvm_coproc.h +++ b/arch/arm64/include/asm/kvm_coproc.h @@ -35,4 +35,6 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu); +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu); + #endif /* __ARM64_KVM_COPROC_H__ */ diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h index 905c2b87e05a..50152e364c4f 100644 --- a/arch/arm64/include/asm/kvm_host.h +++ b/arch/arm64/include/asm/kvm_host.h @@ -184,6 +184,9 @@ enum vcpu_sysreg { CNTP_CVAL_EL0, CNTP_CTL_EL0, + ID_REG_BASE, + ID_REG_END = ID_REG_BASE + 55, + /* 32bit specific registers. Keep them at the end of the range */ DACR32_EL2, /* Domain Access Control Register */ IFSR32_EL2, /* Instruction Fault Status Register */ diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index b588c3b5c2f0..6d961e192268 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -274,6 +274,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) if (err) return err; + kvm_arm_sys_reg_init(vcpu); + return create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP); } diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 077293b5115f..2b0fa8d5ac62 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1119,13 +1119,16 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, return true; } +#define ID_REG_INDEX(id) \ + (ID_REG_BASE + (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))) + /* Read a sanitised cpufeature ID register by sys_reg_desc */ -static u64 read_id_reg(const struct kvm_vcpu *vcpu, +static u64 read_id_reg(struct kvm_vcpu *vcpu, struct sys_reg_desc const *r, bool raz) { u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); - u64 val = raz ? 0 : read_sanitised_ftr_reg(id); + u64 val = raz ? 0 : __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)); if (id == SYS_ID_AA64PFR0_EL1) { if (!vcpu_has_sve(vcpu)) @@ -1265,7 +1268,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, * are stored, and for set_id_reg() we don't allow the effective value * to be changed. */ -static int __get_id_reg(const struct kvm_vcpu *vcpu, +static int __get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { @@ -1275,7 +1278,7 @@ static int __get_id_reg(const struct kvm_vcpu *vcpu, return reg_to_user(uaddr, &val, id); } -static int __set_id_reg(const struct kvm_vcpu *vcpu, +static int __set_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, bool raz) { @@ -2854,3 +2857,25 @@ void kvm_sys_reg_table_init(void) /* Clear all higher bits. */ cache_levels &= (1 << (i*3))-1; } + +static int get_cpu_ftr(u32 id, u64 val, void *argp) +{ + struct kvm_vcpu *vcpu = argp; + + /* + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), + * where 1<=crm<8, 0<=op2<8. + */ + if (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) > 0 && + sys_reg_CRm(id) < 8) { + __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)) = val; + } + + return 0; +} + +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu) +{ + arm64_cpu_ftr_regs_traverse(get_cpu_ftr, vcpu); +} -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 3/7] kvm: arm64: save ID registers to sys_regs file 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 7:34 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:34 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:57PM +0800, Peng Liang wrote: > To emulate the ID registers, we need a place to storage the values of > the ID regsiters. Maybe putting them in sysreg file is a good idea. > > This commit has no functional changes but only code refactor. When > initializing a vCPU, get the values of the ID registers from > arm64_ftr_regs and storage them in sysreg file. And we just read > the value from sysreg file when getting/setting the value of the ID > regs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/kvm_coproc.h | 2 ++ > arch/arm64/include/asm/kvm_host.h | 3 +++ > arch/arm64/kvm/arm.c | 2 ++ > arch/arm64/kvm/sys_regs.c | 33 +++++++++++++++++++++++++---- > 4 files changed, 36 insertions(+), 4 deletions(-) > > diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h > index d6bb40122fdb..76e8c3cb0662 100644 > --- a/arch/arm64/include/asm/kvm_coproc.h > +++ b/arch/arm64/include/asm/kvm_coproc.h > @@ -35,4 +35,6 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); > int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); > unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu); > > +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu); > + > #endif /* __ARM64_KVM_COPROC_H__ */ > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index 905c2b87e05a..50152e364c4f 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -184,6 +184,9 @@ enum vcpu_sysreg { > CNTP_CVAL_EL0, > CNTP_CTL_EL0, > > + ID_REG_BASE, > + ID_REG_END = ID_REG_BASE + 55, > + > /* 32bit specific registers. Keep them at the end of the range */ > DACR32_EL2, /* Domain Access Control Register */ > IFSR32_EL2, /* Instruction Fault Status Register */ > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c > index b588c3b5c2f0..6d961e192268 100644 > --- a/arch/arm64/kvm/arm.c > +++ b/arch/arm64/kvm/arm.c > @@ -274,6 +274,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) > if (err) > return err; > > + kvm_arm_sys_reg_init(vcpu); > + > return create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP); > } > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 077293b5115f..2b0fa8d5ac62 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1119,13 +1119,16 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, > return true; > } > > +#define ID_REG_INDEX(id) \ > + (ID_REG_BASE + (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))) > + > /* Read a sanitised cpufeature ID register by sys_reg_desc */ > -static u64 read_id_reg(const struct kvm_vcpu *vcpu, > +static u64 read_id_reg(struct kvm_vcpu *vcpu, > struct sys_reg_desc const *r, bool raz) > { > u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, > (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); > - u64 val = raz ? 0 : read_sanitised_ftr_reg(id); > + u64 val = raz ? 0 : __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)); > > if (id == SYS_ID_AA64PFR0_EL1) { > if (!vcpu_has_sve(vcpu)) > @@ -1265,7 +1268,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, > * are stored, and for set_id_reg() we don't allow the effective value > * to be changed. > */ > -static int __get_id_reg(const struct kvm_vcpu *vcpu, > +static int __get_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > bool raz) > { > @@ -1275,7 +1278,7 @@ static int __get_id_reg(const struct kvm_vcpu *vcpu, > return reg_to_user(uaddr, &val, id); > } > > -static int __set_id_reg(const struct kvm_vcpu *vcpu, > +static int __set_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > bool raz) > { > @@ -2854,3 +2857,25 @@ void kvm_sys_reg_table_init(void) > /* Clear all higher bits. */ > cache_levels &= (1 << (i*3))-1; > } > + > +static int get_cpu_ftr(u32 id, u64 val, void *argp) 'get' doesn't seem like the right verb here, but I don't think we need this function anyway, since we don't need arm64_cpu_ftr_regs_traverse(). Just put the for-loop for arm64_cpu_ftr_regs_traverse() and this code directly in kvm_arm_sys_reg_init(). > +{ > + struct kvm_vcpu *vcpu = argp; > + > + /* > + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), > + * where 1<=crm<8, 0<=op2<8. > + */ > + if (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && > + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) > 0 && > + sys_reg_CRm(id) < 8) { > + __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)) = val; > + } > + > + return 0; > +} > + > +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu) > +{ > + arm64_cpu_ftr_regs_traverse(get_cpu_ftr, vcpu); > +} > -- > 2.26.2 > Besides the pointless functions, this patch looks fine to me. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 3/7] kvm: arm64: save ID registers to sys_regs file @ 2020-09-18 7:34 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:34 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:57PM +0800, Peng Liang wrote: > To emulate the ID registers, we need a place to storage the values of > the ID regsiters. Maybe putting them in sysreg file is a good idea. > > This commit has no functional changes but only code refactor. When > initializing a vCPU, get the values of the ID registers from > arm64_ftr_regs and storage them in sysreg file. And we just read > the value from sysreg file when getting/setting the value of the ID > regs. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/include/asm/kvm_coproc.h | 2 ++ > arch/arm64/include/asm/kvm_host.h | 3 +++ > arch/arm64/kvm/arm.c | 2 ++ > arch/arm64/kvm/sys_regs.c | 33 +++++++++++++++++++++++++---- > 4 files changed, 36 insertions(+), 4 deletions(-) > > diff --git a/arch/arm64/include/asm/kvm_coproc.h b/arch/arm64/include/asm/kvm_coproc.h > index d6bb40122fdb..76e8c3cb0662 100644 > --- a/arch/arm64/include/asm/kvm_coproc.h > +++ b/arch/arm64/include/asm/kvm_coproc.h > @@ -35,4 +35,6 @@ int kvm_arm_sys_reg_get_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); > int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *); > unsigned long kvm_arm_num_sys_reg_descs(struct kvm_vcpu *vcpu); > > +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu); > + > #endif /* __ARM64_KVM_COPROC_H__ */ > diff --git a/arch/arm64/include/asm/kvm_host.h b/arch/arm64/include/asm/kvm_host.h > index 905c2b87e05a..50152e364c4f 100644 > --- a/arch/arm64/include/asm/kvm_host.h > +++ b/arch/arm64/include/asm/kvm_host.h > @@ -184,6 +184,9 @@ enum vcpu_sysreg { > CNTP_CVAL_EL0, > CNTP_CTL_EL0, > > + ID_REG_BASE, > + ID_REG_END = ID_REG_BASE + 55, > + > /* 32bit specific registers. Keep them at the end of the range */ > DACR32_EL2, /* Domain Access Control Register */ > IFSR32_EL2, /* Instruction Fault Status Register */ > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c > index b588c3b5c2f0..6d961e192268 100644 > --- a/arch/arm64/kvm/arm.c > +++ b/arch/arm64/kvm/arm.c > @@ -274,6 +274,8 @@ int kvm_arch_vcpu_create(struct kvm_vcpu *vcpu) > if (err) > return err; > > + kvm_arm_sys_reg_init(vcpu); > + > return create_hyp_mappings(vcpu, vcpu + 1, PAGE_HYP); > } > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 077293b5115f..2b0fa8d5ac62 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1119,13 +1119,16 @@ static bool access_arch_timer(struct kvm_vcpu *vcpu, > return true; > } > > +#define ID_REG_INDEX(id) \ > + (ID_REG_BASE + (((sys_reg_CRm(id) - 1) << 3) | sys_reg_Op2(id))) > + > /* Read a sanitised cpufeature ID register by sys_reg_desc */ > -static u64 read_id_reg(const struct kvm_vcpu *vcpu, > +static u64 read_id_reg(struct kvm_vcpu *vcpu, > struct sys_reg_desc const *r, bool raz) > { > u32 id = sys_reg((u32)r->Op0, (u32)r->Op1, > (u32)r->CRn, (u32)r->CRm, (u32)r->Op2); > - u64 val = raz ? 0 : read_sanitised_ftr_reg(id); > + u64 val = raz ? 0 : __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)); > > if (id == SYS_ID_AA64PFR0_EL1) { > if (!vcpu_has_sve(vcpu)) > @@ -1265,7 +1268,7 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, > * are stored, and for set_id_reg() we don't allow the effective value > * to be changed. > */ > -static int __get_id_reg(const struct kvm_vcpu *vcpu, > +static int __get_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > bool raz) > { > @@ -1275,7 +1278,7 @@ static int __get_id_reg(const struct kvm_vcpu *vcpu, > return reg_to_user(uaddr, &val, id); > } > > -static int __set_id_reg(const struct kvm_vcpu *vcpu, > +static int __set_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > bool raz) > { > @@ -2854,3 +2857,25 @@ void kvm_sys_reg_table_init(void) > /* Clear all higher bits. */ > cache_levels &= (1 << (i*3))-1; > } > + > +static int get_cpu_ftr(u32 id, u64 val, void *argp) 'get' doesn't seem like the right verb here, but I don't think we need this function anyway, since we don't need arm64_cpu_ftr_regs_traverse(). Just put the for-loop for arm64_cpu_ftr_regs_traverse() and this code directly in kvm_arm_sys_reg_init(). > +{ > + struct kvm_vcpu *vcpu = argp; > + > + /* > + * (Op0, Op1, CRn, CRm, Op2) of ID registers is (3, 0, 0, crm, op2), > + * where 1<=crm<8, 0<=op2<8. > + */ > + if (sys_reg_Op0(id) == 3 && sys_reg_Op1(id) == 0 && > + sys_reg_CRn(id) == 0 && sys_reg_CRm(id) > 0 && > + sys_reg_CRm(id) < 8) { > + __vcpu_sys_reg(vcpu, ID_REG_INDEX(id)) = val; > + } > + > + return 0; > +} > + > +void kvm_arm_sys_reg_init(struct kvm_vcpu *vcpu) > +{ > + arm64_cpu_ftr_regs_traverse(get_cpu_ftr, vcpu); > +} > -- > 2.26.2 > Besides the pointless functions, this patch looks fine to me. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 4/7] kvm: arm64: introduce check_user 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:00 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will Currently, if we need to check the value of the register defined by user space, we should check it in set_user. However, some system registers may use the same set_user (for example, almost all ID registers), which make it difficult to validate the value defined by user space. Introduce check_user to solve the problem. And apply check_user before set_user to make sure that the value of register is valid. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 7 +++++++ arch/arm64/kvm/sys_regs.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 2b0fa8d5ac62..86ebb8093c3c 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg { const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; + int err; if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_set(reg->id, uaddr); @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (sysreg_hidden_from_user(vcpu, r)) return -ENOENT; + if (r->check_user) { + err = (r->check_user)(vcpu, r, reg, uaddr); + if (err) + return err; + } + if (r->set_user) return (r->set_user)(vcpu, r, reg, uaddr); diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 5a6fc30f5989..9bce5e9a3490 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -53,6 +53,12 @@ struct sys_reg_desc { const struct kvm_one_reg *reg, void __user *uaddr); int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr); + /* + * Check the value userspace passed. It should return 0 on success and + * otherwise on failure. + */ + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr); /* Return mask of REG_* runtime visibility overrides */ unsigned int (*visibility)(const struct kvm_vcpu *vcpu, -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 4/7] kvm: arm64: introduce check_user @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang Currently, if we need to check the value of the register defined by user space, we should check it in set_user. However, some system registers may use the same set_user (for example, almost all ID registers), which make it difficult to validate the value defined by user space. Introduce check_user to solve the problem. And apply check_user before set_user to make sure that the value of register is valid. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 7 +++++++ arch/arm64/kvm/sys_regs.h | 6 ++++++ 2 files changed, 13 insertions(+) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 2b0fa8d5ac62..86ebb8093c3c 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg { const struct sys_reg_desc *r; void __user *uaddr = (void __user *)(unsigned long)reg->addr; + int err; if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) return demux_c15_set(reg->id, uaddr); @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg if (sysreg_hidden_from_user(vcpu, r)) return -ENOENT; + if (r->check_user) { + err = (r->check_user)(vcpu, r, reg, uaddr); + if (err) + return err; + } + if (r->set_user) return (r->set_user)(vcpu, r, reg, uaddr); diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h index 5a6fc30f5989..9bce5e9a3490 100644 --- a/arch/arm64/kvm/sys_regs.h +++ b/arch/arm64/kvm/sys_regs.h @@ -53,6 +53,12 @@ struct sys_reg_desc { const struct kvm_one_reg *reg, void __user *uaddr); int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, const struct kvm_one_reg *reg, void __user *uaddr); + /* + * Check the value userspace passed. It should return 0 on success and + * otherwise on failure. + */ + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, void __user *uaddr); /* Return mask of REG_* runtime visibility overrides */ unsigned int (*visibility)(const struct kvm_vcpu *vcpu, -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 4/7] kvm: arm64: introduce check_user 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 7:41 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:41 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:58PM +0800, Peng Liang wrote: > Currently, if we need to check the value of the register defined by user > space, we should check it in set_user. However, some system registers > may use the same set_user (for example, almost all ID registers), which > make it difficult to validate the value defined by user space. If sharing set_user no longer makes sense for ID registers, then we need to rework the code so it's no longer shared. As I keep saying, we need to address this problem one ID register at a time. So, IMO, the approach should be to change one ID register at a time from using ID_SANITISED() to having its own table entry with its own set/get_user code. There may still be opportunity to share code among the ID registers, in which case refactoring can be done as needed too. Thanks, drew > > Introduce check_user to solve the problem. And apply check_user before > set_user to make sure that the value of register is valid. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 7 +++++++ > arch/arm64/kvm/sys_regs.h | 6 ++++++ > 2 files changed, 13 insertions(+) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 2b0fa8d5ac62..86ebb8093c3c 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > { > const struct sys_reg_desc *r; > void __user *uaddr = (void __user *)(unsigned long)reg->addr; > + int err; > > if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) > return demux_c15_set(reg->id, uaddr); > @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (sysreg_hidden_from_user(vcpu, r)) > return -ENOENT; > > + if (r->check_user) { > + err = (r->check_user)(vcpu, r, reg, uaddr); > + if (err) > + return err; > + } > + > if (r->set_user) > return (r->set_user)(vcpu, r, reg, uaddr); > > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h > index 5a6fc30f5989..9bce5e9a3490 100644 > --- a/arch/arm64/kvm/sys_regs.h > +++ b/arch/arm64/kvm/sys_regs.h > @@ -53,6 +53,12 @@ struct sys_reg_desc { > const struct kvm_one_reg *reg, void __user *uaddr); > int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > const struct kvm_one_reg *reg, void __user *uaddr); > + /* > + * Check the value userspace passed. It should return 0 on success and > + * otherwise on failure. > + */ > + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, void __user *uaddr); > > /* Return mask of REG_* runtime visibility overrides */ > unsigned int (*visibility)(const struct kvm_vcpu *vcpu, > -- > 2.26.2 > _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 4/7] kvm: arm64: introduce check_user @ 2020-09-18 7:41 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:41 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:58PM +0800, Peng Liang wrote: > Currently, if we need to check the value of the register defined by user > space, we should check it in set_user. However, some system registers > may use the same set_user (for example, almost all ID registers), which > make it difficult to validate the value defined by user space. If sharing set_user no longer makes sense for ID registers, then we need to rework the code so it's no longer shared. As I keep saying, we need to address this problem one ID register at a time. So, IMO, the approach should be to change one ID register at a time from using ID_SANITISED() to having its own table entry with its own set/get_user code. There may still be opportunity to share code among the ID registers, in which case refactoring can be done as needed too. Thanks, drew > > Introduce check_user to solve the problem. And apply check_user before > set_user to make sure that the value of register is valid. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 7 +++++++ > arch/arm64/kvm/sys_regs.h | 6 ++++++ > 2 files changed, 13 insertions(+) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 2b0fa8d5ac62..86ebb8093c3c 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > { > const struct sys_reg_desc *r; > void __user *uaddr = (void __user *)(unsigned long)reg->addr; > + int err; > > if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) > return demux_c15_set(reg->id, uaddr); > @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg > if (sysreg_hidden_from_user(vcpu, r)) > return -ENOENT; > > + if (r->check_user) { > + err = (r->check_user)(vcpu, r, reg, uaddr); > + if (err) > + return err; > + } > + > if (r->set_user) > return (r->set_user)(vcpu, r, reg, uaddr); > > diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h > index 5a6fc30f5989..9bce5e9a3490 100644 > --- a/arch/arm64/kvm/sys_regs.h > +++ b/arch/arm64/kvm/sys_regs.h > @@ -53,6 +53,12 @@ struct sys_reg_desc { > const struct kvm_one_reg *reg, void __user *uaddr); > int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > const struct kvm_one_reg *reg, void __user *uaddr); > + /* > + * Check the value userspace passed. It should return 0 on success and > + * otherwise on failure. > + */ > + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, void __user *uaddr); > > /* Return mask of REG_* runtime visibility overrides */ > unsigned int (*visibility)(const struct kvm_vcpu *vcpu, > -- > 2.26.2 > ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 4/7] kvm: arm64: introduce check_user 2020-09-18 7:41 ` Andrew Jones @ 2020-09-18 9:25 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:25 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:41 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:58PM +0800, Peng Liang wrote: >> Currently, if we need to check the value of the register defined by user >> space, we should check it in set_user. However, some system registers >> may use the same set_user (for example, almost all ID registers), which >> make it difficult to validate the value defined by user space. > > If sharing set_user no longer makes sense for ID registers, then we need > to rework the code so it's no longer shared. As I keep saying, we need > to address this problem one ID register at a time. So, IMO, the approach > should be to change one ID register at a time from using ID_SANITISED() > to having its own table entry with its own set/get_user code. There may > still be opportunity to share code among the ID registers, in which case > refactoring can be done as needed too. > > Thanks, > drew > Thank you for your advise. Currently, the implementation is a little dirty. Removing the shared set_user of ID registers should make it clean. I will refactor the code to make it in next version. Thanks, Peng >> >> Introduce check_user to solve the problem. And apply check_user before >> set_user to make sure that the value of register is valid. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 7 +++++++ >> arch/arm64/kvm/sys_regs.h | 6 ++++++ >> 2 files changed, 13 insertions(+) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index 2b0fa8d5ac62..86ebb8093c3c 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg >> { >> const struct sys_reg_desc *r; >> void __user *uaddr = (void __user *)(unsigned long)reg->addr; >> + int err; >> >> if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) >> return demux_c15_set(reg->id, uaddr); >> @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg >> if (sysreg_hidden_from_user(vcpu, r)) >> return -ENOENT; >> >> + if (r->check_user) { >> + err = (r->check_user)(vcpu, r, reg, uaddr); >> + if (err) >> + return err; >> + } >> + >> if (r->set_user) >> return (r->set_user)(vcpu, r, reg, uaddr); >> >> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h >> index 5a6fc30f5989..9bce5e9a3490 100644 >> --- a/arch/arm64/kvm/sys_regs.h >> +++ b/arch/arm64/kvm/sys_regs.h >> @@ -53,6 +53,12 @@ struct sys_reg_desc { >> const struct kvm_one_reg *reg, void __user *uaddr); >> int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> const struct kvm_one_reg *reg, void __user *uaddr); >> + /* >> + * Check the value userspace passed. It should return 0 on success and >> + * otherwise on failure. >> + */ >> + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, void __user *uaddr); >> >> /* Return mask of REG_* runtime visibility overrides */ >> unsigned int (*visibility)(const struct kvm_vcpu *vcpu, >> -- >> 2.26.2 >> > > . > _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 4/7] kvm: arm64: introduce check_user @ 2020-09-18 9:25 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:25 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:41 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:58PM +0800, Peng Liang wrote: >> Currently, if we need to check the value of the register defined by user >> space, we should check it in set_user. However, some system registers >> may use the same set_user (for example, almost all ID registers), which >> make it difficult to validate the value defined by user space. > > If sharing set_user no longer makes sense for ID registers, then we need > to rework the code so it's no longer shared. As I keep saying, we need > to address this problem one ID register at a time. So, IMO, the approach > should be to change one ID register at a time from using ID_SANITISED() > to having its own table entry with its own set/get_user code. There may > still be opportunity to share code among the ID registers, in which case > refactoring can be done as needed too. > > Thanks, > drew > Thank you for your advise. Currently, the implementation is a little dirty. Removing the shared set_user of ID registers should make it clean. I will refactor the code to make it in next version. Thanks, Peng >> >> Introduce check_user to solve the problem. And apply check_user before >> set_user to make sure that the value of register is valid. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 7 +++++++ >> arch/arm64/kvm/sys_regs.h | 6 ++++++ >> 2 files changed, 13 insertions(+) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index 2b0fa8d5ac62..86ebb8093c3c 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -2684,6 +2684,7 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg >> { >> const struct sys_reg_desc *r; >> void __user *uaddr = (void __user *)(unsigned long)reg->addr; >> + int err; >> >> if ((reg->id & KVM_REG_ARM_COPROC_MASK) == KVM_REG_ARM_DEMUX) >> return demux_c15_set(reg->id, uaddr); >> @@ -2699,6 +2700,12 @@ int kvm_arm_sys_reg_set_reg(struct kvm_vcpu *vcpu, const struct kvm_one_reg *reg >> if (sysreg_hidden_from_user(vcpu, r)) >> return -ENOENT; >> >> + if (r->check_user) { >> + err = (r->check_user)(vcpu, r, reg, uaddr); >> + if (err) >> + return err; >> + } >> + >> if (r->set_user) >> return (r->set_user)(vcpu, r, reg, uaddr); >> >> diff --git a/arch/arm64/kvm/sys_regs.h b/arch/arm64/kvm/sys_regs.h >> index 5a6fc30f5989..9bce5e9a3490 100644 >> --- a/arch/arm64/kvm/sys_regs.h >> +++ b/arch/arm64/kvm/sys_regs.h >> @@ -53,6 +53,12 @@ struct sys_reg_desc { >> const struct kvm_one_reg *reg, void __user *uaddr); >> int (*set_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> const struct kvm_one_reg *reg, void __user *uaddr); >> + /* >> + * Check the value userspace passed. It should return 0 on success and >> + * otherwise on failure. >> + */ >> + int (*check_user)(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, void __user *uaddr); >> >> /* Return mask of REG_* runtime visibility overrides */ >> unsigned int (*visibility)(const struct kvm_vcpu *vcpu, >> -- >> 2.26.2 >> > > . > ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 5/7] kvm: arm64: implement check_user for ID registers 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:00 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will For most ID registers, only neeed to check each field defined by user space is no more than that in host and only the fields we want to exposed to guest is set. For some ID registers, the relationship between some fields need to be check or we'd better to keep the same value as host for some fields. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- 1 file changed, 424 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 86ebb8093c3c..a642ecfebe0a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, return true; } +#define ID_CHECKER(reg) __check_ ##reg + +static int __general_id_checker(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + + return check_features(reg_id, val); +} + +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | + (0xfUL << ID_DFR0_COPDBG_SHIFT) | + (0xfUL << ID_DFR0_COPDBG_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int fphp, simdhp; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; +} + +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int fp, asimd; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); + return fp == asimd ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int sm3, sm4, sha1, sha2, sha3; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); + /* + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same + * value. + */ + if (sm3 != sm4) + return -EINVAL; + + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); + /* + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; + */ + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) + return -EINVAL; + + return 0; +} + +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int gpi, gpa, api, apa; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); + /* + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then + * ID_AA64ISAR1_EL1.GPI must have the value 0; + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then + * ID_AA64ISAR1_EL1.GPA must have the value 0; + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then + * ID_AA64ISAR1_EL1.API must have the value 0; + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then + * ID_AA64ISAR1_EL1.APA must have the value 0; + */ + if ((gpi && gpa) || (api && apa)) + return -EINVAL; + + return 0; +} + +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + unsigned int vmidbits, host_vmidbits; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); + host_val = read_sanitised_ftr_reg(reg_id); + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); + return vmidbits == host_vmidbits ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + /* sys_reg_desc initialiser for known cpufeature ID registers */ #define ID_SANITISED(name) { \ SYS_DESC(SYS_##name), \ .access = access_id_reg, \ .get_user = get_id_reg, \ .set_user = set_id_reg, \ + .check_user = ID_CHECKER(name), \ } /* @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_SANITISED(ID_AA64PFR1_EL1), ID_UNALLOCATED(4,2), ID_UNALLOCATED(4,3), - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, + .check_user = __general_id_checker, .visibility = sve_id_visibility }, ID_UNALLOCATED(4,5), ID_UNALLOCATED(4,6), ID_UNALLOCATED(4,7), -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 5/7] kvm: arm64: implement check_user for ID registers @ 2020-09-17 12:00 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:00 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang For most ID registers, only neeed to check each field defined by user space is no more than that in host and only the fields we want to exposed to guest is set. For some ID registers, the relationship between some fields need to be check or we'd better to keep the same value as host for some fields. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- 1 file changed, 424 insertions(+), 1 deletion(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index 86ebb8093c3c..a642ecfebe0a 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, return true; } +#define ID_CHECKER(reg) __check_ ##reg + +static int __general_id_checker(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + + return check_features(reg_id, val); +} + +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | + (0xfUL << ID_DFR0_COPDBG_SHIFT) | + (0xfUL << ID_DFR0_COPDBG_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int fphp, simdhp; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; +} + +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int fp, asimd; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); + return fp == asimd ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int sm3, sm4, sha1, sha2, sha3; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); + /* + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same + * value. + */ + if (sm3 != sm4) + return -EINVAL; + + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); + /* + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; + */ + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) + return -EINVAL; + + return 0; +} + +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val; + unsigned int gpi, gpa, api, apa; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); + /* + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then + * ID_AA64ISAR1_EL1.GPI must have the value 0; + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then + * ID_AA64ISAR1_EL1.GPA must have the value 0; + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then + * ID_AA64ISAR1_EL1.API must have the value 0; + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then + * ID_AA64ISAR1_EL1.APA must have the value 0; + */ + if ((gpi && gpa) || (api && apa)) + return -EINVAL; + + return 0; +} + +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + host_val = read_sanitised_ftr_reg(reg_id); + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + int err; + u64 val, host_val; + unsigned int vmidbits, host_vmidbits; + + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); + if (err) + return err; + err = check_features(reg_id, val); + if (err) + return err; + + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); + host_val = read_sanitised_ftr_reg(reg_id); + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); + return vmidbits == host_vmidbits ? 0 : -EINVAL; +} + +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, + const struct sys_reg_desc *rd, + const struct kvm_one_reg *reg, + void __user *uaddr) +{ + return __general_id_checker(vcpu, rd, reg, uaddr); +} + /* sys_reg_desc initialiser for known cpufeature ID registers */ #define ID_SANITISED(name) { \ SYS_DESC(SYS_##name), \ .access = access_id_reg, \ .get_user = get_id_reg, \ .set_user = set_id_reg, \ + .check_user = ID_CHECKER(name), \ } /* @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { ID_SANITISED(ID_AA64PFR1_EL1), ID_UNALLOCATED(4,2), ID_UNALLOCATED(4,3), - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, + .check_user = __general_id_checker, .visibility = sve_id_visibility }, ID_UNALLOCATED(4,5), ID_UNALLOCATED(4,6), ID_UNALLOCATED(4,7), -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 5/7] kvm: arm64: implement check_user for ID registers 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 7:46 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:46 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:59PM +0800, Peng Liang wrote: > For most ID registers, only neeed to check each field defined by user > space is no more than that in host and only the fields we want to > exposed to guest is set. For some ID registers, the relationship > between some fields need to be check or we'd better to keep the same > value as host for some fields. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 424 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 86ebb8093c3c..a642ecfebe0a 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, > return true; > } > > +#define ID_CHECKER(reg) __check_ ##reg > + > +static int __general_id_checker(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + > + return check_features(reg_id, val); > +} > + > +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | > + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | > + (0xfUL << ID_DFR0_COPDBG_SHIFT) | > + (0xfUL << ID_DFR0_COPDBG_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} There has to be a better way to handle all these redundant functions... > + > +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int fphp, simdhp; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); > + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); > + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || > + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int fp, asimd; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); > + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); > + return fp == asimd ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | > + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | > + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | > + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | > + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int sm3, sm4, sha1, sha2, sha3; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); > + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); > + /* > + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same > + * value. > + */ > + if (sm3 != sm4) > + return -EINVAL; > + > + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); > + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); > + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); > + /* > + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then > + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; > + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then > + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; > + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then > + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; > + */ > + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) > + return -EINVAL; > + > + return 0; > +} > + > +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int gpi, gpa, api, apa; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); > + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); > + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); > + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); > + /* > + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then > + * ID_AA64ISAR1_EL1.GPI must have the value 0; > + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then > + * ID_AA64ISAR1_EL1.GPA must have the value 0; > + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then > + * ID_AA64ISAR1_EL1.API must have the value 0; > + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then > + * ID_AA64ISAR1_EL1.APA must have the value 0; > + */ > + if ((gpi && gpa) || (api && apa)) > + return -EINVAL; > + > + return 0; > +} > + > +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | > + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | > + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + unsigned int vmidbits, host_vmidbits; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); > + host_val = read_sanitised_ftr_reg(reg_id); > + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); > + return vmidbits == host_vmidbits ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > /* sys_reg_desc initialiser for known cpufeature ID registers */ > #define ID_SANITISED(name) { \ > SYS_DESC(SYS_##name), \ > .access = access_id_reg, \ > .get_user = get_id_reg, \ > .set_user = set_id_reg, \ > + .check_user = ID_CHECKER(name), \ This patch makes it clear that continuing to use ID_SANITISED() for all ID registers makes no sense. > } > > /* > @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { > ID_SANITISED(ID_AA64PFR1_EL1), > ID_UNALLOCATED(4,2), > ID_UNALLOCATED(4,3), > - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, > + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, > + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, > + .check_user = __general_id_checker, .visibility = sve_id_visibility }, > ID_UNALLOCATED(4,5), > ID_UNALLOCATED(4,6), > ID_UNALLOCATED(4,7), > -- > 2.26.2 > Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 5/7] kvm: arm64: implement check_user for ID registers @ 2020-09-18 7:46 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:46 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:59PM +0800, Peng Liang wrote: > For most ID registers, only neeed to check each field defined by user > space is no more than that in host and only the fields we want to > exposed to guest is set. For some ID registers, the relationship > between some fields need to be check or we'd better to keep the same > value as host for some fields. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- > 1 file changed, 424 insertions(+), 1 deletion(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index 86ebb8093c3c..a642ecfebe0a 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, > return true; > } > > +#define ID_CHECKER(reg) __check_ ##reg > + > +static int __general_id_checker(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + > + return check_features(reg_id, val); > +} > + > +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | > + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | > + (0xfUL << ID_DFR0_COPDBG_SHIFT) | > + (0xfUL << ID_DFR0_COPDBG_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} There has to be a better way to handle all these redundant functions... > + > +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int fphp, simdhp; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); > + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); > + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || > + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int fp, asimd; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); > + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); > + return fp == asimd ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | > + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | > + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | > + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | > + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int sm3, sm4, sha1, sha2, sha3; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); > + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); > + /* > + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same > + * value. > + */ > + if (sm3 != sm4) > + return -EINVAL; > + > + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); > + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); > + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); > + /* > + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then > + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; > + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then > + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; > + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then > + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; > + */ > + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) > + return -EINVAL; > + > + return 0; > +} > + > +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val; > + unsigned int gpi, gpa, api, apa; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); > + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); > + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); > + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); > + /* > + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then > + * ID_AA64ISAR1_EL1.GPI must have the value 0; > + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then > + * ID_AA64ISAR1_EL1.GPA must have the value 0; > + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then > + * ID_AA64ISAR1_EL1.API must have the value 0; > + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then > + * ID_AA64ISAR1_EL1.APA must have the value 0; > + */ > + if ((gpi && gpa) || (api && apa)) > + return -EINVAL; > + > + return 0; > +} > + > +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | > + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | > + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | > + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + host_val = read_sanitised_ftr_reg(reg_id); > + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + int err; > + u64 val, host_val; > + unsigned int vmidbits, host_vmidbits; > + > + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); > + if (err) > + return err; > + err = check_features(reg_id, val); > + if (err) > + return err; > + > + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); > + host_val = read_sanitised_ftr_reg(reg_id); > + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); > + return vmidbits == host_vmidbits ? 0 : -EINVAL; > +} > + > +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, > + const struct sys_reg_desc *rd, > + const struct kvm_one_reg *reg, > + void __user *uaddr) > +{ > + return __general_id_checker(vcpu, rd, reg, uaddr); > +} > + > /* sys_reg_desc initialiser for known cpufeature ID registers */ > #define ID_SANITISED(name) { \ > SYS_DESC(SYS_##name), \ > .access = access_id_reg, \ > .get_user = get_id_reg, \ > .set_user = set_id_reg, \ > + .check_user = ID_CHECKER(name), \ This patch makes it clear that continuing to use ID_SANITISED() for all ID registers makes no sense. > } > > /* > @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { > ID_SANITISED(ID_AA64PFR1_EL1), > ID_UNALLOCATED(4,2), > ID_UNALLOCATED(4,3), > - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, > + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, > + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, > + .check_user = __general_id_checker, .visibility = sve_id_visibility }, > ID_UNALLOCATED(4,5), > ID_UNALLOCATED(4,6), > ID_UNALLOCATED(4,7), > -- > 2.26.2 > Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 5/7] kvm: arm64: implement check_user for ID registers 2020-09-18 7:46 ` Andrew Jones @ 2020-09-18 9:26 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:46 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:59PM +0800, Peng Liang wrote: >> For most ID registers, only neeed to check each field defined by user >> space is no more than that in host and only the fields we want to >> exposed to guest is set. For some ID registers, the relationship >> between some fields need to be check or we'd better to keep the same >> value as host for some fields. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- >> 1 file changed, 424 insertions(+), 1 deletion(-) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index 86ebb8093c3c..a642ecfebe0a 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, >> return true; >> } >> >> +#define ID_CHECKER(reg) __check_ ##reg >> + >> +static int __general_id_checker(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + >> + return check_features(reg_id, val); >> +} >> + >> +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | >> + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | >> + (0xfUL << ID_DFR0_COPDBG_SHIFT) | >> + (0xfUL << ID_DFR0_COPDBG_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} > > There has to be a better way to handle all these redundant functions... > >> + >> +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int fphp, simdhp; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); >> + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); >> + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || >> + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int fp, asimd; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); >> + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); >> + return fp == asimd ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | >> + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | >> + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | >> + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | >> + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int sm3, sm4, sha1, sha2, sha3; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); >> + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); >> + /* >> + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same >> + * value. >> + */ >> + if (sm3 != sm4) >> + return -EINVAL; >> + >> + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); >> + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); >> + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); >> + /* >> + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then >> + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; >> + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then >> + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; >> + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then >> + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; >> + */ >> + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int gpi, gpa, api, apa; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); >> + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); >> + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); >> + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); >> + /* >> + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then >> + * ID_AA64ISAR1_EL1.GPI must have the value 0; >> + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then >> + * ID_AA64ISAR1_EL1.GPA must have the value 0; >> + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then >> + * ID_AA64ISAR1_EL1.API must have the value 0; >> + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then >> + * ID_AA64ISAR1_EL1.APA must have the value 0; >> + */ >> + if ((gpi && gpa) || (api && apa)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + unsigned int vmidbits, host_vmidbits; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); >> + host_val = read_sanitised_ftr_reg(reg_id); >> + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); >> + return vmidbits == host_vmidbits ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> /* sys_reg_desc initialiser for known cpufeature ID registers */ >> #define ID_SANITISED(name) { \ >> SYS_DESC(SYS_##name), \ >> .access = access_id_reg, \ >> .get_user = get_id_reg, \ >> .set_user = set_id_reg, \ >> + .check_user = ID_CHECKER(name), \ > > This patch makes it clear that continuing to use ID_SANITISED() for all ID > registers makes no sense. > >> } >> >> /* >> @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { >> ID_SANITISED(ID_AA64PFR1_EL1), >> ID_UNALLOCATED(4,2), >> ID_UNALLOCATED(4,3), >> - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, >> + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, >> + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, >> + .check_user = __general_id_checker, .visibility = sve_id_visibility }, >> ID_UNALLOCATED(4,5), >> ID_UNALLOCATED(4,6), >> ID_UNALLOCATED(4,7), >> -- >> 2.26.2 >> > > Thanks, > drew > > . > I also think this patch is a little ugly. I will refactor the code to remove the sharing set_user of ID registers in next version. Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 5/7] kvm: arm64: implement check_user for ID registers @ 2020-09-18 9:26 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:46 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:59PM +0800, Peng Liang wrote: >> For most ID registers, only neeed to check each field defined by user >> space is no more than that in host and only the fields we want to >> exposed to guest is set. For some ID registers, the relationship >> between some fields need to be check or we'd better to keep the same >> value as host for some fields. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 425 +++++++++++++++++++++++++++++++++++++- >> 1 file changed, 424 insertions(+), 1 deletion(-) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index 86ebb8093c3c..a642ecfebe0a 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -1385,12 +1385,433 @@ static bool access_ccsidr(struct kvm_vcpu *vcpu, struct sys_reg_params *p, >> return true; >> } >> >> +#define ID_CHECKER(reg) __check_ ##reg >> + >> +static int __general_id_checker(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + >> + return check_features(reg_id, val); >> +} >> + >> +static int ID_CHECKER(ID_PFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_PFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_PFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_DFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_DFR0_PERFMON_SHIFT) | >> + (0xfUL << ID_DFR0_MMAPDBG_SHIFT) | >> + (0xfUL << ID_DFR0_COPDBG_SHIFT) | >> + (0xfUL << ID_DFR0_COPDBG_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_MMFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR3_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR4_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_MMFR5_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR3_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR4_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR5_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_ISAR6_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(MVFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} > > There has to be a better way to handle all these redundant functions... > >> + >> +static int ID_CHECKER(MVFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int fphp, simdhp; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + fphp = cpuid_feature_extract_signed_field(val, MVFR1_FPHP_SHIFT); >> + simdhp = cpuid_feature_extract_signed_field(val, MVFR1_SIMDHP_SHIFT); >> + return ((fphp == 0 && simdhp == 0) || (fphp == 2 && simdhp == 1) || >> + (fphp == 3 && simdhp == 2)) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(MVFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64PFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int fp, asimd; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + fp = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_FP_SHIFT); >> + asimd = cpuid_feature_extract_signed_field(val, ID_AA64PFR0_ASIMD_SHIFT); >> + return fp == asimd ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64PFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64DFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_AA64DFR0_PMUVER_SHIFT) | >> + (0xfUL << ID_AA64DFR0_DEBUGVER_SHIFT) | >> + (0xfUL << ID_AA64DFR0_CTX_CMPS_SHIFT) | >> + (0xfUL << ID_AA64DFR0_WRPS_SHIFT) | >> + (0xfUL << ID_AA64DFR0_BRPS_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64DFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> +static int ID_CHECKER(ID_AA64ISAR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int sm3, sm4, sha1, sha2, sha3; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + sm3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM3_SHIFT); >> + sm4 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SM4_SHIFT); >> + /* >> + * ID_AA64ISAR0_EL1.SM3 and ID_AA64ISAR0_EL1.SM4 must have the same >> + * value. >> + */ >> + if (sm3 != sm4) >> + return -EINVAL; >> + >> + sha1 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA1_SHIFT); >> + sha2 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA2_SHIFT); >> + sha3 = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR0_SHA3_SHIFT); >> + /* >> + * 1. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then >> + * ID_AA64ISAR0_EL1.SHA2 must have the value 0, and vice versa; >> + * 2. If the value of ID_AA64ISAR0_EL1.SHA2 is 2, then >> + * ID_AA64ISAR0_EL1.SHA3 must have the value 1, and vice versa; >> + * 3. If the value of ID_AA64ISAR0_EL1.SHA1 is 0, then >> + * ID_AA64ISAR0_EL1.SHA3 must have the value 0; >> + */ >> + if ((sha1 ^ sha2) || ((sha2 == 2) ^ (sha3 == 1)) || (!sha1 && sha3)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> +static int ID_CHECKER(ID_AA64ISAR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val; >> + unsigned int gpi, gpa, api, apa; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + gpi = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPI_SHIFT); >> + gpa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_GPA_SHIFT); >> + api = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_API_SHIFT); >> + apa = cpuid_feature_extract_unsigned_field(val, ID_AA64ISAR1_APA_SHIFT); >> + /* >> + * 1. If the value of ID_AA64ISAR1_EL1.GPA is non-zero, then >> + * ID_AA64ISAR1_EL1.GPI must have the value 0; >> + * 2. If the value of ID_AA64ISAR1_EL1.GPI is non-zero, then >> + * ID_AA64ISAR1_EL1.GPA must have the value 0; >> + * 3. If the value of ID_AA64ISAR1_EL1.APA is non-zero, then >> + * ID_AA64ISAR1_EL1.API must have the value 0; >> + * 4. If the value of ID_AA64ISAR1_EL1.API is non-zero, then >> + * ID_AA64ISAR1_EL1.APA must have the value 0; >> + */ >> + if ((gpi && gpa) || (api && apa)) >> + return -EINVAL; >> + >> + return 0; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR0_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + u64 mask = ((0xfUL << ID_AA64MMFR0_TGRAN4_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN64_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN16_2_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN4_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN64_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_TGRAN16_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_ASID_SHIFT) | >> + (0xfUL << ID_AA64MMFR0_PARANGE_SHIFT)); >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + host_val = read_sanitised_ftr_reg(reg_id); >> + return (val & mask) == (host_val & mask) ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR1_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + int err; >> + u64 val, host_val; >> + unsigned int vmidbits, host_vmidbits; >> + >> + err = reg_from_user(&val, uaddr, sys_reg_to_index(rd)); >> + if (err) >> + return err; >> + err = check_features(reg_id, val); >> + if (err) >> + return err; >> + >> + vmidbits = cpuid_feature_extract_unsigned_field(val, ID_AA64MMFR1_VMIDBITS_SHIFT); >> + host_val = read_sanitised_ftr_reg(reg_id); >> + host_vmidbits = cpuid_feature_extract_signed_field(host_val, ID_AA64MMFR1_VMIDBITS_SHIFT); >> + return vmidbits == host_vmidbits ? 0 : -EINVAL; >> +} >> + >> +static int ID_CHECKER(ID_AA64MMFR2_EL1)(struct kvm_vcpu *vcpu, >> + const struct sys_reg_desc *rd, >> + const struct kvm_one_reg *reg, >> + void __user *uaddr) >> +{ >> + return __general_id_checker(vcpu, rd, reg, uaddr); >> +} >> + >> /* sys_reg_desc initialiser for known cpufeature ID registers */ >> #define ID_SANITISED(name) { \ >> SYS_DESC(SYS_##name), \ >> .access = access_id_reg, \ >> .get_user = get_id_reg, \ >> .set_user = set_id_reg, \ >> + .check_user = ID_CHECKER(name), \ > > This patch makes it clear that continuing to use ID_SANITISED() for all ID > registers makes no sense. > >> } >> >> /* >> @@ -1512,7 +1933,9 @@ static const struct sys_reg_desc sys_reg_descs[] = { >> ID_SANITISED(ID_AA64PFR1_EL1), >> ID_UNALLOCATED(4,2), >> ID_UNALLOCATED(4,3), >> - { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, .visibility = sve_id_visibility }, >> + { SYS_DESC(SYS_ID_AA64ZFR0_EL1), access_id_aa64zfr0_el1, >> + .get_user = get_id_aa64zfr0_el1, .set_user = set_id_aa64zfr0_el1, >> + .check_user = __general_id_checker, .visibility = sve_id_visibility }, >> ID_UNALLOCATED(4,5), >> ID_UNALLOCATED(4,6), >> ID_UNALLOCATED(4,7), >> -- >> 2.26.2 >> > > Thanks, > drew > > . > I also think this patch is a little ugly. I will refactor the code to remove the sharing set_user of ID registers in next version. Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 6/7] kvm: arm64: make ID registers configurable 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:01 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:01 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will It's time to make ID registers configurable. When userspace (but not guest) want to set the values of ID registers, save the value in sysreg file so that guest can read the modified values. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a642ecfebe0a..881b66494524 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, /* * cpufeature ID register user accessors - * - * For now, these registers are immutable for userspace, so no values - * are stored, and for set_id_reg() we don't allow the effective value - * to be changed. */ static int __get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, if (err) return err; - /* This is what we mean by invariant: you can't change it. */ - if (val != read_id_reg(vcpu, rd, raz)) - return -EINVAL; + if (raz) { + if (val != read_id_reg(vcpu, rd, raz)) + return -EINVAL; + } else { + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + /* val should be checked in check_user */ + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; + } return 0; } -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 6/7] kvm: arm64: make ID registers configurable @ 2020-09-17 12:01 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:01 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang It's time to make ID registers configurable. When userspace (but not guest) want to set the values of ID registers, save the value in sysreg file so that guest can read the modified values. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- arch/arm64/kvm/sys_regs.c | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c index a642ecfebe0a..881b66494524 100644 --- a/arch/arm64/kvm/sys_regs.c +++ b/arch/arm64/kvm/sys_regs.c @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, /* * cpufeature ID register user accessors - * - * For now, these registers are immutable for userspace, so no values - * are stored, and for set_id_reg() we don't allow the effective value - * to be changed. */ static int __get_id_reg(struct kvm_vcpu *vcpu, const struct sys_reg_desc *rd, void __user *uaddr, @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, if (err) return err; - /* This is what we mean by invariant: you can't change it. */ - if (val != read_id_reg(vcpu, rd, raz)) - return -EINVAL; + if (raz) { + if (val != read_id_reg(vcpu, rd, raz)) + return -EINVAL; + } else { + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, + (u32)rd->CRm, (u32)rd->Op2); + /* val should be checked in check_user */ + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; + } return 0; } -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 6/7] kvm: arm64: make ID registers configurable 2020-09-17 12:01 ` Peng Liang @ 2020-09-18 7:50 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:50 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:01:00PM +0800, Peng Liang wrote: > It's time to make ID registers configurable. When userspace (but not > guest) want to set the values of ID registers, save the value in > sysreg file so that guest can read the modified values. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 16 +++++++++------- > 1 file changed, 9 insertions(+), 7 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index a642ecfebe0a..881b66494524 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, > > /* > * cpufeature ID register user accessors > - * > - * For now, these registers are immutable for userspace, so no values > - * are stored, and for set_id_reg() we don't allow the effective value > - * to be changed. > */ > static int __get_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, > if (err) > return err; > > - /* This is what we mean by invariant: you can't change it. */ > - if (val != read_id_reg(vcpu, rd, raz)) > - return -EINVAL; > + if (raz) { > + if (val != read_id_reg(vcpu, rd, raz)) val != 0 ? > + return -EINVAL; > + } else { > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + /* val should be checked in check_user */ It really doesn't make sense to share this trivial set_user function and have different check functions. Just don't share the set_user function. > + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; > + } > > return 0; > } > -- > 2.26.2 > Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 6/7] kvm: arm64: make ID registers configurable @ 2020-09-18 7:50 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:50 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:01:00PM +0800, Peng Liang wrote: > It's time to make ID registers configurable. When userspace (but not > guest) want to set the values of ID registers, save the value in > sysreg file so that guest can read the modified values. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > arch/arm64/kvm/sys_regs.c | 16 +++++++++------- > 1 file changed, 9 insertions(+), 7 deletions(-) > > diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c > index a642ecfebe0a..881b66494524 100644 > --- a/arch/arm64/kvm/sys_regs.c > +++ b/arch/arm64/kvm/sys_regs.c > @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, > > /* > * cpufeature ID register user accessors > - * > - * For now, these registers are immutable for userspace, so no values > - * are stored, and for set_id_reg() we don't allow the effective value > - * to be changed. > */ > static int __get_id_reg(struct kvm_vcpu *vcpu, > const struct sys_reg_desc *rd, void __user *uaddr, > @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, > if (err) > return err; > > - /* This is what we mean by invariant: you can't change it. */ > - if (val != read_id_reg(vcpu, rd, raz)) > - return -EINVAL; > + if (raz) { > + if (val != read_id_reg(vcpu, rd, raz)) val != 0 ? > + return -EINVAL; > + } else { > + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, > + (u32)rd->CRm, (u32)rd->Op2); > + /* val should be checked in check_user */ It really doesn't make sense to share this trivial set_user function and have different check functions. Just don't share the set_user function. > + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; > + } > > return 0; > } > -- > 2.26.2 > Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 6/7] kvm: arm64: make ID registers configurable 2020-09-18 7:50 ` Andrew Jones @ 2020-09-18 9:26 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:50 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:01:00PM +0800, Peng Liang wrote: >> It's time to make ID registers configurable. When userspace (but not >> guest) want to set the values of ID registers, save the value in >> sysreg file so that guest can read the modified values. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 16 +++++++++------- >> 1 file changed, 9 insertions(+), 7 deletions(-) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index a642ecfebe0a..881b66494524 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, >> >> /* >> * cpufeature ID register user accessors >> - * >> - * For now, these registers are immutable for userspace, so no values >> - * are stored, and for set_id_reg() we don't allow the effective value >> - * to be changed. >> */ >> static int __get_id_reg(struct kvm_vcpu *vcpu, >> const struct sys_reg_desc *rd, void __user *uaddr, >> @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, >> if (err) >> return err; >> >> - /* This is what we mean by invariant: you can't change it. */ >> - if (val != read_id_reg(vcpu, rd, raz)) >> - return -EINVAL; >> + if (raz) { >> + if (val != read_id_reg(vcpu, rd, raz)) > > val != 0 ? Thanks for you advise. It will make it much clearer. I'll change it in next version. Thanks, Peng > >> + return -EINVAL; >> + } else { >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + /* val should be checked in check_user */ > > It really doesn't make sense to share this trivial set_user function and > have different check functions. Just don't share the set_user function. > >> + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; >> + } >> >> return 0; >> } >> -- >> 2.26.2 >> > > Thanks, > drew > > . > _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 6/7] kvm: arm64: make ID registers configurable @ 2020-09-18 9:26 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:50 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:01:00PM +0800, Peng Liang wrote: >> It's time to make ID registers configurable. When userspace (but not >> guest) want to set the values of ID registers, save the value in >> sysreg file so that guest can read the modified values. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> arch/arm64/kvm/sys_regs.c | 16 +++++++++------- >> 1 file changed, 9 insertions(+), 7 deletions(-) >> >> diff --git a/arch/arm64/kvm/sys_regs.c b/arch/arm64/kvm/sys_regs.c >> index a642ecfebe0a..881b66494524 100644 >> --- a/arch/arm64/kvm/sys_regs.c >> +++ b/arch/arm64/kvm/sys_regs.c >> @@ -1263,10 +1263,6 @@ static int set_id_aa64zfr0_el1(struct kvm_vcpu *vcpu, >> >> /* >> * cpufeature ID register user accessors >> - * >> - * For now, these registers are immutable for userspace, so no values >> - * are stored, and for set_id_reg() we don't allow the effective value >> - * to be changed. >> */ >> static int __get_id_reg(struct kvm_vcpu *vcpu, >> const struct sys_reg_desc *rd, void __user *uaddr, >> @@ -1290,9 +1286,15 @@ static int __set_id_reg(struct kvm_vcpu *vcpu, >> if (err) >> return err; >> >> - /* This is what we mean by invariant: you can't change it. */ >> - if (val != read_id_reg(vcpu, rd, raz)) >> - return -EINVAL; >> + if (raz) { >> + if (val != read_id_reg(vcpu, rd, raz)) > > val != 0 ? Thanks for you advise. It will make it much clearer. I'll change it in next version. Thanks, Peng > >> + return -EINVAL; >> + } else { >> + u32 reg_id = sys_reg((u32)rd->Op0, (u32)rd->Op1, (u32)rd->CRn, >> + (u32)rd->CRm, (u32)rd->Op2); >> + /* val should be checked in check_user */ > > It really doesn't make sense to share this trivial set_user function and > have different check functions. Just don't share the set_user function. > >> + __vcpu_sys_reg(vcpu, ID_REG_INDEX(reg_id)) = val; >> + } >> >> return 0; >> } >> -- >> 2.26.2 >> > > Thanks, > drew > > . > ^ permalink raw reply [flat|nested] 52+ messages in thread
* [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension 2020-09-17 12:00 ` Peng Liang @ 2020-09-17 12:01 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:01 UTC (permalink / raw) To: kvmarm; +Cc: zhang.zhanghailiang, kvm, maz, will Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM supports to set CPU features in AArch64. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- Documentation/virt/kvm/api.rst | 8 ++++++++ arch/arm64/kvm/arm.c | 1 + include/uapi/linux/kvm.h | 1 + 3 files changed, 10 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index d2b733dc7892..50214ed8f50e 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature is supported, than the other should as well and vice versa. For arm64 see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". + +8.25 KVM_CAP_ARM_CPU_FEATURE +----------------------------------- + +:Architecture: arm64 + +This capability indicates that userspace can modify the ID registers via +KVM_SET_ONE_REG ioctl. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 6d961e192268..918a7a56b224 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: case KVM_CAP_ARM_NISV_TO_USER: case KVM_CAP_ARM_INJECT_EXT_DABT: + case KVM_CAP_ARM_CPU_FEATURE: r = 1; break; case KVM_CAP_ARM_SET_DEVICE_ADDR: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7d8eced6f459..12356beadd5a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SMALLER_MAXPHYADDR 185 #define KVM_CAP_S390_DIAG318 186 #define KVM_CAP_STEAL_TIME 187 +#define KVM_CAP_ARM_CPU_FEATURE 188 #ifdef KVM_CAP_IRQ_ROUTING -- 2.26.2 _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply related [flat|nested] 52+ messages in thread
* [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension @ 2020-09-17 12:01 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-17 12:01 UTC (permalink / raw) To: kvmarm Cc: kvm, maz, will, drjones, zhang.zhanghailiang, xiexiangyou, Peng Liang Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM supports to set CPU features in AArch64. Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> Signed-off-by: Peng Liang <liangpeng10@huawei.com> --- Documentation/virt/kvm/api.rst | 8 ++++++++ arch/arm64/kvm/arm.c | 1 + include/uapi/linux/kvm.h | 1 + 3 files changed, 10 insertions(+) diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst index d2b733dc7892..50214ed8f50e 100644 --- a/Documentation/virt/kvm/api.rst +++ b/Documentation/virt/kvm/api.rst @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature is supported, than the other should as well and vice versa. For arm64 see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". + +8.25 KVM_CAP_ARM_CPU_FEATURE +----------------------------------- + +:Architecture: arm64 + +This capability indicates that userspace can modify the ID registers via +KVM_SET_ONE_REG ioctl. diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c index 6d961e192268..918a7a56b224 100644 --- a/arch/arm64/kvm/arm.c +++ b/arch/arm64/kvm/arm.c @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: case KVM_CAP_ARM_NISV_TO_USER: case KVM_CAP_ARM_INJECT_EXT_DABT: + case KVM_CAP_ARM_CPU_FEATURE: r = 1; break; case KVM_CAP_ARM_SET_DEVICE_ADDR: diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h index 7d8eced6f459..12356beadd5a 100644 --- a/include/uapi/linux/kvm.h +++ b/include/uapi/linux/kvm.h @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { #define KVM_CAP_SMALLER_MAXPHYADDR 185 #define KVM_CAP_S390_DIAG318 186 #define KVM_CAP_STEAL_TIME 187 +#define KVM_CAP_ARM_CPU_FEATURE 188 #ifdef KVM_CAP_IRQ_ROUTING -- 2.26.2 ^ permalink raw reply related [flat|nested] 52+ messages in thread
* Re: [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension 2020-09-17 12:01 ` Peng Liang @ 2020-09-18 7:55 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:55 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:01:01PM +0800, Peng Liang wrote: > Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM > supports to set CPU features in AArch64. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > Documentation/virt/kvm/api.rst | 8 ++++++++ > arch/arm64/kvm/arm.c | 1 + > include/uapi/linux/kvm.h | 1 + > 3 files changed, 10 insertions(+) > > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst > index d2b733dc7892..50214ed8f50e 100644 > --- a/Documentation/virt/kvm/api.rst > +++ b/Documentation/virt/kvm/api.rst > @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature > is supported, than the other should as well and vice versa. For arm64 > see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". > For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". > + > +8.25 KVM_CAP_ARM_CPU_FEATURE > +----------------------------------- Too many '----' > + > +:Architecture: arm64 > + > +This capability indicates that userspace can modify the ID registers via > +KVM_SET_ONE_REG ioctl. You should say something like "See KVM_SET_ONE_REG:ARM64 ID Registers" here and also extend the "KVM_SET_ONE_REG" section with a "ARM64 ID Register" section that describes the limits and return values. > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c > index 6d961e192268..918a7a56b224 100644 > --- a/arch/arm64/kvm/arm.c > +++ b/arch/arm64/kvm/arm.c > @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) > case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: > case KVM_CAP_ARM_NISV_TO_USER: > case KVM_CAP_ARM_INJECT_EXT_DABT: > + case KVM_CAP_ARM_CPU_FEATURE: > r = 1; > break; > case KVM_CAP_ARM_SET_DEVICE_ADDR: > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 7d8eced6f459..12356beadd5a 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { > #define KVM_CAP_SMALLER_MAXPHYADDR 185 > #define KVM_CAP_S390_DIAG318 186 > #define KVM_CAP_STEAL_TIME 187 > +#define KVM_CAP_ARM_CPU_FEATURE 188 > > #ifdef KVM_CAP_IRQ_ROUTING > > -- > 2.26.2 > Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension @ 2020-09-18 7:55 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 7:55 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:01:01PM +0800, Peng Liang wrote: > Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM > supports to set CPU features in AArch64. > > Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> > Signed-off-by: Peng Liang <liangpeng10@huawei.com> > --- > Documentation/virt/kvm/api.rst | 8 ++++++++ > arch/arm64/kvm/arm.c | 1 + > include/uapi/linux/kvm.h | 1 + > 3 files changed, 10 insertions(+) > > diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst > index d2b733dc7892..50214ed8f50e 100644 > --- a/Documentation/virt/kvm/api.rst > +++ b/Documentation/virt/kvm/api.rst > @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature > is supported, than the other should as well and vice versa. For arm64 > see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". > For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". > + > +8.25 KVM_CAP_ARM_CPU_FEATURE > +----------------------------------- Too many '----' > + > +:Architecture: arm64 > + > +This capability indicates that userspace can modify the ID registers via > +KVM_SET_ONE_REG ioctl. You should say something like "See KVM_SET_ONE_REG:ARM64 ID Registers" here and also extend the "KVM_SET_ONE_REG" section with a "ARM64 ID Register" section that describes the limits and return values. > diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c > index 6d961e192268..918a7a56b224 100644 > --- a/arch/arm64/kvm/arm.c > +++ b/arch/arm64/kvm/arm.c > @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) > case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: > case KVM_CAP_ARM_NISV_TO_USER: > case KVM_CAP_ARM_INJECT_EXT_DABT: > + case KVM_CAP_ARM_CPU_FEATURE: > r = 1; > break; > case KVM_CAP_ARM_SET_DEVICE_ADDR: > diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h > index 7d8eced6f459..12356beadd5a 100644 > --- a/include/uapi/linux/kvm.h > +++ b/include/uapi/linux/kvm.h > @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { > #define KVM_CAP_SMALLER_MAXPHYADDR 185 > #define KVM_CAP_S390_DIAG318 186 > #define KVM_CAP_STEAL_TIME 187 > +#define KVM_CAP_ARM_CPU_FEATURE 188 > > #ifdef KVM_CAP_IRQ_ROUTING > > -- > 2.26.2 > Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension 2020-09-18 7:55 ` Andrew Jones @ 2020-09-18 9:26 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 3:55 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:01:01PM +0800, Peng Liang wrote: >> Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM >> supports to set CPU features in AArch64. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> Documentation/virt/kvm/api.rst | 8 ++++++++ >> arch/arm64/kvm/arm.c | 1 + >> include/uapi/linux/kvm.h | 1 + >> 3 files changed, 10 insertions(+) >> >> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst >> index d2b733dc7892..50214ed8f50e 100644 >> --- a/Documentation/virt/kvm/api.rst >> +++ b/Documentation/virt/kvm/api.rst >> @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature >> is supported, than the other should as well and vice versa. For arm64 >> see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". >> For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". >> + >> +8.25 KVM_CAP_ARM_CPU_FEATURE >> +----------------------------------- > > Too many '----' > >> + >> +:Architecture: arm64 >> + >> +This capability indicates that userspace can modify the ID registers via >> +KVM_SET_ONE_REG ioctl. > > You should say something like "See KVM_SET_ONE_REG:ARM64 ID Registers" > here and also extend the "KVM_SET_ONE_REG" section with a "ARM64 ID > Register" section that describes the limits and return values. > >> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c >> index 6d961e192268..918a7a56b224 100644 >> --- a/arch/arm64/kvm/arm.c >> +++ b/arch/arm64/kvm/arm.c >> @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) >> case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: >> case KVM_CAP_ARM_NISV_TO_USER: >> case KVM_CAP_ARM_INJECT_EXT_DABT: >> + case KVM_CAP_ARM_CPU_FEATURE: >> r = 1; >> break; >> case KVM_CAP_ARM_SET_DEVICE_ADDR: >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h >> index 7d8eced6f459..12356beadd5a 100644 >> --- a/include/uapi/linux/kvm.h >> +++ b/include/uapi/linux/kvm.h >> @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { >> #define KVM_CAP_SMALLER_MAXPHYADDR 185 >> #define KVM_CAP_S390_DIAG318 186 >> #define KVM_CAP_STEAL_TIME 187 >> +#define KVM_CAP_ARM_CPU_FEATURE 188 >> >> #ifdef KVM_CAP_IRQ_ROUTING >> >> -- >> 2.26.2 >> > > Thanks, > drew > > . > Thank you for your advise. I'll change them in next version. Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension @ 2020-09-18 9:26 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:26 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 3:55 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:01:01PM +0800, Peng Liang wrote: >> Add KVM_CAP_ARM_CPU_FEATURE extension for userpace to check whether KVM >> supports to set CPU features in AArch64. >> >> Signed-off-by: zhanghailiang <zhang.zhanghailiang@huawei.com> >> Signed-off-by: Peng Liang <liangpeng10@huawei.com> >> --- >> Documentation/virt/kvm/api.rst | 8 ++++++++ >> arch/arm64/kvm/arm.c | 1 + >> include/uapi/linux/kvm.h | 1 + >> 3 files changed, 10 insertions(+) >> >> diff --git a/Documentation/virt/kvm/api.rst b/Documentation/virt/kvm/api.rst >> index d2b733dc7892..50214ed8f50e 100644 >> --- a/Documentation/virt/kvm/api.rst >> +++ b/Documentation/virt/kvm/api.rst >> @@ -6173,3 +6173,11 @@ specific interfaces must be consistent, i.e. if one says the feature >> is supported, than the other should as well and vice versa. For arm64 >> see Documentation/virt/kvm/devices/vcpu.rst "KVM_ARM_VCPU_PVTIME_CTRL". >> For x86 see Documentation/virt/kvm/msr.rst "MSR_KVM_STEAL_TIME". >> + >> +8.25 KVM_CAP_ARM_CPU_FEATURE >> +----------------------------------- > > Too many '----' > >> + >> +:Architecture: arm64 >> + >> +This capability indicates that userspace can modify the ID registers via >> +KVM_SET_ONE_REG ioctl. > > You should say something like "See KVM_SET_ONE_REG:ARM64 ID Registers" > here and also extend the "KVM_SET_ONE_REG" section with a "ARM64 ID > Register" section that describes the limits and return values. > >> diff --git a/arch/arm64/kvm/arm.c b/arch/arm64/kvm/arm.c >> index 6d961e192268..918a7a56b224 100644 >> --- a/arch/arm64/kvm/arm.c >> +++ b/arch/arm64/kvm/arm.c >> @@ -178,6 +178,7 @@ int kvm_vm_ioctl_check_extension(struct kvm *kvm, long ext) >> case KVM_CAP_ARM_IRQ_LINE_LAYOUT_2: >> case KVM_CAP_ARM_NISV_TO_USER: >> case KVM_CAP_ARM_INJECT_EXT_DABT: >> + case KVM_CAP_ARM_CPU_FEATURE: >> r = 1; >> break; >> case KVM_CAP_ARM_SET_DEVICE_ADDR: >> diff --git a/include/uapi/linux/kvm.h b/include/uapi/linux/kvm.h >> index 7d8eced6f459..12356beadd5a 100644 >> --- a/include/uapi/linux/kvm.h >> +++ b/include/uapi/linux/kvm.h >> @@ -1037,6 +1037,7 @@ struct kvm_ppc_resize_hpt { >> #define KVM_CAP_SMALLER_MAXPHYADDR 185 >> #define KVM_CAP_S390_DIAG318 186 >> #define KVM_CAP_STEAL_TIME 187 >> +#define KVM_CAP_ARM_CPU_FEATURE 188 >> >> #ifdef KVM_CAP_IRQ_ROUTING >> >> -- >> 2.26.2 >> > > Thanks, > drew > > . > Thank you for your advise. I'll change them in next version. Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers 2020-09-17 12:00 ` Peng Liang @ 2020-09-18 8:01 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 8:01 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: > In AArch64, guest will read the same values of the ID regsiters with > host. Both of them read the values from arm64_ftr_regs. This patch > series add support to emulate and configure ID registers so that we can > control the value of ID registers that guest read. > > v1 -> v2: > - save the ID registers in sysreg file instead of a new struct > - apply a checker before setting the value to the register > - add doc for new KVM_CAP_ARM_CPU_FEATURE > > Peng Liang (7): > arm64: add a helper function to traverse arm64_ftr_regs > arm64: introduce check_features > kvm: arm64: save ID registers to sys_regs file > kvm: arm64: introduce check_user > kvm: arm64: implement check_user for ID registers > kvm: arm64: make ID registers configurable > kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension > > Documentation/virt/kvm/api.rst | 8 + > arch/arm64/include/asm/cpufeature.h | 4 + > arch/arm64/include/asm/kvm_coproc.h | 2 + > arch/arm64/include/asm/kvm_host.h | 3 + > arch/arm64/kernel/cpufeature.c | 36 +++ > arch/arm64/kvm/arm.c | 3 + > arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- > arch/arm64/kvm/sys_regs.h | 6 + > include/uapi/linux/kvm.h | 1 + > 9 files changed, 532 insertions(+), 12 deletions(-) > > -- > 2.26.2 > Hi Peng, I'd much rather see a series of patches where each patch converts a single ID register from using ID_SANITISED() to having its own table entry, where its own set_user() and reset() functions take into account its features using high level arm64_ftr* functions. Any ID registers that can still share code can certainly do so with some post-conversion refactoring. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers @ 2020-09-18 8:01 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 8:01 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: > In AArch64, guest will read the same values of the ID regsiters with > host. Both of them read the values from arm64_ftr_regs. This patch > series add support to emulate and configure ID registers so that we can > control the value of ID registers that guest read. > > v1 -> v2: > - save the ID registers in sysreg file instead of a new struct > - apply a checker before setting the value to the register > - add doc for new KVM_CAP_ARM_CPU_FEATURE > > Peng Liang (7): > arm64: add a helper function to traverse arm64_ftr_regs > arm64: introduce check_features > kvm: arm64: save ID registers to sys_regs file > kvm: arm64: introduce check_user > kvm: arm64: implement check_user for ID registers > kvm: arm64: make ID registers configurable > kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension > > Documentation/virt/kvm/api.rst | 8 + > arch/arm64/include/asm/cpufeature.h | 4 + > arch/arm64/include/asm/kvm_coproc.h | 2 + > arch/arm64/include/asm/kvm_host.h | 3 + > arch/arm64/kernel/cpufeature.c | 36 +++ > arch/arm64/kvm/arm.c | 3 + > arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- > arch/arm64/kvm/sys_regs.h | 6 + > include/uapi/linux/kvm.h | 1 + > 9 files changed, 532 insertions(+), 12 deletions(-) > > -- > 2.26.2 > Hi Peng, I'd much rather see a series of patches where each patch converts a single ID register from using ID_SANITISED() to having its own table entry, where its own set_user() and reset() functions take into account its features using high level arm64_ftr* functions. Any ID registers that can still share code can certainly do so with some post-conversion refactoring. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers 2020-09-18 8:01 ` Andrew Jones @ 2020-09-18 9:51 ` Peng Liang -1 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:51 UTC (permalink / raw) To: Andrew Jones; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On 9/18/2020 4:01 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: >> In AArch64, guest will read the same values of the ID regsiters with >> host. Both of them read the values from arm64_ftr_regs. This patch >> series add support to emulate and configure ID registers so that we can >> control the value of ID registers that guest read. >> >> v1 -> v2: >> - save the ID registers in sysreg file instead of a new struct >> - apply a checker before setting the value to the register >> - add doc for new KVM_CAP_ARM_CPU_FEATURE >> >> Peng Liang (7): >> arm64: add a helper function to traverse arm64_ftr_regs >> arm64: introduce check_features >> kvm: arm64: save ID registers to sys_regs file >> kvm: arm64: introduce check_user >> kvm: arm64: implement check_user for ID registers >> kvm: arm64: make ID registers configurable >> kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension >> >> Documentation/virt/kvm/api.rst | 8 + >> arch/arm64/include/asm/cpufeature.h | 4 + >> arch/arm64/include/asm/kvm_coproc.h | 2 + >> arch/arm64/include/asm/kvm_host.h | 3 + >> arch/arm64/kernel/cpufeature.c | 36 +++ >> arch/arm64/kvm/arm.c | 3 + >> arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- >> arch/arm64/kvm/sys_regs.h | 6 + >> include/uapi/linux/kvm.h | 1 + >> 9 files changed, 532 insertions(+), 12 deletions(-) >> >> -- >> 2.26.2 >> > > Hi Peng, > > I'd much rather see a series of patches where each patch converts a single > ID register from using ID_SANITISED() to having its own table entry, where > its own set_user() and reset() functions take into account its features > using high level arm64_ftr* functions. Any ID registers that can still > share code can certainly do so with some post-conversion refactoring. > > Thanks, > drew > > . > Hi Andrew, Thank you for your advise. I'll rework the code to use different set_user() for different ID registers (maybe some general registers still use shareing set_user()) and check the value defined by user space in its own set_user in next version. But do we need to implement reset() for ID registers? I think ID registers are read-only in guest and guest won't and can't change their values. And after 03fdfb2690099 ("KVM: arm64: Don't write junk to sysregs on reset"), we won't write junk to sysregs on reset. So their values won't change on reset? Thanks, Peng _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers @ 2020-09-18 9:51 ` Peng Liang 0 siblings, 0 replies; 52+ messages in thread From: Peng Liang @ 2020-09-18 9:51 UTC (permalink / raw) To: Andrew Jones; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On 9/18/2020 4:01 PM, Andrew Jones wrote: > On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: >> In AArch64, guest will read the same values of the ID regsiters with >> host. Both of them read the values from arm64_ftr_regs. This patch >> series add support to emulate and configure ID registers so that we can >> control the value of ID registers that guest read. >> >> v1 -> v2: >> - save the ID registers in sysreg file instead of a new struct >> - apply a checker before setting the value to the register >> - add doc for new KVM_CAP_ARM_CPU_FEATURE >> >> Peng Liang (7): >> arm64: add a helper function to traverse arm64_ftr_regs >> arm64: introduce check_features >> kvm: arm64: save ID registers to sys_regs file >> kvm: arm64: introduce check_user >> kvm: arm64: implement check_user for ID registers >> kvm: arm64: make ID registers configurable >> kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension >> >> Documentation/virt/kvm/api.rst | 8 + >> arch/arm64/include/asm/cpufeature.h | 4 + >> arch/arm64/include/asm/kvm_coproc.h | 2 + >> arch/arm64/include/asm/kvm_host.h | 3 + >> arch/arm64/kernel/cpufeature.c | 36 +++ >> arch/arm64/kvm/arm.c | 3 + >> arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- >> arch/arm64/kvm/sys_regs.h | 6 + >> include/uapi/linux/kvm.h | 1 + >> 9 files changed, 532 insertions(+), 12 deletions(-) >> >> -- >> 2.26.2 >> > > Hi Peng, > > I'd much rather see a series of patches where each patch converts a single > ID register from using ID_SANITISED() to having its own table entry, where > its own set_user() and reset() functions take into account its features > using high level arm64_ftr* functions. Any ID registers that can still > share code can certainly do so with some post-conversion refactoring. > > Thanks, > drew > > . > Hi Andrew, Thank you for your advise. I'll rework the code to use different set_user() for different ID registers (maybe some general registers still use shareing set_user()) and check the value defined by user space in its own set_user in next version. But do we need to implement reset() for ID registers? I think ID registers are read-only in guest and guest won't and can't change their values. And after 03fdfb2690099 ("KVM: arm64: Don't write junk to sysregs on reset"), we won't write junk to sysregs on reset. So their values won't change on reset? Thanks, Peng ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers 2020-09-18 9:51 ` Peng Liang @ 2020-09-18 10:20 ` Andrew Jones -1 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 10:20 UTC (permalink / raw) To: Peng Liang; +Cc: zhang.zhanghailiang, kvm, maz, will, kvmarm On Fri, Sep 18, 2020 at 05:51:27PM +0800, Peng Liang wrote: > On 9/18/2020 4:01 PM, Andrew Jones wrote: > > On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: > >> In AArch64, guest will read the same values of the ID regsiters with > >> host. Both of them read the values from arm64_ftr_regs. This patch > >> series add support to emulate and configure ID registers so that we can > >> control the value of ID registers that guest read. > >> > >> v1 -> v2: > >> - save the ID registers in sysreg file instead of a new struct > >> - apply a checker before setting the value to the register > >> - add doc for new KVM_CAP_ARM_CPU_FEATURE > >> > >> Peng Liang (7): > >> arm64: add a helper function to traverse arm64_ftr_regs > >> arm64: introduce check_features > >> kvm: arm64: save ID registers to sys_regs file > >> kvm: arm64: introduce check_user > >> kvm: arm64: implement check_user for ID registers > >> kvm: arm64: make ID registers configurable > >> kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension > >> > >> Documentation/virt/kvm/api.rst | 8 + > >> arch/arm64/include/asm/cpufeature.h | 4 + > >> arch/arm64/include/asm/kvm_coproc.h | 2 + > >> arch/arm64/include/asm/kvm_host.h | 3 + > >> arch/arm64/kernel/cpufeature.c | 36 +++ > >> arch/arm64/kvm/arm.c | 3 + > >> arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- > >> arch/arm64/kvm/sys_regs.h | 6 + > >> include/uapi/linux/kvm.h | 1 + > >> 9 files changed, 532 insertions(+), 12 deletions(-) > >> > >> -- > >> 2.26.2 > >> > > > > Hi Peng, > > > > I'd much rather see a series of patches where each patch converts a single > > ID register from using ID_SANITISED() to having its own table entry, where > > its own set_user() and reset() functions take into account its features > > using high level arm64_ftr* functions. Any ID registers that can still > > share code can certainly do so with some post-conversion refactoring. > > > > Thanks, > > drew > > > > . > > > Hi Andrew, > > Thank you for your advise. I'll rework the code to use different set_user() > for different ID registers (maybe some general registers still use shareing > set_user()) and check the value defined by user space in its own set_user in > next version. > > But do we need to implement reset() for ID registers? I think ID registers > are read-only in guest and guest won't and can't change their values. And > after 03fdfb2690099 ("KVM: arm64: Don't write junk to sysregs on reset"), > we won't write junk to sysregs on reset. So their values won't change on > reset? If a new reset isn't needed, then that's fine. I just want each ID register to have its requirements considered independently, rather than trying to apply the same functions to all of them without any apparent consideration. Thanks, drew _______________________________________________ kvmarm mailing list kvmarm@lists.cs.columbia.edu https://lists.cs.columbia.edu/mailman/listinfo/kvmarm ^ permalink raw reply [flat|nested] 52+ messages in thread
* Re: [RFC v2 0/7] kvm: arm64: emulate ID registers @ 2020-09-18 10:20 ` Andrew Jones 0 siblings, 0 replies; 52+ messages in thread From: Andrew Jones @ 2020-09-18 10:20 UTC (permalink / raw) To: Peng Liang; +Cc: kvmarm, kvm, maz, will, zhang.zhanghailiang, xiexiangyou On Fri, Sep 18, 2020 at 05:51:27PM +0800, Peng Liang wrote: > On 9/18/2020 4:01 PM, Andrew Jones wrote: > > On Thu, Sep 17, 2020 at 08:00:54PM +0800, Peng Liang wrote: > >> In AArch64, guest will read the same values of the ID regsiters with > >> host. Both of them read the values from arm64_ftr_regs. This patch > >> series add support to emulate and configure ID registers so that we can > >> control the value of ID registers that guest read. > >> > >> v1 -> v2: > >> - save the ID registers in sysreg file instead of a new struct > >> - apply a checker before setting the value to the register > >> - add doc for new KVM_CAP_ARM_CPU_FEATURE > >> > >> Peng Liang (7): > >> arm64: add a helper function to traverse arm64_ftr_regs > >> arm64: introduce check_features > >> kvm: arm64: save ID registers to sys_regs file > >> kvm: arm64: introduce check_user > >> kvm: arm64: implement check_user for ID registers > >> kvm: arm64: make ID registers configurable > >> kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension > >> > >> Documentation/virt/kvm/api.rst | 8 + > >> arch/arm64/include/asm/cpufeature.h | 4 + > >> arch/arm64/include/asm/kvm_coproc.h | 2 + > >> arch/arm64/include/asm/kvm_host.h | 3 + > >> arch/arm64/kernel/cpufeature.c | 36 +++ > >> arch/arm64/kvm/arm.c | 3 + > >> arch/arm64/kvm/sys_regs.c | 481 +++++++++++++++++++++++++++- > >> arch/arm64/kvm/sys_regs.h | 6 + > >> include/uapi/linux/kvm.h | 1 + > >> 9 files changed, 532 insertions(+), 12 deletions(-) > >> > >> -- > >> 2.26.2 > >> > > > > Hi Peng, > > > > I'd much rather see a series of patches where each patch converts a single > > ID register from using ID_SANITISED() to having its own table entry, where > > its own set_user() and reset() functions take into account its features > > using high level arm64_ftr* functions. Any ID registers that can still > > share code can certainly do so with some post-conversion refactoring. > > > > Thanks, > > drew > > > > . > > > Hi Andrew, > > Thank you for your advise. I'll rework the code to use different set_user() > for different ID registers (maybe some general registers still use shareing > set_user()) and check the value defined by user space in its own set_user in > next version. > > But do we need to implement reset() for ID registers? I think ID registers > are read-only in guest and guest won't and can't change their values. And > after 03fdfb2690099 ("KVM: arm64: Don't write junk to sysregs on reset"), > we won't write junk to sysregs on reset. So their values won't change on > reset? If a new reset isn't needed, then that's fine. I just want each ID register to have its requirements considered independently, rather than trying to apply the same functions to all of them without any apparent consideration. Thanks, drew ^ permalink raw reply [flat|nested] 52+ messages in thread
end of thread, other threads:[~2020-09-18 11:58 UTC | newest] Thread overview: 52+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2020-09-17 12:00 [RFC v2 0/7] kvm: arm64: emulate ID registers Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-17 12:00 ` [RFC v2 1/7] arm64: add a helper function to traverse arm64_ftr_regs Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-18 7:18 ` Andrew Jones 2020-09-18 7:18 ` Andrew Jones 2020-09-18 9:24 ` Peng Liang 2020-09-18 9:24 ` Peng Liang 2020-09-18 10:28 ` Andrew Jones 2020-09-18 10:28 ` Andrew Jones 2020-09-18 11:58 ` Peng Liang 2020-09-18 11:58 ` Peng Liang 2020-09-17 12:00 ` [RFC v2 2/7] arm64: introduce check_features Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-18 7:30 ` Andrew Jones 2020-09-18 7:30 ` Andrew Jones 2020-09-18 9:25 ` Peng Liang 2020-09-18 9:25 ` Peng Liang 2020-09-17 12:00 ` [RFC v2 3/7] kvm: arm64: save ID registers to sys_regs file Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-18 7:34 ` Andrew Jones 2020-09-18 7:34 ` Andrew Jones 2020-09-17 12:00 ` [RFC v2 4/7] kvm: arm64: introduce check_user Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-18 7:41 ` Andrew Jones 2020-09-18 7:41 ` Andrew Jones 2020-09-18 9:25 ` Peng Liang 2020-09-18 9:25 ` Peng Liang 2020-09-17 12:00 ` [RFC v2 5/7] kvm: arm64: implement check_user for ID registers Peng Liang 2020-09-17 12:00 ` Peng Liang 2020-09-18 7:46 ` Andrew Jones 2020-09-18 7:46 ` Andrew Jones 2020-09-18 9:26 ` Peng Liang 2020-09-18 9:26 ` Peng Liang 2020-09-17 12:01 ` [RFC v2 6/7] kvm: arm64: make ID registers configurable Peng Liang 2020-09-17 12:01 ` Peng Liang 2020-09-18 7:50 ` Andrew Jones 2020-09-18 7:50 ` Andrew Jones 2020-09-18 9:26 ` Peng Liang 2020-09-18 9:26 ` Peng Liang 2020-09-17 12:01 ` [RFC v2 7/7] kvm: arm64: add KVM_CAP_ARM_CPU_FEATURE extension Peng Liang 2020-09-17 12:01 ` Peng Liang 2020-09-18 7:55 ` Andrew Jones 2020-09-18 7:55 ` Andrew Jones 2020-09-18 9:26 ` Peng Liang 2020-09-18 9:26 ` Peng Liang 2020-09-18 8:01 ` [RFC v2 0/7] kvm: arm64: emulate ID registers Andrew Jones 2020-09-18 8:01 ` Andrew Jones 2020-09-18 9:51 ` Peng Liang 2020-09-18 9:51 ` Peng Liang 2020-09-18 10:20 ` Andrew Jones 2020-09-18 10:20 ` Andrew Jones
This is an external index of several public inboxes, see mirroring instructions on how to clone and mirror all data and code used by this external index.