git: fbec1f91951f - main - arm64: Add a masked get_kernel_reg()
- Go to: [ bottom of page ] [ top of archives ] [ this month ]
Date: Wed, 28 Jun 2023 20:47:35 UTC
The branch main has been updated by markj:
URL: https://cgit.FreeBSD.org/src/commit/?id=fbec1f91951fe01c1c590bab5e6c16a30884f352
commit fbec1f91951fe01c1c590bab5e6c16a30884f352
Author: Mark Johnston <markj@FreeBSD.org>
AuthorDate: 2023-06-28 20:12:47 +0000
Commit: Mark Johnston <markj@FreeBSD.org>
CommitDate: 2023-06-28 20:29:49 +0000
arm64: Add a masked get_kernel_reg()
This lets consumers fetch the value of a system register and apply a
mask over individual fields. That is, each field in the returned value
will be the "smaller" of the two provided by "mask" and the value saved
in kern_cpu_desc. This will be used by vmm to sanitize host system
register fields.
Reviewed by: andrew
MFC after: 2 weeks
Sponsored by: The FreeBSD Foundation
Sponsored by: Klara, Inc. (hardware)
Differential Revision: https://reviews.freebsd.org/D40500
---
sys/arm64/arm64/identcpu.c | 90 +++++++++++++++++++++++++++++-----------------
sys/arm64/include/cpu.h | 1 +
2 files changed, 59 insertions(+), 32 deletions(-)
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
index e96f0a089784..01e663ff47c2 100644
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -1721,38 +1721,6 @@ user_mrs_handler(vm_offset_t va, uint32_t insn, struct trapframe *frame,
return (1);
}
-bool
-extract_user_id_field(u_int reg, u_int field_shift, uint8_t *val)
-{
- uint64_t value;
- int i;
-
- for (i = 0; i < nitems(user_regs); i++) {
- if (user_regs[i].reg == reg) {
- value = CPU_DESC_FIELD(user_cpu_desc, i);
- *val = value >> field_shift;
- return (true);
- }
- }
-
- return (false);
-}
-
-bool
-get_kernel_reg(u_int reg, uint64_t *val)
-{
- int i;
-
- for (i = 0; i < nitems(user_regs); i++) {
- if (user_regs[i].reg == reg) {
- *val = CPU_DESC_FIELD(kern_cpu_desc, i);
- return (true);
- }
- }
-
- return (false);
-}
-
/*
* Compares two field values that may be signed or unsigned.
* Returns:
@@ -1808,6 +1776,64 @@ update_lower_register(uint64_t val, uint64_t new_val, u_int shift,
return (val);
}
+bool
+extract_user_id_field(u_int reg, u_int field_shift, uint8_t *val)
+{
+ uint64_t value;
+ int i;
+
+ for (i = 0; i < nitems(user_regs); i++) {
+ if (user_regs[i].reg == reg) {
+ value = CPU_DESC_FIELD(user_cpu_desc, i);
+ *val = value >> field_shift;
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+bool
+get_kernel_reg(u_int reg, uint64_t *val)
+{
+ int i;
+
+ for (i = 0; i < nitems(user_regs); i++) {
+ if (user_regs[i].reg == reg) {
+ *val = CPU_DESC_FIELD(kern_cpu_desc, i);
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
+/*
+ * Fetch the specified register's value, ensuring that individual field values
+ * do not exceed those in the mask.
+ */
+bool
+get_kernel_reg_masked(u_int reg, uint64_t *valp, uint64_t mask)
+{
+ struct mrs_field *fields;
+ uint64_t val;
+
+ for (int i = 0; i < nitems(user_regs); i++) {
+ if (user_regs[i].reg == reg) {
+ val = CPU_DESC_FIELD(kern_cpu_desc, i);
+ *valp = 0;
+ fields = user_regs[i].fields;
+ for (int j = 0; fields[j].type != 0; j++) {
+ *valp |= update_lower_register(mask, val,
+ fields[j].shift, 4, fields[j].sign);
+ }
+ return (true);
+ }
+ }
+
+ return (false);
+}
+
void
update_special_regs(u_int cpu)
{
diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h
index 1ea497756698..0bb320f2e0a0 100644
--- a/sys/arm64/include/cpu.h
+++ b/sys/arm64/include/cpu.h
@@ -213,6 +213,7 @@ void ptrauth_mp_start(uint64_t);
void update_special_regs(u_int);
bool extract_user_id_field(u_int, u_int, uint8_t *);
bool get_kernel_reg(u_int, uint64_t *);
+bool get_kernel_reg_masked(u_int, uint64_t *, uint64_t);
void cpu_desc_init(void);