Page Menu
Home
FreeBSD
Search
Configure Global Search
Log In
Files
F153709010
D50572.id.diff
No One
Temporary
Actions
View File
Edit File
Delete File
View Transforms
Subscribe
Mute Notifications
Flag For Later
Award Token
Size
5 KB
Referenced Files
None
Subscribers
None
D50572.id.diff
View Options
diff --git a/sys/arm64/arm64/identcpu.c b/sys/arm64/arm64/identcpu.c
--- a/sys/arm64/arm64/identcpu.c
+++ b/sys/arm64/arm64/identcpu.c
@@ -51,6 +51,9 @@
static MALLOC_DEFINE(M_IDENTCPU, "CPU ID", "arm64 CPU identification memory");
struct cpu_desc;
+#ifdef INVARIANTS
+static bool hwcaps_set = false;
+#endif
static void print_cpu_midr(struct sbuf *sb, u_int cpu);
static void print_cpu_features(u_int cpu, struct cpu_desc *desc,
@@ -2594,13 +2597,62 @@
return (user_reg);
}
+static void
+clear_set_special_reg_idx(int idx, uint64_t clear, uint64_t set)
+{
+ const struct mrs_field *fields;
+ uint64_t k_old, k_new;
+ uint64_t f_old, f_new;
+ uint64_t l_old, l_new;
+
+ MPASS(idx < nitems(user_regs));
+
+ k_old = CPU_DESC_FIELD(kern_cpu_desc, idx);
+ k_new = (k_old & ~clear) | set;
+
+ f_old = CPU_DESC_FIELD(user_cpu_desc, idx);
+ f_new = (f_old & ~clear) | set;
+
+ l_old = CPU_DESC_FIELD(l_user_cpu_desc, idx);
+ l_new = (l_old & ~clear) | set;
+
+ fields = user_regs[idx].fields;
+ for (int j = 0; fields[j].type != 0; j++) {
+ u_int type;
+
+ /* Update the FreeBSD userspace ID register view */
+ type = ((fields[j].type & MRS_FREEBSD) != 0) ?
+ fields[j].type :
+ (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK));
+ f_new = update_special_reg_field(f_new,
+ type, f_old, fields[j].width, fields[j].shift,
+ fields[j].sign);
+
+ /* Update the Linux userspace ID register view */
+ type = ((fields[j].type & MRS_LINUX) != 0) ?
+ fields[j].type :
+ (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK));
+ l_new = update_special_reg_field(l_new,
+ type, l_old, fields[j].width, fields[j].shift,
+ fields[j].sign);
+
+ /* Update the kernel ID register view */
+ k_new = update_special_reg_field(k_new,
+ fields[j].type, k_old, fields[j].width,
+ fields[j].shift, fields[j].sign);
+ }
+
+ CPU_DESC_FIELD(kern_cpu_desc, idx) = k_new;
+ CPU_DESC_FIELD(user_cpu_desc, idx) = f_new;
+ CPU_DESC_FIELD(l_user_cpu_desc, idx) = l_new;
+}
+
void
update_special_regs(u_int cpu)
{
struct cpu_desc *desc;
- const struct mrs_field *fields;
- uint64_t l_user_reg, user_reg, kern_reg, value;
- int i, j;
+ uint64_t value;
+ int i;
if (cpu == 0) {
/* Create a user visible cpu description with safe values */
@@ -2618,44 +2670,42 @@
for (i = 0; i < nitems(user_regs); i++) {
value = CPU_DESC_FIELD(*desc, i);
if (cpu == 0) {
- kern_reg = value;
- user_reg = value;
- l_user_reg = value;
- } else {
- kern_reg = CPU_DESC_FIELD(kern_cpu_desc, i);
- user_reg = CPU_DESC_FIELD(user_cpu_desc, i);
- l_user_reg = CPU_DESC_FIELD(l_user_cpu_desc, i);
+ CPU_DESC_FIELD(kern_cpu_desc, i) = value;
+ CPU_DESC_FIELD(user_cpu_desc, i) = value;
+ CPU_DESC_FIELD(l_user_cpu_desc, i) = value;
}
- fields = user_regs[i].fields;
- for (j = 0; fields[j].type != 0; j++) {
- u_int type;
-
- /* Update the FreeBSD userspace ID register view */
- type = ((fields[j].type & MRS_FREEBSD) != 0) ?
- fields[j].type :
- (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK));
- user_reg = update_special_reg_field(user_reg,
- type, value, fields[j].width, fields[j].shift,
- fields[j].sign);
-
- /* Update the Linux userspace ID register view */
- type = ((fields[j].type & MRS_LINUX) != 0) ?
- fields[j].type :
- (MRS_EXACT | (fields[j].type & MRS_SAFE_MASK));
- l_user_reg = update_special_reg_field(l_user_reg,
- type, value, fields[j].width, fields[j].shift,
- fields[j].sign);
-
- /* Update the kernel ID register view */
- kern_reg = update_special_reg_field(kern_reg,
- fields[j].type, value, fields[j].width,
- fields[j].shift, fields[j].sign);
- }
+ clear_set_special_reg_idx(i, UINT64_MAX, value);
+ }
+}
+
+/*
+ * Updates a special register in all views. This creates a copy of the
+ * register then clears it and sets new bits. It will then compare this
+ * with the old version as if it was the ID register for a new CPU.
+ *
+ * It is intended to let code that disables features, e.g. due to errata,
+ * to clear the user visible field.
+ *
+ * This needs to be called before the HWCAPs are set. If called from a CPU
+ * feature handler this safe to call from CPU_FEAT_EARLY_BOOT. It also needs
+ * to be before link_elf_late_ireloc is called. As this is called after the
+ * HWCAPs are set the check for these is enough.
+ */
+void
+update_special_reg(u_int reg, uint64_t clear, uint64_t set)
+{
+ MPASS(hwcaps_set == false);
+ /* There is no locking here, so we only support changing this on CPU0 */
+ /* TODO: Add said locking */
+ MPASS(PCPU_GET(cpuid) == 0);
+
+ for (int i = 0; i < nitems(user_regs); i++) {
+ if (user_regs[i].reg != reg)
+ continue;
- CPU_DESC_FIELD(kern_cpu_desc, i) = kern_reg;
- CPU_DESC_FIELD(user_cpu_desc, i) = user_reg;
- CPU_DESC_FIELD(l_user_cpu_desc, i) = l_user_reg;
+ clear_set_special_reg_idx(i, clear, set);
+ return;
}
}
@@ -2757,6 +2807,11 @@
prev_desc = desc;
}
+#ifdef INVARIANTS
+ /* Check we dont update the special registers after this point */
+ hwcaps_set = true;
+#endif
+
/* Find the values to export to userspace as AT_HWCAP and AT_HWCAP2 */
parse_cpu_features(true, &user_cpu_desc, &elf_hwcap, &elf_hwcap2);
parse_cpu_features(true, &l_user_cpu_desc, &linux_elf_hwcap,
diff --git a/sys/arm64/include/cpu.h b/sys/arm64/include/cpu.h
--- a/sys/arm64/include/cpu.h
+++ b/sys/arm64/include/cpu.h
@@ -232,6 +232,7 @@
/* Functions to read the sanitised view of the special registers */
void update_special_regs(u_int);
+void update_special_reg(u_int reg, uint64_t, uint64_t);
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);
File Metadata
Details
Attached
Mime Type
text/plain
Expires
Fri, Apr 24, 2:52 AM (16 h, 53 m)
Storage Engine
blob
Storage Format
Raw Data
Storage Handle
32056766
Default Alt Text
D50572.id.diff (5 KB)
Attached To
Mode
D50572: arm64: Add a function to restrict the ID registers
Attached
Detach File
Event Timeline
Log In to Comment