summaryrefslogtreecommitdiff
path: root/src/sys
diff options
context:
space:
mode:
authorIan Moffett <ian@osmora.org>2025-09-15 12:31:08 -0400
committerIan Moffett <ian@osmora.org>2025-09-15 12:31:08 -0400
commit6bd92c969a6f4aefee258adc79a3ab0bde9443b2 (patch)
tree34ccbfba395827ce6975972704a52d43592803e5 /src/sys
parent4122de881d3b7f9e54563affd7564213d415d1e5 (diff)
kern/amd64: lapic: Initialize percore Local APIC
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'src/sys')
-rw-r--r--src/sys/arch/amd64/cpu/cpu_conf.c2
-rw-r--r--src/sys/arch/amd64/cpu/cpu_lapic.c174
-rw-r--r--src/sys/include/arch/amd64/cpuid.h40
-rw-r--r--src/sys/include/arch/amd64/lapic.h40
-rw-r--r--src/sys/include/arch/amd64/lapicregs.h108
-rw-r--r--src/sys/include/arch/amd64/mdcpu.h7
6 files changed, 371 insertions, 0 deletions
diff --git a/src/sys/arch/amd64/cpu/cpu_conf.c b/src/sys/arch/amd64/cpu/cpu_conf.c
index de0e9bc..7c1f5a0 100644
--- a/src/sys/arch/amd64/cpu/cpu_conf.c
+++ b/src/sys/arch/amd64/cpu/cpu_conf.c
@@ -32,6 +32,7 @@
#include <machine/msr.h>
#include <machine/idt.h>
#include <machine/trap.h>
+#include <machine/lapic.h>
/*
* Initialize interrupt vectors
@@ -63,4 +64,5 @@ cpu_conf(struct pcore *pcore)
/* We use %GS to store the processor */
wrmsr(IA32_GS_BASE, (uintptr_t)pcore);
+ lapic_init();
}
diff --git a/src/sys/arch/amd64/cpu/cpu_lapic.c b/src/sys/arch/amd64/cpu/cpu_lapic.c
new file mode 100644
index 0000000..1d12824
--- /dev/null
+++ b/src/sys/arch/amd64/cpu/cpu_lapic.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2025 Ian Marco Moffett and L5 engineers
+ * 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 the project 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.
+ */
+
+/*
+ * Description: Local APIC driver
+ * Author: Ian Marco Moffett
+ */
+
+#include <sys/syslog.h>
+#include <sys/cpuvar.h>
+#include <sys/panic.h>
+#include <sys/cdefs.h>
+#include <sys/param.h>
+#include <sys/types.h>
+#include <os/mmio.h>
+#include <machine/mdcpu.h>
+#include <machine/lapicregs.h>
+#include <machine/lapic.h>
+#include <machine/cpuid.h>
+#include <machine/msr.h>
+
+#define pr_trace(fmt, ...) printf("lapic: " fmt, ##__VA_ARGS__)
+#define bsp_trace(fmt, ...) if (lapic_is_bsp()) pr_trace(fmt, ##__VA_ARGS__)
+
+/*
+ * Returns true if the current processor is the
+ * bootstrap processor.
+ */
+__always_inline static inline bool
+lapic_is_bsp(void)
+{
+ uint64_t apic_base;
+
+ apic_base = rdmsr(IA32_APIC_BASE_MSR);
+ return ISSET(apic_base, BIT(8)) != 0;
+}
+
+/*
+ * Returns true if the processor supports the
+ * x2APIC.
+ */
+__always_inline static inline bool
+lapic_has_x2apic(void)
+{
+ uint32_t unused, ecx;
+
+ CPUID(1, unused, unused, ecx, unused);
+ return ISSET(ecx, BIT(21)) != 0;
+}
+
+/*
+ * Reads a 32 bit value from Local APIC
+ * register space.
+ *
+ * @ci: Target processor
+ * @reg: Register to read from.
+ */
+static inline uint64_t
+lapic_readl(const struct mdcore *core, uint32_t reg)
+{
+ void *addr;
+
+ if (!core->x2apic) {
+ addr = PTR_OFFSET(core->lapic_base, reg);
+ return mmio_read32(addr);
+ } else {
+ reg >>= 4;
+ return rdmsr(x2APIC_MSR_BASE + reg);
+ }
+}
+
+/*
+ * Reads the Local APIC ID of the current
+ * processor.
+ *
+ * @ci: Current processor
+ */
+static inline uint32_t
+lapic_read_id(const struct mdcore *core)
+{
+ if (!core->x2apic) {
+ return (lapic_readl(core, LAPIC_ID) >> 24) & 0xF;
+ } else {
+ return lapic_readl(core, LAPIC_ID);
+ }
+}
+
+/*
+ * Writes a 32 bit value to Local APIC
+ * register space.
+ *
+ * @ci: Target processor
+ * @reg: Register to write to.
+ * @val: Value to write
+ */
+static inline void
+lapic_writel(const struct mdcore *core, uint32_t reg, uint64_t val)
+{
+ void *addr;
+
+ if (!core->x2apic) {
+ addr = PTR_OFFSET(core->lapic_base, reg);
+ mmio_write32(addr, val);
+ } else {
+ reg >>= 4;
+ wrmsr(x2APIC_MSR_BASE + reg, val);
+ }
+}
+
+/*
+ * Hardware and software enable the Local APIC
+ * through IA32_APIC_BASE_MSR and the SVR.
+ *
+ * @ci: Current processor
+ */
+static inline void
+lapic_enable(const struct mdcore *core)
+{
+ uint64_t tmp;
+
+ /* Hardware enable the Local APIC */
+ tmp = rdmsr(IA32_APIC_BASE_MSR);
+ tmp |= core->x2apic << x2APIC_ENABLE_SHIFT;
+ wrmsr(IA32_APIC_BASE_MSR, tmp | LAPIC_HW_ENABLE);
+
+ /* Software enable the Local APIC */
+ tmp = lapic_readl(core, LAPIC_SVR);
+ lapic_writel(core, LAPIC_SVR, tmp | LAPIC_SW_ENABLE);
+}
+
+void
+lapic_init(void)
+{
+ struct pcore *core = this_core();
+ struct mdcore *mdcore;
+
+ if (__unlikely(core == NULL)) {
+ panic("lapic_init: unable to get current core\n");
+ }
+
+ mdcore = &core->md;
+ bsp_trace("detected lapic0 @ core %d\n", core->id);
+ mdcore->x2apic = lapic_has_x2apic();
+
+ /* If we can, put the chip in x2APIC mode on startup */
+ lapic_enable(mdcore);
+ bsp_trace("lapic0 enabled in %sapic mode\n", mdcore->x2apic ? "x2" : "x");
+}
diff --git a/src/sys/include/arch/amd64/cpuid.h b/src/sys/include/arch/amd64/cpuid.h
new file mode 100644
index 0000000..94ffcbb
--- /dev/null
+++ b/src/sys/include/arch/amd64/cpuid.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2025 Ian Marco Moffett and L5 engineers
+ * 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 the project 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.
+ */
+
+#ifndef _MACHINE_CPUID_H_
+#define _MACHINE_CPUID_H_ 1
+
+#include <sys/cdefs.h>
+
+#define CPUID(level, a, b, c, d) \
+ __ASMV("cpuid\n\t" \
+ : "=a" (a), "=b" (b), "=c" (c), "=d" (d) \
+ : "0" (level))
+
+#endif /* !_MACHINE_CPUID_H_ */
diff --git a/src/sys/include/arch/amd64/lapic.h b/src/sys/include/arch/amd64/lapic.h
new file mode 100644
index 0000000..d73e7d0
--- /dev/null
+++ b/src/sys/include/arch/amd64/lapic.h
@@ -0,0 +1,40 @@
+
+/*
+ * Copyright (c) 2025 Ian Marco Moffett and L5 engineers
+ * 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 the project 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.
+ */
+
+#ifndef _MACHINE_LAPIC_H_
+#define _MACHINE_LAPIC_H_ 1
+
+/*
+ * Initialize the local APIC on the current
+ * processor.
+ */
+void lapic_init(void);
+
+#endif /* !_MACHINE_LAPIC_H_ */
diff --git a/src/sys/include/arch/amd64/lapicregs.h b/src/sys/include/arch/amd64/lapicregs.h
new file mode 100644
index 0000000..468556c
--- /dev/null
+++ b/src/sys/include/arch/amd64/lapicregs.h
@@ -0,0 +1,108 @@
+/*
+ * Copyright (c) 2025 Ian Marco Moffett and L5 engineers
+ * 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 the project 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.
+ */
+
+/*
+ * Description: Local register interface definitions
+ * Author: Ian Marco Moffett
+ */
+
+#ifndef _MACHINE_LAPICREGS_H_
+#define _MACHINE_LAPICREGS_H_ 1
+
+#include <sys/param.h>
+#include <sys/cdefs.h>
+#include <vm/vm.h>
+
+#define _LAPIC_MMIO_BASE 0xFEE00000
+
+/* LAPIC register offsets */
+#define LAPIC_ID 0x0020U /* ID Register */
+#define LAPIC_VERSION 0x0030U /* Version Register */
+#define LAPIC_TPR 0x0080U /* Task Priority Register */
+#define LAPIC_APR 0x0090U /* Arbitration Priority Register */
+#define LAPIC_PPR 0x00A0U /* Processor Priority Register */
+#define LAPIC_EOI 0x00B0U /* End Of Interrupt Register */
+#define LAPIC_RRD 0x00C0U /* Remote Read Register */
+#define LAPIC_LDR 0x00D0U /* Logical Destination Register */
+#define LAPIC_DFR 0x00E0U /* Destination Format Register */
+#define LAPIC_SVR 0x00F0U /* Spurious Vector Register */
+#define LAPIC_ISR 0x0100U /* In service register (max=0x0220) */
+#define LAPIC_TMR 0x0180U /* Trigger Mode Register (max=0x0220) */
+#define LAPIC_IRR 0x0200U /* Interrupt Request Register (max=0x0270) */
+#define LAPIC_ERR 0x0280U /* Error Status Register */
+#define LAPIC_ICRLO 0x0300U /* Interrupt Command Low Register */
+#define LAPIC_ICRHI 0x0310U /* Interrupt Command High Register */
+#define LAPIC_LVT_TMR 0x0320U /* LVT Timer Register */
+#define LAPIC_DCR 0x03E0U /* Divide Configuration Register (for timer) */
+#define LAPIC_INIT_CNT 0x0380U /* Initial Count Register (for timer) */
+#define LAPIC_CUR_CNT 0x0390U /* Current Count Register (for timer) */
+
+/*
+ * The x2APIC register space is accessed via
+ * RDMSR/WRMSR instructions. The below defines
+ * the base MSR address for the register space.
+ */
+#define x2APIC_MSR_BASE 0x00000800
+
+/*
+ * To hardware enable, OR the value of the IA32_APIC_BASE
+ * MSR with LAPIC_HW_ENABLE and rewrite it.
+ *
+ * To software enable, OR the value of the SVR with
+ * LAPIC_SW_ENABLE and rewrite it.
+ *
+ * LAPIC_SW_ENABLE has the low 8 bits set as some hardware
+ * requires the spurious vector to be hardwired to 1s so
+ * we'll go with that to be safe.
+ */
+#define LAPIC_HW_ENABLE BIT(11)
+#define LAPIC_SW_ENABLE (BIT(8) | 0xFF)
+#define x2APIC_ENABLE_SHIFT 10
+
+/* LVT bits */
+#define LAPIC_LVT_MASK BIT(16)
+#define LVT_TMR_ONESHOT 0x00
+#define LVT_TMR_PERIODIC 0x01
+#define LVT_TMR_TSC_DEADLINE 0x02
+
+/*
+ * Convert a APIC destination ID into a MMIO
+ * base address for the Local APIC register
+ * space of that target processor
+ */
+__always_inline static void *
+lapic_base(uint8_t apic_id)
+{
+ uint64_t base = _LAPIC_MMIO_BASE;
+
+ base |= (apic_id & 0xFF) << 12;
+ return PHYS_TO_VIRT(base);
+}
+
+#endif /* !_MACHINE_LAPICREGS_H_ */
diff --git a/src/sys/include/arch/amd64/mdcpu.h b/src/sys/include/arch/amd64/mdcpu.h
index c38aae2..0a39eb4 100644
--- a/src/sys/include/arch/amd64/mdcpu.h
+++ b/src/sys/include/arch/amd64/mdcpu.h
@@ -41,10 +41,17 @@
/*
* Represents the machine dependent information
* of a processor core on the machine.
+ *
+ * @apic_id: Local APIC ID
+ * @cr3: CR3 register value (PML<n> phys)
+ * @lapic_base: LAPIC register interface base
+ * @x2apic: Has the x2APIC? Is 1 if true
*/
struct mdcore {
uint32_t apic_id;
uint64_t cr3;
+ void *lapic_base;
+ uint8_t x2apic : 1;
};
#endif /* !_MACHINE_MDCPU_H_ */