diff options
author | Ian Moffett <ian@osmora.org> | 2025-09-15 12:31:08 -0400 |
---|---|---|
committer | Ian Moffett <ian@osmora.org> | 2025-09-15 12:31:08 -0400 |
commit | 6bd92c969a6f4aefee258adc79a3ab0bde9443b2 (patch) | |
tree | 34ccbfba395827ce6975972704a52d43592803e5 /src | |
parent | 4122de881d3b7f9e54563affd7564213d415d1e5 (diff) |
kern/amd64: lapic: Initialize percore Local APIC
Signed-off-by: Ian Moffett <ian@osmora.org>
Diffstat (limited to 'src')
-rw-r--r-- | src/sys/arch/amd64/cpu/cpu_conf.c | 2 | ||||
-rw-r--r-- | src/sys/arch/amd64/cpu/cpu_lapic.c | 174 | ||||
-rw-r--r-- | src/sys/include/arch/amd64/cpuid.h | 40 | ||||
-rw-r--r-- | src/sys/include/arch/amd64/lapic.h | 40 | ||||
-rw-r--r-- | src/sys/include/arch/amd64/lapicregs.h | 108 | ||||
-rw-r--r-- | src/sys/include/arch/amd64/mdcpu.h | 7 |
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_ */ |