summaryrefslogtreecommitdiff
path: root/sys/arch/amd64/amd64/machdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/amd64/amd64/machdep.c')
-rw-r--r--sys/arch/amd64/amd64/machdep.c108
1 files changed, 106 insertions, 2 deletions
diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c
index 3f8580a..3338caa 100644
--- a/sys/arch/amd64/amd64/machdep.c
+++ b/sys/arch/amd64/amd64/machdep.c
@@ -74,6 +74,12 @@
#define CPU_SMEP 0
#endif
+#if defined(__CPU_UMIP)
+#define CPU_UMIP __CPU_UMIP
+#else
+#define CPU_UMIP 0
+#endif
+
int ibrs_enable(void);
int simd_init(void);
void syscall_isr(void);
@@ -238,17 +244,90 @@ init_ipis(void)
}
static void
+cpu_get_vendor(struct cpu_info *ci)
+{
+ uint32_t unused, ebx, ecx, edx;
+ char vendor_str[13];
+
+ /*
+ * This CPUID returns a 12 byte CPU vendor string
+ * that we'll put together and use to detect the vendor.
+ */
+ CPUID(0, unused, ebx, ecx, edx);
+
+ /* Dword 0 */
+ vendor_str[0] = ebx & 0xFF;
+ vendor_str[1] = (ebx >> 8) & 0xFF;
+ vendor_str[2] = (ebx >> 16) & 0xFF;
+ vendor_str[3] = (ebx >> 24) & 0xFF;
+
+ /* Dword 1 */
+ vendor_str[4] = edx & 0xFF;
+ vendor_str[5] = (edx >> 8) & 0xFF;
+ vendor_str[6] = (edx >> 16) & 0xFF;
+ vendor_str[7] = (edx >> 24) & 0xFF;
+
+ /* Dword 2 */
+ vendor_str[8] = ecx & 0xFF;
+ vendor_str[9] = (ecx >> 8) & 0xFF;
+ vendor_str[10] = (ecx >> 16) & 0xFF;
+ vendor_str[11] = (ecx >> 24) & 0xFF;
+ vendor_str[12] = '\0';
+
+ /* Is this an AMD CPU? */
+ if (strcmp(vendor_str, "AuthenticAMD") == 0) {
+ ci->vendor = CPU_VENDOR_AMD;
+ return;
+ }
+
+ /* Is this an Intel CPU? */
+ if (strcmp(vendor_str, "GenuineIntel") == 0) {
+ ci->vendor = CPU_VENDOR_INTEL;
+ return;
+ }
+
+ /*
+ * Some buggy Intel CPUs report the string "GenuineIotel"
+ * instead of "GenuineIntel". This is rare but we should
+ * still handle it as it can happen. Probably a good idea
+ * to log it so the user can know about their rare CPU
+ * quirk and brag to their friends :~)
+ */
+ if (strcmp(vendor_str, "GenuineIotel") == 0) {
+ pr_trace_bsp("vendor_str=%s\n", vendor_str);
+ pr_trace_bsp("detected vendor string quirk\n");
+ ci->vendor = CPU_VENDOR_INTEL;
+ return;
+ }
+
+ ci->vendor = CPU_VENDOR_OTHER;
+}
+
+static void
cpu_get_info(struct cpu_info *ci)
{
- uint32_t eax, ebx, unused;
+ uint32_t unused, eax, ebx, ecx, edx;
uint8_t ext_model, ext_family;
+ /* Get the vendor information */
+ cpu_get_vendor(ci);
+
/* Extended features */
- CPUID(0x07, unused, ebx, unused, unused);
+ CPUID(0x07, unused, ebx, ecx, unused);
if (ISSET(ebx, BIT(7)))
ci->feat |= CPU_FEAT_SMEP;
if (ISSET(ebx, BIT(20)))
ci->feat |= CPU_FEAT_SMAP;
+ if (ISSET(ecx, BIT(2)))
+ ci->feat |= CPU_FEAT_UMIP;
+
+ /*
+ * Processor power management information bits as well
+ * as bits describing RAS capabilities
+ */
+ CPUID(0x80000007, unused, unused, unused, edx);
+ if (ISSET(edx, BIT(8)))
+ ci->feat |= CPU_FEAT_TSCINV;
/*
* Processor info and feature bits
@@ -278,6 +357,30 @@ cpu_get_info(struct cpu_info *ci)
}
}
+/*
+ * The CR4.UMIP bit prevents user programs from
+ * executing instructions related to accessing
+ * system memory structures. This should be enabled
+ * by default if supported.
+ */
+static void
+cpu_enable_umip(void)
+{
+ struct cpu_info *ci = this_cpu();
+ uint64_t cr4;
+
+ if (!CPU_UMIP) {
+ pr_trace_bsp("UMIP not configured\n");
+ return;
+ }
+
+ if (ISSET(ci->feat, CPU_FEAT_UMIP)) {
+ cr4 = amd64_read_cr4();
+ cr4 |= CR4_UMIP;
+ amd64_write_cr4(cr4);
+ }
+}
+
void
cpu_shootdown_tlb(vaddr_t va)
{
@@ -509,6 +612,7 @@ cpu_startup(struct cpu_info *ci)
cpu_get_info(ci);
cpu_enable_smep();
+ cpu_enable_umip();
enable_simd();
lapic_init();