summaryrefslogtreecommitdiff
path: root/sys/arch/amd64
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arch/amd64')
-rw-r--r--sys/arch/amd64/amd64/hpet.c1
-rw-r--r--sys/arch/amd64/amd64/lapic.c1
-rw-r--r--sys/arch/amd64/amd64/machdep.c108
-rw-r--r--sys/arch/amd64/amd64/proc_machdep.c2
-rw-r--r--sys/arch/amd64/amd64/tsc.c109
-rw-r--r--sys/arch/amd64/conf/GENERIC2
6 files changed, 220 insertions, 3 deletions
diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c
index 3b0ca46..9191bee 100644
--- a/sys/arch/amd64/amd64/hpet.c
+++ b/sys/arch/amd64/amd64/hpet.c
@@ -197,6 +197,7 @@ hpet_init(void)
timer.get_time_usec = hpet_time_usec;
timer.get_time_nsec = hpet_time_nsec;
timer.get_time_sec = hpet_time_sec;
+ timer.flags = TIMER_MONOTONIC;
register_timer(TIMER_GP, &timer);
return 0;
}
diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c
index 022592c..ceb5428 100644
--- a/sys/arch/amd64/amd64/lapic.c
+++ b/sys/arch/amd64/amd64/lapic.c
@@ -364,5 +364,6 @@ lapic_init(void)
lapic_timer.name = "LAPIC_INTEGRATED_TIMER";
lapic_timer.stop = lapic_timer_stop;
lapic_timer.oneshot_us = lapic_timer_oneshot_us;
+ lapic_timer.flags = 0;
register_timer(TIMER_SCHED, &lapic_timer);
}
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();
diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c
index ad807fe..a1d6563 100644
--- a/sys/arch/amd64/amd64/proc_machdep.c
+++ b/sys/arch/amd64/amd64/proc_machdep.c
@@ -256,7 +256,7 @@ sched_switch_to(struct trapframe *tf, struct proc *td)
/* Update stats */
cpustat = &ci->stat;
- cpustat->nswitch++;
+ atomic_inc_64(&cpustat->nswitch);
ci->curtd = td;
pcbp = &td->pcb;
diff --git a/sys/arch/amd64/amd64/tsc.c b/sys/arch/amd64/amd64/tsc.c
new file mode 100644
index 0000000..2111cd0
--- /dev/null
+++ b/sys/arch/amd64/amd64/tsc.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright (c) 2023-2025 Ian Marco Moffett and the Osmora Team.
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright notice,
+ * this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of Hyra nor the names of its
+ * contributors may be used to endorse or promote products derived from
+ * this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
+ * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
+ * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include <sys/errno.h>
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <sys/driver.h>
+#include <sys/syslog.h>
+#include <machine/tsc.h>
+#include <machine/asm.h>
+#include <machine/cpuid.h>
+
+/* See kconf(9) */
+#if defined(__USER_TSC)
+#define USER_TSC __USER_TSC
+#else
+#define USER_TSC 0
+#endif /* __USER_TSC */
+
+#define pr_trace(fmt, ...) kprintf("tsc: " fmt, ##__VA_ARGS__)
+#define pr_error(...) pr_trace(__VA_ARGS__)
+
+static uint64_t tsc_i = 0;
+
+uint64_t
+rdtsc_rel(void)
+{
+ return rdtsc() - tsc_i;
+}
+
+/*
+ * Check if the TSC and RDTSC instruction is
+ * supported on the current CPU.
+ *
+ * Returns zero if supported, otherwise a less
+ * than zero value is returned.
+ */
+static int
+tsc_check(void)
+{
+ uint32_t edx, unused;
+
+ CPUID(1, unused, unused, unused, edx);
+ if (ISSET(edx, BIT(4))) {
+ return 0;
+ }
+
+ return -ENOTSUP;
+}
+
+static int
+tsc_init(void)
+{
+ uint64_t cr4;
+ int error;
+
+ /* Is the TSC even supported? */
+ if ((error = tsc_check()) != 0) {
+ pr_error("TSC not supported by machine\n");
+ return error;
+ }
+
+ cr4 = amd64_read_cr4();
+ tsc_i = rdtsc();
+ pr_trace("initial count @ %d\n", rdtsc_rel());
+
+ /*
+ * If we USER_TSC is configured to "yes" then
+ * we'll need to enable the 'rdtsc' instruction
+ * in user mode.
+ */
+ if (!USER_TSC) {
+ cr4 &= ~CR4_TSD;
+ } else {
+ cr4 |= CR4_TSD;
+ }
+
+ amd64_write_cr4(cr4);
+ return 0;
+}
+
+DRIVER_EXPORT(tsc_init, "x86-tsc");
diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC
index 6f573f3..6bf3af5 100644
--- a/sys/arch/amd64/conf/GENERIC
+++ b/sys/arch/amd64/conf/GENERIC
@@ -7,6 +7,8 @@
//
option SPECTRE_IBRS no // Enable the IBRS CPU feature
option SERIAL_DEBUG yes // Enable kmsg serial logging
+option CPU_UMIP yes // Enable User-mode Instruction Prevention
option USER_KMSG no // Show kmsg in user consoles
+option USER_TSC no // Enable 'rdtsc' in user mode
option CPU_SMEP yes // Supervisor Memory Exec Protection
option I8042_POLL yes // Use polling for the i8042