From 98ccb3a2d41015b42d46d8b382decc755a003c3f Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 13:41:11 -0400 Subject: project: Initial commit Signed-off-by: Ian Moffett --- sys/include/arch/amd64/asm.h | 113 ++++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/cpu.h | 43 +++++++++++++++ sys/include/arch/amd64/cpuid.h | 40 ++++++++++++++ sys/include/arch/amd64/frame.h | 61 ++++++++++++++++++++ sys/include/arch/amd64/frameasm.h | 103 ++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/gdt.h | 47 ++++++++++++++++ sys/include/arch/amd64/idt.h | 68 +++++++++++++++++++++++ sys/include/arch/amd64/msr.h | 63 +++++++++++++++++++++ sys/include/arch/amd64/pio.h | 43 +++++++++++++++ sys/include/arch/amd64/trap.h | 68 +++++++++++++++++++++++ 10 files changed, 649 insertions(+) create mode 100644 sys/include/arch/amd64/asm.h create mode 100644 sys/include/arch/amd64/cpu.h create mode 100644 sys/include/arch/amd64/cpuid.h create mode 100644 sys/include/arch/amd64/frame.h create mode 100644 sys/include/arch/amd64/frameasm.h create mode 100644 sys/include/arch/amd64/gdt.h create mode 100644 sys/include/arch/amd64/idt.h create mode 100644 sys/include/arch/amd64/msr.h create mode 100644 sys/include/arch/amd64/pio.h create mode 100644 sys/include/arch/amd64/trap.h (limited to 'sys/include/arch') diff --git a/sys/include/arch/amd64/asm.h b/sys/include/arch/amd64/asm.h new file mode 100644 index 0000000..d7334fe --- /dev/null +++ b/sys/include/arch/amd64/asm.h @@ -0,0 +1,113 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_ASM_H_ +#define _MACHINE_ASM_H_ + +#include +#include +#include + +/* + * Contains information for the current + * core. Stored in %GS. + * + * MUST REMAIN IN ORDER!!! + */ +struct cpu_ctx { + struct cpu_info *ci; +}; + +/* + * Returns true for this core if maskable + * interrupts are masked (CLI) and false if + * they aren't (STI). + */ +static inline bool +amd64_is_intr_mask(void) +{ + uint64_t flags; + + __ASMV("pushfq; pop %0" : "=rm" (flags) :: "memory"); + return !ISSET(flags, BIT(9)); +} + +static inline void +amd64_write_gs_base(uintptr_t val) +{ + wrmsr(IA32_KERNEL_GS_BASE, val); +} + +static inline uintptr_t +amd64_read_gs_base(void) +{ + return rdmsr(IA32_KERNEL_GS_BASE); +} + +static inline uint64_t +amd64_read_cr0(void) +{ + uint64_t cr0; + __ASMV("mov %%cr0, %0" : "=r" (cr0) :: "memory"); + return cr0; +} + +static inline void +amd64_write_cr0(uint64_t val) +{ + __ASMV("mov %0, %%cr0" :: "r" (val) : "memory"); +} + +static inline uint64_t +amd64_read_cr4(void) +{ + uint64_t cr4; + __ASMV("mov %%cr4, %0" : "=r" (cr4) :: "memory"); + return cr4; +} + +static inline void +amd64_write_cr4(uint64_t val) +{ + __ASMV("mov %0, %%cr4" :: "r" (val) : "memory"); +} + +static inline void +amd64_fxsave(void *area) +{ + __ASMV("fxsave (%0)" :: "r" (area) : "memory"); +} + +static inline void +amd64_fxrstor(void *area) +{ + __ASMV("fxrstor (%0)" :: "r" (area) : "memory"); +} + +#endif diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h new file mode 100644 index 0000000..efa60ad --- /dev/null +++ b/sys/include/arch/amd64/cpu.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_CPU_H_ +#define _MACHINE_CPU_H_ + +#include +#include + +struct cpu_info { + uint32_t apicid; +}; + +void cpu_startup(void); + + +#endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/include/arch/amd64/cpuid.h b/sys/include/arch/amd64/cpuid.h new file mode 100644 index 0000000..d1a752b --- /dev/null +++ b/sys/include/arch/amd64/cpuid.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_CPUID_H_ +#define _MACHINE_CPUID_H_ + +#include + +#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/sys/include/arch/amd64/frame.h b/sys/include/arch/amd64/frame.h new file mode 100644 index 0000000..a132e4c --- /dev/null +++ b/sys/include/arch/amd64/frame.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_FRAME_H_ +#define _MACHINE_FRAME_H_ + +#include + +struct trapframe { + uint64_t trapno; + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsi; + uint64_t rdi; + uint64_t rbp; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + /* Pushed by hardware */ + uint64_t error_code; + uint64_t rip; + uint64_t cs; + uint64_t rflags; + uint64_t rsp; + uint64_t ss; +}; + +#endif /* !_MACHINE_FRAME_H_ */ diff --git a/sys/include/arch/amd64/frameasm.h b/sys/include/arch/amd64/frameasm.h new file mode 100644 index 0000000..b6d4f39 --- /dev/null +++ b/sys/include/arch/amd64/frameasm.h @@ -0,0 +1,103 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_FRAMEASM_H_ +#define _MACHINE_FRAMEASM_H_ + +/* + * If the interrupt has an error code, this macro shall + * be used to create the trapframe. + * + * XXX: A trapframe created with this must be popped with + * pop_trapframe_ec + */ +.macro push_trapframe_ec trapno + push %r15 + push %r14 + push %r13 + push %r12 + push %r11 + push %r10 + push %r9 + push %r8 + push %rbp + push %rdi + push %rsi + push %rbx + push %rdx + push %rcx + push %rax + push \trapno +.endm + +/* + * If the interrupt has an error code, this macro shall + * be used to cleanup the trapframe. + */ +.macro pop_trapframe_ec + add $8, %rsp /* Trapno */ + pop %rax + pop %rcx + pop %rdx + pop %rbx + pop %rsi + pop %rdi + pop %rbp + pop %r8 + pop %r9 + pop %r10 + pop %r11 + pop %r12 + pop %r13 + pop %r14 + pop %r15 +.endm + +/* + * If the interrupt has no error code, this macro + * shall be used to create the trapframe. + * + * XXX: A trapframe created with this must be popped + * with pop_trapframe + */ +.macro push_trapframe trapno + push $0 + push_trapframe_ec \trapno +.endm + + +/* + * If the interrupt has no error code, this macro shall + * be used to cleanup the trapframe. + */ +.macro pop_trapframe + pop_trapframe_ec + add $8, %rsp /* Pop error code */ +.endm +#endif /* !_MACHINE_FRAMEASM_H_ */ diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h new file mode 100644 index 0000000..6f8a914 --- /dev/null +++ b/sys/include/arch/amd64/gdt.h @@ -0,0 +1,47 @@ +#ifndef _AMD64_GDT_H_ +#define _AMD64_GDT_H_ + +#include +#include + +#define KERNEL_CS 0x08 +#define KERNEL_DS 0x10 + +struct __packed gdt_entry { + uint16_t limit; + uint16_t base_low; + uint8_t base_mid; + uint8_t access; + uint8_t granularity; + uint8_t base_hi; +}; + +struct __packed gdtr { + uint16_t limit; + uintptr_t offset; +}; + +__always_inline static inline void +gdt_load(struct gdtr *gdtr) +{ + __ASMV("lgdt %0\n" + "push $8\n" /* Push CS */ + "lea 1f(%%rip), %%rax\n" /* Load 1 label address into RAX */ + "push %%rax\n" /* Push the return address (label 1) */ + "lretq\n" /* Far return to update CS */ + "1:\n" + " mov $0x10, %%eax\n" + " mov %%eax, %%ds\n" + " mov %%eax, %%es\n" + " mov %%eax, %%fs\n" + " mov %%eax, %%gs\n" + " mov %%eax, %%ss\n" + : + : "m" (*gdtr) + : "rax", "memory" + ); +} + +extern struct gdt_entry g_gdt_data[256]; + +#endif /* !AMD64_GDT_H_ */ diff --git a/sys/include/arch/amd64/idt.h b/sys/include/arch/amd64/idt.h new file mode 100644 index 0000000..7f439f3 --- /dev/null +++ b/sys/include/arch/amd64/idt.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_IDT_H_ +#define _MACHINE_IDT_H_ + +#include +#include + +#define IDT_TRAP_GATE 0x8F +#define IDT_INT_GATE 0x8E +#define IDT_USER_INT_GATE 0xEE + +#define ISR(p) ((uintptr_t)p) + +/* + * AMD64 Interrupt Gate Descriptor. + */ +struct idt_entry { + uint16_t off_lo; /* Low 16 bits of ISR offset */ + uint16_t segsel; /* Segment selector, hardcode to kernel CS */ + uint8_t ist : 2; /* Interrupt stack table */ + uint8_t zero : 1; /* Unused: keep zero */ + uint8_t zero1 : 4; /* Unused: keep zero */ + uint8_t type : 4; /* Gate type */ + uint8_t zero2 : 1; /* Unused: keep zero */ + uint8_t dpl : 2; /* Descriptor privilege level */ + uint8_t p : 1; /* Present (keep 1 to mark as valid) */ + uint16_t off_mid; /* Middle 16 bits of ISR offset */ + uint32_t off_hi; /* High 32-bits of ISR offset */ + uint32_t reserved; /* Reserved: keep zero */ +}; + +struct __packed idtr { + uint16_t limit; + uintptr_t offset; +}; + +void idt_set_desc(uint8_t vector, uint8_t type, uintptr_t isr, uint8_t ist); +void idt_load(void); + +#endif /* !_MACHINE_IDT_H_ */ diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h new file mode 100644 index 0000000..bc0dbcb --- /dev/null +++ b/sys/include/arch/amd64/msr.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_MSR_H_ +#define _MACHINE_MSR_H_ + +#define IA32_SPEC_CTL 0x00000048 +#define IA32_KERNEL_GS_BASE 0xC0000102 + +static inline uint64_t +rdmsr(uint32_t msr_addr) +{ + uint32_t lo, hi; + + __ASMV("rdmsr" + : "=a" (lo), "=d" (hi) + : "c" (msr_addr) + ); + return ((uint64_t)hi << 32) | lo; +} + +static inline void +wrmsr(uint32_t msr_addr, uint64_t value) +{ + uint32_t lo, hi; + + lo = (uint32_t)value; + hi = (uint32_t)(value >> 32); + + __ASMV("wrmsr" + : /* No outputs */ + : "a" (lo), "d" (hi), + "c" (msr_addr) + ); +} + +#endif /* !_MACHINE_MSR_H_ */ diff --git a/sys/include/arch/amd64/pio.h b/sys/include/arch/amd64/pio.h new file mode 100644 index 0000000..193e986 --- /dev/null +++ b/sys/include/arch/amd64/pio.h @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_PIO_H_ +#define _MACHINE_PIO_H_ + +#include + +uint8_t inb(uint16_t port); +uint16_t inw(uint16_t port); +uint32_t inl(uint16_t port); + +void outb(uint16_t port, uint8_t val); +void outw(uint16_t port, uint16_t val); +void outl(uint16_t port, uint32_t val); + +#endif /* !_MACHINE_PIO_H_ */ diff --git a/sys/include/arch/amd64/trap.h b/sys/include/arch/amd64/trap.h new file mode 100644 index 0000000..deeb738 --- /dev/null +++ b/sys/include/arch/amd64/trap.h @@ -0,0 +1,68 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_TRAP_H_ +#define _MACHINE_TRAP_H_ + +#if !defined(__ASSEMBLER__) +#include +#endif + +#define TRAP_NONE 0 /* Used for general interrupts */ +#define TRAP_BREAKPOINT 1 /* Breakpoint */ +#define TRAP_ARITH_ERR 2 /* Arithmetic error (e.g division by 0) */ +#define TRAP_OVERFLOW 3 /* Overflow */ +#define TRAP_BOUND_RANGE 4 /* BOUND range exceeded */ +#define TRAP_INVLOP 5 /* Invalid opcode */ +#define TRAP_DOUBLE_FAULT 6 /* Double fault */ +#define TRAP_INVLTSS 7 /* Invalid TSS */ +#define TRAP_SEGNP 8 /* Segment not present */ +#define TRAP_PROTFLT 9 /* General protection */ +#define TRAP_PAGEFLT 10 /* Page fault */ +#define TRAP_NMI 11 /* Non-maskable interrupt */ +#define TRAP_SS 12 /* Stack-segment fault */ + +#if !defined(__ASSEMBLER__) + +void breakpoint_handler(void *sf); +void arith_err(void *sf); +void overflow(void *sf); +void bound_range(void *sf); +void invl_op(void *sf); +void double_fault(void *sf); +void invl_tss(void *sf); +void segnp(void *sf); +void general_prot(void *sf); +void page_fault(void *sf); +void nmi(void *sf); +void ss_fault(void *sf); +void trap_handler(struct trapframe *tf); + +#endif /* !__ASSEMBLER__ */ +#endif /* !_MACHINE_TRAP_H_ */ -- cgit v1.2.3 From 7c29fb70b00315bba95fa2a8b044e88a8d0b32d1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 15:52:13 -0400 Subject: kernel/amd64: Add HPET driver Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/hpet.c | 186 ++++++++++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_init.c | 11 +++ sys/include/arch/amd64/hpet.h | 37 +++++++++ 3 files changed, 234 insertions(+) create mode 100644 sys/arch/amd64/amd64/hpet.c create mode 100644 sys/include/arch/amd64/hpet.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/hpet.c b/sys/arch/amd64/amd64/hpet.c new file mode 100644 index 0000000..860e610 --- /dev/null +++ b/sys/arch/amd64/amd64/hpet.c @@ -0,0 +1,186 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include + +#define pr_trace(fmt, ...) kprintf("hpet: " fmt, ##__VA_ARGS__) +#define pr_error(fmt, ...) pr_trace(__VA_ARGS__) + +#define HPET_REG_CAPS 0x00 +#define HPET_GENERAL_CONFIG 0x10 +#define HPET_REG_MAIN_COUNTER 0xF0 + +#define CAP_REV_ID(caps) (caps & 0xFF) +#define CAP_NUM_TIM(caps) (caps >> 8) & 0x1F +#define CAP_CLK_PERIOD(caps) (caps >> 32) + +#define FSEC_PER_SECOND 1000000000000000ULL +#define USEC_PER_SECOND 1000000ULL + +static void *hpet_base = NULL; +static struct timer timer = {0}; + +/* + * Read from HPET register space. + * + * @reg: Register to read from. + */ +static inline uint64_t +hpet_read(uint32_t reg) +{ + void *addr; + + addr = (void *)((uintptr_t)hpet_base + reg); + return mmio_read64(addr); +} + +/* + * Write to HPET register space. + * + * @reg: Register to write to. + * @val: Value to write. + */ +static inline void +hpet_write(uint32_t reg, uint64_t val) +{ + void *addr; + + addr = (void *)((uintptr_t)hpet_base + reg); + mmio_write64(addr, val); +} + +static int +hpet_sleep(uint64_t n, uint64_t units) +{ + uint64_t caps; + uint32_t period; + uint64_t counter_val; + volatile size_t ticks; + + caps = hpet_read(HPET_REG_CAPS); + period = CAP_CLK_PERIOD(caps); + counter_val = hpet_read(HPET_REG_MAIN_COUNTER); + + ticks = counter_val + (n * (units / period)); + + while (hpet_read(HPET_REG_MAIN_COUNTER) < ticks) { + __ASMV("rep; nop"); + } + + return 0; +} + +static int +hpet_msleep(size_t ms) +{ + return hpet_sleep(ms, 1000000000000); +} + +static int +hpet_usleep(size_t us) +{ + return hpet_sleep(us, 1000000000); +} + +static int +hpet_nsleep(size_t ns) +{ + return hpet_sleep(ns, 1000000); +} + +static size_t +hpet_time_usec(void) +{ + uint64_t period, freq, caps; + uint64_t counter; + + caps = hpet_read(HPET_REG_CAPS); + period = CAP_CLK_PERIOD(caps); + freq = FSEC_PER_SECOND / period; + + counter = hpet_read(HPET_REG_MAIN_COUNTER); + return (counter * USEC_PER_SECOND) / freq; +} + +static size_t +hpet_time_sec(void) +{ + return hpet_time_usec() / USEC_PER_SECOND; +} + +int +hpet_init(void) +{ + struct acpi_gas *gas; + struct acpi_hpet *hpet; + uint64_t caps; + + hpet = acpi_query("HPET"); + if (hpet == NULL) + return -1; + + gas = &hpet->gas; + hpet_base = (void *)gas->address; + + /* Ensure caps aren't bogus */ + caps = hpet_read(HPET_REG_CAPS); + if (CAP_REV_ID(caps) == 0) { + pr_error("Found bogus revision, assuming faulty\n"); + return -1; + } + if (CAP_CLK_PERIOD(caps) > 0x05F5E100) { + /* + * The spec states this counter clk period must + * be <= 0x05F5E100. So we'll consider it as bogus + * if it exceeds this value + */ + pr_error("Found bogus COUNTER_CLK_PERIOD, assuming faulty\n"); + return 1; + } + + pr_trace("HPET integrity verified\n"); + hpet_write(HPET_REG_MAIN_COUNTER, 0); + hpet_write(HPET_GENERAL_CONFIG, 1); + + /* Setup timer descriptor */ + timer.name = "HIGH_PRECISION_EVENT_TIMER"; + timer.msleep = hpet_msleep; + timer.usleep = hpet_usleep; + timer.nsleep = hpet_nsleep; + timer.get_time_usec = hpet_time_usec; + timer.get_time_sec = hpet_time_sec; + register_timer(TIMER_GP, &timer); + return 0; +} diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c index a8423e4..f445d95 100644 --- a/sys/dev/acpi/acpi_init.c +++ b/sys/dev/acpi/acpi_init.c @@ -48,6 +48,16 @@ static volatile struct limine_rsdp_request rsdp_req = { .revision = 0 }; +static void +acpi_init_hpet(void) +{ +#if defined(__x86_64__) + if (hpet_init() != 0) { + panic("Could not init HPET\n"); + } +#endif +} + /* * Writes out OEMID of ACPI header. * @@ -107,4 +117,5 @@ acpi_init(void) } root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; + acpi_init_hpet(); } diff --git a/sys/include/arch/amd64/hpet.h b/sys/include/arch/amd64/hpet.h new file mode 100644 index 0000000..0ebc96b --- /dev/null +++ b/sys/include/arch/amd64/hpet.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_HPET_H_ +#define _MACHINE_HPET_H_ + +#include + +int hpet_init(void); + +#endif /* !_MACHINE_HPET_H_ */ -- cgit v1.2.3 From 955d6a381f53c234ce1f4d52aa57f183ed9a6e65 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 22:13:30 -0400 Subject: kernel/amd64: Support IBRS Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/machdep.c | 19 +++++++++++++++ sys/arch/amd64/amd64/spectre.S | 53 ++++++++++++++++++++++++++++++++++++++++++ sys/arch/amd64/conf/GENERIC | 3 ++- sys/include/arch/amd64/msr.h | 2 ++ 4 files changed, 76 insertions(+), 1 deletion(-) create mode 100644 sys/arch/amd64/amd64/spectre.S (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 19ba28a..275c23e 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -35,6 +35,14 @@ #include #include +#if defined(__SPECTRE_IBRS) +#define SPECTRE_IBRS __SPECTRE_IBRS +#else +#define SPECTRE_IBRS 0 +#endif + +int ibrs_enable(void); + static struct cpu_info g_bsp_ci = {0}; static struct gdtr bsp_gdtr = { .limit = sizeof(struct gdt_entry) * 256 - 1, @@ -58,6 +66,16 @@ setup_vectors(void) idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0); } +static void +try_mitigate_spectre(void) +{ + if (!SPECTRE_IBRS) { + return; + } + + ibrs_enable(); +} + void cpu_startup(void) { @@ -66,4 +84,5 @@ cpu_startup(void) setup_vectors(); amd64_write_gs_base((uintptr_t)&g_bsp_ci); + try_mitigate_spectre(); } diff --git a/sys/arch/amd64/amd64/spectre.S b/sys/arch/amd64/amd64/spectre.S new file mode 100644 index 0000000..6781cbd --- /dev/null +++ b/sys/arch/amd64/amd64/spectre.S @@ -0,0 +1,53 @@ +/* + * Copyright (c) 2023-2024 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 + + .text + .globl ibrs_enable + .type ibrs_enable, @function +ibrs_enable: + /* See if it is supported */ + mov $7, %eax + xor %ecx, %ecx + cpuid + bt $26, %edx + jnc fail + + /* Now we enable it */ + mov $IA32_SPEC_CTL, %ecx + rdmsr + or $1, %eax + wrmsr + xor %rax, %rax + jmp 1f +fail: + mov $1, %rax +1: + retq diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index 70b786d..1a48a94 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1 +1,2 @@ -// TODO +// Kernel options +option SPECTRE_IBRS yes diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h index bc0dbcb..6ad95f1 100644 --- a/sys/include/arch/amd64/msr.h +++ b/sys/include/arch/amd64/msr.h @@ -33,6 +33,7 @@ #define IA32_SPEC_CTL 0x00000048 #define IA32_KERNEL_GS_BASE 0xC0000102 +#if !defined(__ASSEMBLER__) static inline uint64_t rdmsr(uint32_t msr_addr) { @@ -60,4 +61,5 @@ wrmsr(uint32_t msr_addr, uint64_t value) ); } +#endif /* !__ASSEMBLER__ */ #endif /* !_MACHINE_MSR_H_ */ -- cgit v1.2.3 From b7b304843f34b9f7d9c36d0603874f5050f5d83a Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 22:18:32 -0400 Subject: kernel/amd64: Add I/O APIC driver Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/acpi_machdep.c | 3 + sys/arch/amd64/amd64/ioapic.c | 230 ++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/ioapic.h | 44 +++++++ sys/include/arch/amd64/ioapicvar.h | 28 +++++ 4 files changed, 305 insertions(+) create mode 100644 sys/arch/amd64/amd64/ioapic.c create mode 100644 sys/include/arch/amd64/ioapic.h create mode 100644 sys/include/arch/amd64/ioapicvar.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index 5f3b3bf..d1686df 100644 --- a/sys/arch/amd64/amd64/acpi_machdep.c +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -32,6 +32,7 @@ #include #include #include +#include #define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) @@ -64,6 +65,8 @@ acpi_init_madt(void) ioapic = (struct ioapic *)cur; pr_trace("Detected I/O APIC (id=%d, gsi_base=%d)\n", ioapic->ioapic_id, ioapic->gsi_base); + + ioapic_init((void *)(uintptr_t)ioapic->ioapic_addr); } cur += apichdr->length; diff --git a/sys/arch/amd64/amd64/ioapic.c b/sys/arch/amd64/amd64/ioapic.c new file mode 100644 index 0000000..39bf8f8 --- /dev/null +++ b/sys/arch/amd64/amd64/ioapic.c @@ -0,0 +1,230 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include + +#define pr_trace(fmt, ...) kprintf("ioapic: " fmt, ##__VA_ARGS__) +#define IOAPIC_BASE_OFF(off) ((void *)((uintptr_t)ioapic_base + off)) + +static void *ioapic_base = NULL; +static struct acpi_madt *madt = NULL; + +/* + * Converts IRQ numbers to its corresponding + * Global System Interrupt (GSI) number. + * + * @irq: IRQ number. + */ +static uint32_t +irq_to_gsi(uint8_t irq) +{ + struct apic_header *hdr = NULL; + struct interrupt_override *override = NULL; + uint8_t *cur = NULL; + uint8_t *end = NULL; + + if (madt == NULL) + madt = acpi_query("APIC"); + if (madt == NULL) + panic("Failed to fetch MADT\n"); + + cur = (uint8_t *)(madt + 1); + end = (uint8_t *)madt + madt->hdr.length; + + while (cur < end) { + hdr = (void *)cur; + + if (hdr->type == APIC_TYPE_INTERRUPT_OVERRIDE) { + override = (struct interrupt_override *)cur; + if (override->source == irq) { + return override->interrupt; + } + } + + cur += hdr->length; + } + + return irq; +} + +/* + * Reads a 32 bit value from the IOAPIC + * register space. + * + * @reg: Register to read from. + */ +static uint32_t +ioapic_readl(uint16_t reg) +{ + mmio_write32(IOAPIC_BASE_OFF(IOREGSEL), reg); + return mmio_read32(IOAPIC_BASE_OFF(IOWIN)); +} + +/* + * Writes a 32 bit value to the IOAPIC + * register space. + * + * @reg: Register to write to. + * @val: Value to write. + */ +static void +ioapic_writel(uint16_t reg, uint32_t val) +{ + mmio_write32(IOAPIC_BASE_OFF(IOREGSEL), reg); + mmio_write32(IOAPIC_BASE_OFF(IOWIN), val); +} + +/* + * Reads an I/O APIC redirection entry. + * + * @entry: Entry variable to read into. + * @index: Index to read. + */ +static void +ioapic_read_redentry(union ioapic_redentry *entry, uint8_t index) +{ + uint32_t lo, hi; + + lo = ioapic_readl(IOREDTBL + index * 2); + hi = ioapic_readl(IOREDTBL + index * 2 + 1); + entry->value = ((uint64_t)hi << 32) | lo; +} + +/* + * Writes an I/O APIC redirection entry. + * + * @entry: Entry variable to write. + * @index: Index to write to. + */ +static void +ioapic_write_redentry(const union ioapic_redentry *entry, uint8_t index) +{ + ioapic_writel(IOREDTBL + index * 2, (uint32_t)entry->value); + ioapic_writel(IOREDTBL + index * 2 + 1, (uint32_t)(entry->value >> 32)); +} + +/* + * Mask I/O APIC pin with "raw" pin number + * (Global System Interrupt) + * + * @gsi: Global System Interrupt number + */ +void +ioapic_gsi_mask(uint8_t gsi) +{ + union ioapic_redentry redentry; + + ioapic_read_redentry(&redentry, gsi); + redentry.interrupt_mask = 1; + ioapic_write_redentry(&redentry, gsi); +} + +/* + * Unmask I/O APIC pin with "raw" pin number + * (Global System Interrupt) + * + * @gsi: Global System Interrupt number + */ +void +ioapic_gsi_unmask(uint8_t gsi) +{ + union ioapic_redentry redentry; + + ioapic_read_redentry(&redentry, gsi); + redentry.interrupt_mask = 0; + ioapic_write_redentry(&redentry, gsi); +} + +/* + * Masks I/O APIC pin via IRQ number + * + * @irq: Interrupt Request number + */ +void +ioapic_irq_mask(uint8_t irq) +{ + uint8_t gsi = irq_to_gsi(irq); + ioapic_gsi_mask(gsi); +} + +/* + * Unmasks I/O APIC pin via IRQ number + * + * @irq: Interrupt Request number + */ +void +ioapic_irq_unmask(uint8_t irq) +{ + uint8_t gsi = irq_to_gsi(irq); + ioapic_gsi_unmask(gsi); +} + +/* + * Assign an interrupt vector to a redirection + * entry. + * + * @irq: IRQ number to assign vector to. + * @vector: Vector assign. + */ +void +ioapic_set_vec(uint8_t irq, uint8_t vector) +{ + union ioapic_redentry redentry; + uint8_t gsi = irq_to_gsi(irq); + + ioapic_read_redentry(&redentry, gsi); + redentry.vector = vector; + ioapic_write_redentry(&redentry, gsi); +} + +void +ioapic_init(void *base) +{ + size_t tmp; + uint8_t redir_ent_cnt, ver; + + ioapic_base = base; + tmp = ioapic_readl(IOAPICVER); + ver = tmp & 0xFF; + redir_ent_cnt = ((tmp >> 16) & 0xFF) + 1; + + pr_trace("version=%d, address=0x%x\n", ver, base); + pr_trace("Masking %d GSIs...\n", redir_ent_cnt); + + for (uint8_t i = 0; i < redir_ent_cnt; ++i) { + ioapic_gsi_mask(i); + } +} diff --git a/sys/include/arch/amd64/ioapic.h b/sys/include/arch/amd64/ioapic.h new file mode 100644 index 0000000..4a0479f --- /dev/null +++ b/sys/include/arch/amd64/ioapic.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_IOAPIC_H_ +#define _MACHINE_IOAPIC_H_ + +#include + +void ioapic_init(void *base); +void ioapic_gsi_mask(uint8_t gsi); + +void ioapic_gsi_unmask(uint8_t gsi); +void ioapic_irq_mask(uint8_t irq); + +void ioapic_irq_unmask(uint8_t irq); +void ioapic_set_vec(uint8_t irq, uint8_t vector); + +#endif /* !_MACHINE_IOAPIC_H_ */ diff --git a/sys/include/arch/amd64/ioapicvar.h b/sys/include/arch/amd64/ioapicvar.h new file mode 100644 index 0000000..d5a75df --- /dev/null +++ b/sys/include/arch/amd64/ioapicvar.h @@ -0,0 +1,28 @@ +#ifndef _MACHINE_IOAPICVAR_H_ +#define _MACHINE_IOAPICVAR_H_ + +#include + +/* Register offsets */ +#define IOREGSEL 0x00 +#define IOWIN 0x10 +#define IOAPICVER 0x01 +#define IOREDTBL 0x10 + +union ioapic_redentry { + struct { + uint8_t vector; + uint8_t delmod : 3; + uint8_t destmod : 1; + uint8_t delivs : 1; + uint8_t intpol : 1; + uint8_t remote_irr : 1; + uint8_t trigger_mode : 1; + uint8_t interrupt_mask : 1; + uint64_t reserved : 39; + uint8_t dest_field; + }; + uint64_t value; +}; + +#endif /* !_MACHINE_IOAPICVAR_H_ */ -- cgit v1.2.3 From dbfcd0e88e471564392549652d0bde2a967c34f4 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 5 Jun 2024 20:58:51 -0400 Subject: kernel/amd64: Add initial LAPIC code Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/acpi_machdep.c | 2 + sys/arch/amd64/amd64/lapic.c | 214 ++++++++++++++++++++++++++++++++++++ sys/arch/amd64/amd64/machdep.c | 13 +++ sys/include/arch/amd64/cpu.h | 3 +- sys/include/arch/amd64/lapic.h | 39 +++++++ sys/include/arch/amd64/lapicvar.h | 85 ++++++++++++++ sys/include/arch/amd64/msr.h | 1 + 7 files changed, 356 insertions(+), 1 deletion(-) create mode 100644 sys/arch/amd64/amd64/lapic.c create mode 100644 sys/include/arch/amd64/lapic.h create mode 100644 sys/include/arch/amd64/lapicvar.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c index d1686df..3bcdc9d 100644 --- a/sys/arch/amd64/amd64/acpi_machdep.c +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -33,6 +33,7 @@ #include #include #include +#include #define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) @@ -50,6 +51,7 @@ acpi_init_madt(void) cur = (uint8_t *)(madt + 1); end = (uint8_t *)madt + madt->hdr.length; + g_lapic_base = madt->lapic_addr; while (cur < end) { apichdr = (void *)cur; diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c new file mode 100644 index 0000000..f61715d --- /dev/null +++ b/sys/arch/amd64/amd64/lapic.c @@ -0,0 +1,214 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define pr_trace(fmt, ...) kprintf("lapic: " fmt, ##__VA_ARGS__) + +/* + * Only calls pr_trace if we are the BSP. + */ +#define bsp_trace(...) do { \ + uint64_t msr_val; \ + \ + msr_val = rdmsr(IA32_APIC_BASE_MSR); \ + if (ISSET(msr_val, BIT(8))) { \ + pr_trace(__VA_ARGS__); \ + } \ + } while (0); + +uintptr_t g_lapic_base = 0; + +/* + * Returns true if LAPIC is supported. + * + * LAPIC is supported if CPUID.(EAX=1H):EDX[9] == 1 + */ +static inline bool +lapic_supported(void) +{ + uint32_t eax, edx, tmp; + + CPUID(0x00000001, eax, tmp, tmp, edx); + return ISSET(edx, BIT(9)); +} + +/* + * Checks if the processor supports x2APIC + * mode. Returns true if so. + */ +static inline bool +lapic_has_x2apic(void) +{ + uint32_t ecx, tmp; + + CPUID(0x00000001, tmp, tmp, ecx, tmp); + return ISSET(ecx, BIT(21)); +} + +/* + * Reads a 32 bit value from Local APIC + * register space. + * + * @reg: Register to read from. + */ +static inline uint64_t +lapic_readl(uint32_t reg) +{ + void *addr; + const struct cpu_info *ci = this_cpu(); + + if (!ci->has_x2apic) { + addr = (void *)(g_lapic_base + reg); + return mmio_read32(addr); + } else { + reg >>= 4; + return rdmsr(x2APIC_MSR_BASE + reg); + } +} + +/* + * Writes a 32 bit value to Local APIC + * register space. + * + * @reg: Register to write to. + */ +static inline void +lapic_writel(uint32_t reg, uint64_t val) +{ + void *addr; + const struct cpu_info *ci = this_cpu(); + + if (!ci->has_x2apic) { + addr = (void *)(g_lapic_base + reg); + mmio_write32(addr, val); + } else { + reg >>= 4; + wrmsr(x2APIC_MSR_BASE + reg, val); + } +} + +/* + * Set bits within a LAPIC register + * without overwriting the whole thing. + * + * @reg: Reg with bits to be set. + * @value: Value in reg will be ORd with this. + */ +static inline void +lapic_reg_set(uint32_t reg, uint32_t value) +{ + uint32_t old; + + old = lapic_readl(reg); + lapic_writel(reg, old | value); +} + +/* + * Clear bits within a LAPIC register + * without overwriting the whole thing. + * + * @reg: Reg with bits to be cleared. + * @value: Value in reg will be cleared by this value. + */ +static inline void +lapic_reg_clear(uint32_t reg, uint32_t value) +{ + uint32_t old; + + old = lapic_readl(reg); + lapic_writel(reg, old & ~(value)); +} + +/* + * Hardware and software enable the Local APIC + * through IA32_APIC_BASE_MSR + */ +static inline void +lapic_enable(const struct cpu_info *ci) +{ + uint64_t tmp; + + /* Hardware enable the Local APIC */ + tmp = rdmsr(IA32_APIC_BASE_MSR); + tmp |= ci->has_x2apic << x2APIC_ENABLE_SHIFT; + wrmsr(IA32_APIC_BASE_MSR, tmp | LAPIC_HW_ENABLE); + + /* Software enable the Local APIC */ + lapic_reg_set(LAPIC_SVR, LAPIC_SW_ENABLE); +} + +/* + * Reads the Local APIC ID of the current + * processor. + */ +static inline uint32_t +lapic_read_id(const struct cpu_info *ci) +{ + if (!ci->has_x2apic) { + return (lapic_readl(LAPIC_ID) >> 24) & 0xF; + } else { + return lapic_readl(LAPIC_ID); + } +} + +void +lapic_init(void) +{ + struct cpu_info *ci = this_cpu(); + + /* + * Hyra currently depends on the existance + * of a Local APIC. + */ + if (!lapic_supported()) { + panic("This machine does not support LAPIC!\n"); + } + + /* Ensure the LAPIC base is valid */ + if (g_lapic_base == 0) { + panic("Invalid LAPIC base\n"); + } + + ci->has_x2apic = lapic_has_x2apic(); + lapic_enable(ci); + + ci->apicid = lapic_read_id(ci); + bsp_trace("BSP LAPIC enabled in %s mode (id=%d)\n", + ci->has_x2apic ? "x2APIC" : "xAPIC", ci->apicid); +} diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 275c23e..983a480 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -34,6 +34,7 @@ #include #include #include +#include #if defined(__SPECTRE_IBRS) #define SPECTRE_IBRS __SPECTRE_IBRS @@ -76,6 +77,16 @@ try_mitigate_spectre(void) ibrs_enable(); } +/* + * Get the descriptor for the currently + * running processor. + */ +struct cpu_info * +this_cpu(void) +{ + return (void *)amd64_read_gs_base(); +} + void cpu_startup(void) { @@ -84,5 +95,7 @@ cpu_startup(void) setup_vectors(); amd64_write_gs_base((uintptr_t)&g_bsp_ci); + try_mitigate_spectre(); + lapic_init(); } diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index efa60ad..4e5baf1 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -35,9 +35,10 @@ struct cpu_info { uint32_t apicid; + uint8_t has_x2apic : 1; }; void cpu_startup(void); - +struct cpu_info *this_cpu(void); #endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/include/arch/amd64/lapic.h b/sys/include/arch/amd64/lapic.h new file mode 100644 index 0000000..8a6bb14 --- /dev/null +++ b/sys/include/arch/amd64/lapic.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_LAPIC_H_ +#define _MACHINE_LAPIC_H_ + +#include + +void lapic_init(void); + +extern uintptr_t g_lapic_base; + +#endif /* !_MACHINE_LAPIC_H_ */ diff --git a/sys/include/arch/amd64/lapicvar.h b/sys/include/arch/amd64/lapicvar.h new file mode 100644 index 0000000..e224e43 --- /dev/null +++ b/sys/include/arch/amd64/lapicvar.h @@ -0,0 +1,85 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_LAPICVAR_H_ +#define _MACHINE_LAPICVAR_H_ + +#include + +/* 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 + +#endif /* !_MACHINE_LAPICVAR_H_ */ diff --git a/sys/include/arch/amd64/msr.h b/sys/include/arch/amd64/msr.h index 6ad95f1..d3d0c9a 100644 --- a/sys/include/arch/amd64/msr.h +++ b/sys/include/arch/amd64/msr.h @@ -32,6 +32,7 @@ #define IA32_SPEC_CTL 0x00000048 #define IA32_KERNEL_GS_BASE 0xC0000102 +#define IA32_APIC_BASE_MSR 0x0000001B #if !defined(__ASSEMBLER__) static inline uint64_t -- cgit v1.2.3 From b24d9a83b20a7cae49af41031a8e54946f7d42b6 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 15:12:32 -0400 Subject: kernel/amd64: isa: Add i8254 driver Signed-off-by: Ian Moffett --- sys/arch/amd64/isa/i8254.c | 73 ++++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/isa/i8254.h | 44 +++++++++++++++++++++++ 2 files changed, 117 insertions(+) create mode 100644 sys/arch/amd64/isa/i8254.c create mode 100644 sys/include/arch/amd64/isa/i8254.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/isa/i8254.c b/sys/arch/amd64/isa/i8254.c new file mode 100644 index 0000000..b5ceb9c --- /dev/null +++ b/sys/arch/amd64/isa/i8254.c @@ -0,0 +1,73 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include + +/* + * Fetches the current count. + */ +uint16_t +i8254_get_count(void) +{ + uint8_t lo, hi; + + outb(I8254_COMMAND, 0x00); + lo = inb(0x40); + hi = inb(0x40); + return COMBINE8(hi, lo); +} + +/* + * Set the reload value + * + * The reload value is where the i8254's counter + * starts... + */ +void +i8254_set_reload(uint16_t val) +{ + outb(I8254_COMMAND, 0x34); + outb(0x40, (val & 0xFF)); + outb(0x40, (val >> 8) & 0xFF); +} + +void +i8254_set_frequency(uint64_t freq_hz) +{ + uint64_t divisor = I8254_DIVIDEND / freq_hz; + + if ((I8254_DIVIDEND % freq_hz) > (freq_hz / 2)) { + ++divisor; + } + + i8254_set_reload(freq_hz); +} diff --git a/sys/include/arch/amd64/isa/i8254.h b/sys/include/arch/amd64/isa/i8254.h new file mode 100644 index 0000000..1463d71 --- /dev/null +++ b/sys/include/arch/amd64/isa/i8254.h @@ -0,0 +1,44 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_ISA_I8254_H_ +#define _MACHINE_ISA_I8254_H_ + +#include + +#define I8254_COMMAND 0x43 +#define I8254_CHANNEL_0 0x40 +#define I8254_CHANNEL_2 0x42 +#define I8254_DIVIDEND 1193182ULL + +uint16_t i8254_get_count(void); +void i8254_set_reload(uint16_t val); +void i8254_set_frequency(uint64_t frequency_hz); + +#endif /* !_MACHINE_ISA_I8254_H_ */ -- cgit v1.2.3 From 8603f1242b54d2f39e4e618ebc98a1e8bbab8164 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 15:49:34 -0400 Subject: kernel/amd64: intr: Add intr_alloc_vector() Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/intr.c | 43 +++++++++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/intr.h | 37 +++++++++++++++++++++++++++++++++++++ 2 files changed, 80 insertions(+) create mode 100644 sys/arch/amd64/amd64/intr.c create mode 100644 sys/include/arch/amd64/intr.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c new file mode 100644 index 0000000..b841da7 --- /dev/null +++ b/sys/arch/amd64/amd64/intr.c @@ -0,0 +1,43 @@ +/* + * Copyright (c) 2023-2024 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 +#include + +int +intr_alloc_vector(void) +{ + static size_t vec = 0x21; + + if (vec >= 0xFF) { + return -1; + } + + return vec++; +} diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h new file mode 100644 index 0000000..cceab6f --- /dev/null +++ b/sys/include/arch/amd64/intr.h @@ -0,0 +1,37 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_INTR_H_ +#define _MACHINE_INTR_H_ + +#include + +int intr_alloc_vector(void); + +#endif -- cgit v1.2.3 From 79afbbb41dee4bb24d2cad8234beacbd7a7e7a9b Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 15:50:23 -0400 Subject: kernel/amd64: lapic: Add support for LAPIC timer Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/lapic.c | 109 ++++++++++++++++++++++++++++++++++++++ sys/arch/amd64/amd64/lapic_intr.S | 9 ++++ sys/include/arch/amd64/cpu.h | 1 + 3 files changed, 119 insertions(+) create mode 100644 sys/arch/amd64/amd64/lapic_intr.S (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index f61715d..823e830 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -32,11 +32,15 @@ #include #include #include +#include +#include +#include #include #include #include #include #include +#include #define pr_trace(fmt, ...) kprintf("lapic: " fmt, ##__VA_ARGS__) @@ -52,8 +56,12 @@ } \ } while (0); +static struct timer lapic_timer; +static uint8_t lapic_timer_vec = 0; uintptr_t g_lapic_base = 0; +void lapic_tmr_isr(void); + /* * Returns true if LAPIC is supported. * @@ -123,6 +131,62 @@ lapic_writel(uint32_t reg, uint64_t val) } } +/* + * Starts the Local APIC countdown timer... + * + * @mask: True to mask timer. + * @mode: Timer mode. + * @count: Count to start at. + */ +static inline void +lapic_timer_start(bool mask, uint8_t mode, uint32_t count) +{ + uint32_t tmp; + + tmp = (mode << 17) | (mask << 16) | lapic_timer_vec; + lapic_writel(LAPIC_LVT_TMR, tmp); + lapic_writel(LAPIC_DCR, 0); + lapic_writel(LAPIC_INIT_CNT, count); +} + +/* + * Start Local APIC timer oneshot with number + * of ticks to count down from. + * + * @mask: If `true', timer will be masked, `count' should be 0. + * @count: Number of ticks. + */ +static void +lapic_timer_oneshot(bool mask, uint32_t count) +{ + lapic_timer_start(mask, LVT_TMR_ONESHOT, count); +} + +/* + * Start Local APIC timer oneshot in microseconds. + * + * @us: Microseconds. + */ +static void +lapic_timer_oneshot_us(size_t usec) +{ + uint64_t ticks; + struct cpu_info *ci = this_cpu(); + + ticks = usec * (ci->lapic_tmr_freq / 1000000); + lapic_timer_oneshot(false, ticks); +} + +/* + * Stops the Local APIC timer + */ +static void +lapic_timer_stop(void) +{ + lapic_writel(LAPIC_LVT_TMR, LAPIC_LVT_MASK); + lapic_writel(LAPIC_INIT_CNT, 0); +} + /* * Set bits within a LAPIC register * without overwriting the whole thing. @@ -187,10 +251,37 @@ lapic_read_id(const struct cpu_info *ci) } } +/* + * Init the Local APIC timer and return + * the frequency. + */ +static size_t +lapic_timer_init(void) +{ + uint16_t ticks_start, ticks_end; + size_t ticks_total, freq; + const uint16_t MAX_SAMPLES = 0xFFFF; + + lapic_timer_stop(); + i8254_set_reload(MAX_SAMPLES); + ticks_start = i8254_get_count(); + + lapic_writel(LAPIC_INIT_CNT, MAX_SAMPLES); + while (lapic_readl(LAPIC_CUR_CNT) != 0); + + ticks_end = i8254_get_count(); + ticks_total = ticks_start - ticks_end; + + freq = (MAX_SAMPLES / ticks_total) * I8254_DIVIDEND; + lapic_timer_stop(); + return freq; +} + void lapic_init(void) { struct cpu_info *ci = this_cpu(); + tmrr_status_t tmr_status; /* * Hyra currently depends on the existance @@ -200,6 +291,12 @@ lapic_init(void) panic("This machine does not support LAPIC!\n"); } + /* Allocate a vector if needed */ + if (lapic_timer_vec == 0) { + lapic_timer_vec = intr_alloc_vector(); + idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr), 0); + } + /* Ensure the LAPIC base is valid */ if (g_lapic_base == 0) { panic("Invalid LAPIC base\n"); @@ -209,6 +306,18 @@ lapic_init(void) lapic_enable(ci); ci->apicid = lapic_read_id(ci); + ci->lapic_tmr_freq = lapic_timer_init(); bsp_trace("BSP LAPIC enabled in %s mode (id=%d)\n", ci->has_x2apic ? "x2APIC" : "xAPIC", ci->apicid); + + /* Try to register the timer */ + lapic_timer.name = "LAPIC_INTEGRATED_TIMER"; + lapic_timer.stop = lapic_timer_stop; + lapic_timer.oneshot_us = lapic_timer_oneshot_us; + tmr_status = register_timer(TIMER_SCHED, &lapic_timer); + + /* This should not happen but handle it just in case */ + if (__unlikely(tmr_status != TMRR_SUCCESS)) { + panic("Failed to register %s\n", lapic_timer.name); + } } diff --git a/sys/arch/amd64/amd64/lapic_intr.S b/sys/arch/amd64/amd64/lapic_intr.S new file mode 100644 index 0000000..295de2d --- /dev/null +++ b/sys/arch/amd64/amd64/lapic_intr.S @@ -0,0 +1,9 @@ +#include + + .text + .globl lapic_tmr_isr +lapic_tmr_isr: + push_trapframe $0 + mov %rsp, %rdi + pop_trapframe + iretq diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index 4e5baf1..92d2356 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -36,6 +36,7 @@ struct cpu_info { uint32_t apicid; uint8_t has_x2apic : 1; + size_t lapic_tmr_freq; }; void cpu_startup(void); -- cgit v1.2.3 From a84cacff59d6e31c05b6f9eddebf28dbb418b303 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 17:46:39 -0400 Subject: kernel/amd64: tss: Add support for TSS Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/machdep.c | 12 +++ sys/arch/amd64/amd64/tss.c | 177 +++++++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/cpu.h | 2 + sys/include/arch/amd64/gdt.h | 1 + sys/include/arch/amd64/intr.h | 4 + sys/include/arch/amd64/tss.h | 121 ++++++++++++++++++++++++++++ 6 files changed, 317 insertions(+) create mode 100644 sys/arch/amd64/amd64/tss.c create mode 100644 sys/include/arch/amd64/tss.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 983a480..2fe71a9 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -67,6 +68,16 @@ setup_vectors(void) idt_set_desc(0xE, IDT_TRAP_GATE, ISR(page_fault), 0); } +static inline void +init_tss(struct cpu_info *ci) +{ + struct tss_desc *desc; + + desc = (struct tss_desc *)&g_gdt_data[GDT_TSS]; + write_tss(ci, desc); + tss_load(); +} + static void try_mitigate_spectre(void) { @@ -95,6 +106,7 @@ cpu_startup(void) setup_vectors(); amd64_write_gs_base((uintptr_t)&g_bsp_ci); + init_tss(&g_bsp_ci); try_mitigate_spectre(); lapic_init(); diff --git a/sys/arch/amd64/amd64/tss.c b/sys/arch/amd64/amd64/tss.c new file mode 100644 index 0000000..5aab74a --- /dev/null +++ b/sys/arch/amd64/amd64/tss.c @@ -0,0 +1,177 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Allocates memory for TSS and kernel + * stack. + * + * XXX: Kernel stack is allocated from + * vm_alloc_frame() + */ +static void +alloc_resources(struct cpu_info *ci) +{ + const size_t STACK_SIZE = 0x1000; + struct tss_entry *tss; + static uintptr_t rsp0_base, rsp0; + + if (ci->tss == NULL) { + tss = dynalloc(sizeof(*tss)); + + if (tss == NULL) { + panic("Failed to alloc TSS\n"); + } + + memset(tss, 0, sizeof(*tss)); + rsp0_base = vm_alloc_frame(1); + + if (rsp0_base == 0) { + panic("Could not allocate RSP0 base\n"); + } + + rsp0 = rsp0_base + STACK_SIZE; + tss->rsp0_lo = rsp0 & 0xFFFFFFFF; + tss->rsp0_hi = (rsp0 >> 32) & 0xFFFFFFFF; + ci->tss = tss; + } +} + +/* + * Update interrupt stack table entry `istno' with `stack' + * + * @stack: Interrupt stack. + * @istno: IST number, must be 1-based. + * + * Returns 0 on success. + */ +int +tss_update_ist(struct cpu_info *ci, union tss_stack stack, uint8_t istno) +{ + volatile struct tss_entry *tss = ci->tss; + + __assert(tss != NULL); + + switch (istno) { + case 1: + tss->ist1_lo = stack.top_lo; + tss->ist1_hi = stack.top_hi; + break; + case 2: + tss->ist2_lo = stack.top_lo; + tss->ist2_hi = stack.top_hi; + break; + case 3: + tss->ist3_lo = stack.top_lo; + tss->ist3_hi = stack.top_hi; + break; + case 4: + tss->ist4_lo = stack.top_lo; + tss->ist4_hi = stack.top_hi; + break; + case 5: + tss->ist5_lo = stack.top_lo; + tss->ist5_hi = stack.top_hi; + break; + case 6: + tss->ist6_lo = stack.top_lo; + tss->ist6_hi = stack.top_hi; + break; + case 7: + tss->ist7_lo = stack.top_lo; + tss->ist7_hi = stack.top_hi; + break; + default: + return -EINVAL; + }; + + return 0; +} + +/* + * Allocates TSS stack. + * + * @entry_out: Pointer to location where allocated entry + * will be sent. + * + * Returns 0 on success. + */ +int +tss_alloc_stack(union tss_stack *entry_out, size_t size) +{ + uintptr_t base = (uintptr_t)dynalloc(size); + + if (base == 0) { + return -ENOMEM; + } + + entry_out->top = base + size; + return 0; +} + +void +write_tss(struct cpu_info *ci, struct tss_desc *desc) +{ + volatile struct tss_entry *tss; + uintptr_t tss_base; + + alloc_resources(ci); + tss_base = (uintptr_t)ci->tss; + + /* + * XXX: The AVL (Available for use by system software) + * bit is ignored by hardware and it is up to us + * to decide how to use it... As of now, it is useless + * to us and shall remain 0. + */ + desc->seglimit = sizeof(struct tss_entry); + desc->p = 1; /* Must be present to be valid! */ + desc->g = 0; /* Granularity -> 0 */ + desc->avl = 0; /* Not used */ + desc->dpl = 0; /* Descriptor Privilege Level -> 0 */ + desc->type = 0x9; /* For TSS -> 0x9 (0b1001) */ + + desc->base_lo16 = tss_base & 0xFFFF; + desc->base_mid8 = (tss_base >> 16) & 0xFF; + desc->base_hi_mid8 = (tss_base >> 24) & 0xFF; + desc->base_hi32 = (tss_base >> 32) & 0xFFFFFFFF; + + tss = ci->tss; + tss->io_base = 0xFF; /* Disallow ring 3 port I/O */ +} diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index 92d2356..ef2eb78 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -32,11 +32,13 @@ #include #include +#include struct cpu_info { uint32_t apicid; uint8_t has_x2apic : 1; size_t lapic_tmr_freq; + struct tss_entry *tss; }; void cpu_startup(void); diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h index 6f8a914..ce7dd60 100644 --- a/sys/include/arch/amd64/gdt.h +++ b/sys/include/arch/amd64/gdt.h @@ -6,6 +6,7 @@ #define KERNEL_CS 0x08 #define KERNEL_DS 0x10 +#define GDT_TSS 5 struct __packed gdt_entry { uint16_t limit; diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h index cceab6f..3f0da77 100644 --- a/sys/include/arch/amd64/intr.h +++ b/sys/include/arch/amd64/intr.h @@ -32,6 +32,10 @@ #include +#define IST_SCHED 1U +#define IST_HW_IRQ 2U +#define IST_SW_INT 3U + int intr_alloc_vector(void); #endif diff --git a/sys/include/arch/amd64/tss.h b/sys/include/arch/amd64/tss.h new file mode 100644 index 0000000..347192d --- /dev/null +++ b/sys/include/arch/amd64/tss.h @@ -0,0 +1,121 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_TSS_H_ +#define _MACHINE_TSS_H_ + +#include +#include + +struct cpu_info; + +/* + * A TSS entry (64-bit) + * + * See Intel SDM Section 8.2.1 - Task-State Segment (TSS) + */ +struct __packed tss_entry { + uint32_t reserved1; + uint32_t rsp0_lo; + uint32_t rsp0_hi; + uint32_t rsp1_lo; + uint32_t rsp1_hi; + uint32_t rsp2_lo; + uint32_t rsp2_hi; + uint64_t reserved2; + uint32_t ist1_lo; + uint32_t ist1_hi; + uint32_t ist2_lo; + uint32_t ist2_hi; + uint32_t ist3_lo; + uint32_t ist3_hi; + uint32_t ist4_lo; + uint32_t ist4_hi; + uint32_t ist5_lo; + uint32_t ist5_hi; + uint32_t ist6_lo; + uint32_t ist6_hi; + uint32_t ist7_lo; + uint32_t ist7_hi; + uint64_t reserved3; + uint16_t reserved4; + uint16_t io_base; +}; + +/* + * TSS descriptor (64-bit) + * + * The TSS descriptor describes the location + * of the TSS segments among other things... + * + * See Intel SDM Section 8.2.3 - TSS Descriptor in 64-bit mode + */ +struct __packed tss_desc { + uint16_t seglimit; + uint16_t base_lo16; + uint8_t base_mid8; + uint8_t type : 4; + uint8_t zero : 1; + uint8_t dpl : 2; + uint8_t p : 1; + uint8_t seglimit_hi : 4; + uint8_t avl : 1; + uint8_t unused : 2; + uint8_t g : 1; + uint8_t base_hi_mid8; + uint32_t base_hi32; + uint32_t reserved; +}; + +/* + * Holds the address of the address pointing + * to the top of an interrupt stack. + */ +union tss_stack { + struct { + uint32_t top_lo; + uint32_t top_hi; + }; + uint64_t top; +}; + +__always_inline static inline void +tss_load(void) +{ + __ASMV("str %ax\n" + "mov $0x2B, %ax\n" + "ltr %ax" + ); +} + +int tss_alloc_stack(union tss_stack *entry_out, size_t size); +int tss_update_ist(struct cpu_info *ci, union tss_stack stack, uint8_t istno); +void write_tss(struct cpu_info *ci, struct tss_desc *desc); + +#endif /* !_MACHINE_TSS_H_ */ -- cgit v1.2.3 From d5381223cea600ff007069bc1313de142cd06972 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 8 Jun 2024 18:13:42 -0400 Subject: kernel/amd64: lapic: Add End-Of-Interrupt helper Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/lapic.c | 10 ++++++++++ sys/include/arch/amd64/lapic.h | 1 + 2 files changed, 11 insertions(+) (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index 07a9a49..b7cefd4 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -284,6 +284,16 @@ lapic_timer_init(void) return freq; } +/* + * Indicates that the current interrupt is finished + * being serviced. + */ +void +lapic_eoi(void) +{ + lapic_writel(LAPIC_EOI, 0); +} + void lapic_init(void) { diff --git a/sys/include/arch/amd64/lapic.h b/sys/include/arch/amd64/lapic.h index 8a6bb14..d06bcc9 100644 --- a/sys/include/arch/amd64/lapic.h +++ b/sys/include/arch/amd64/lapic.h @@ -33,6 +33,7 @@ #include void lapic_init(void); +void lapic_eoi(void); extern uintptr_t g_lapic_base; -- cgit v1.2.3 From 44ef655a0afc3d2c8aa305f94b412f9d89bec846 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 8 Jun 2024 18:15:13 -0400 Subject: kernel/amd64: Pass CPU info to cpu_startup() Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/machdep.c | 9 +++++---- sys/include/arch/amd64/cpu.h | 3 ++- sys/kern/init_main.c | 2 +- 3 files changed, 8 insertions(+), 6 deletions(-) (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/machdep.c b/sys/arch/amd64/amd64/machdep.c index 2fe71a9..82fa97b 100644 --- a/sys/arch/amd64/amd64/machdep.c +++ b/sys/arch/amd64/amd64/machdep.c @@ -45,7 +45,7 @@ int ibrs_enable(void); -static struct cpu_info g_bsp_ci = {0}; +struct cpu_info g_bsp_ci = {0}; static struct gdtr bsp_gdtr = { .limit = sizeof(struct gdt_entry) * 256 - 1, .offset = (uintptr_t)&g_gdt_data[0] @@ -99,15 +99,16 @@ this_cpu(void) } void -cpu_startup(void) +cpu_startup(struct cpu_info *ci) { gdt_load(&bsp_gdtr); idt_load(); setup_vectors(); - amd64_write_gs_base((uintptr_t)&g_bsp_ci); - init_tss(&g_bsp_ci); + amd64_write_gs_base((uintptr_t)ci); + init_tss(ci); try_mitigate_spectre(); + __ASMV("sti"); /* Unmask interrupts */ lapic_init(); } diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index ef2eb78..84391ba 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -41,7 +41,8 @@ struct cpu_info { struct tss_entry *tss; }; -void cpu_startup(void); +void cpu_startup(struct cpu_info *ci); struct cpu_info *this_cpu(void); +extern struct cpu_info g_bsp_ci; #endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 6f17227..94fa8c0 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -49,7 +49,7 @@ main(void) vm_init(); /* Startup the BSP */ - cpu_startup(); + cpu_startup(&g_bsp_ci); /* Nothing left to do... halt */ cpu_reboot(REBOOT_HALT); -- cgit v1.2.3 From 55845113211400c9b1657ec3ce72b06a05efac4e Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 8 Jun 2024 18:19:51 -0400 Subject: kernel/amd64: Prepare for scheduler Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/lapic_intr.S | 2 + sys/arch/amd64/amd64/mp.c | 93 ++++++++++++++++++++++++++++++++++ sys/arch/amd64/conf/GENERIC | 3 ++ sys/include/arch/amd64/cpu.h | 4 ++ sys/include/sys/proc.h | 48 ++++++++++++++++++ sys/include/sys/sched.h | 39 +++++++++++++++ sys/include/sys/schedvar.h | 63 +++++++++++++++++++++++ sys/kern/init_main.c | 5 ++ sys/kern/kern_sched.c | 102 ++++++++++++++++++++++++++++++++++++++ 9 files changed, 359 insertions(+) create mode 100644 sys/arch/amd64/amd64/mp.c create mode 100644 sys/include/sys/proc.h create mode 100644 sys/include/sys/sched.h create mode 100644 sys/include/sys/schedvar.h create mode 100644 sys/kern/kern_sched.c (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/lapic_intr.S b/sys/arch/amd64/amd64/lapic_intr.S index 295de2d..a3fa7e4 100644 --- a/sys/arch/amd64/amd64/lapic_intr.S +++ b/sys/arch/amd64/amd64/lapic_intr.S @@ -5,5 +5,7 @@ lapic_tmr_isr: push_trapframe $0 mov %rsp, %rdi + call sched_switch + call lapic_eoi pop_trapframe iretq diff --git a/sys/arch/amd64/amd64/mp.c b/sys/arch/amd64/amd64/mp.c new file mode 100644 index 0000000..9512aa6 --- /dev/null +++ b/sys/arch/amd64/amd64/mp.c @@ -0,0 +1,93 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include +#include + +#define pr_trace(fmt, ...) kprintf("cpu_mp: " fmt, ##__VA_ARGS__) + +static volatile struct limine_smp_request g_smp_req = { + .id = LIMINE_SMP_REQUEST, + .revision = 0 +}; + +static void +ap_trampoline(struct limine_smp_info *si) +{ + struct spinlock lock = {0}; + struct cpu_info *ci; + + spinlock_acquire(&lock); + ci = dynalloc(sizeof(*ci)); + __assert(ci != NULL); + + memset(ci, 0, sizeof(*ci)); + cpu_startup(ci); + + spinlock_release(&lock); + sched_enter(); + + while (1); +} + +void +mp_bootstrap_aps(struct cpu_info *ci) +{ + struct limine_smp_response *resp = g_smp_req.response; + struct limine_smp_info **cpus; + size_t cpu_init_counter; + + /* Should not happen */ + __assert(resp != NULL); + + cpus = resp->cpus; + cpu_init_counter = resp->cpu_count - 1; + + if (resp->cpu_count == 1) { + pr_trace("CPU has 1 core, no APs to bootstrap...\n"); + return; + } + + pr_trace("Bootstrapping %d cores...\n", cpu_init_counter); + for (size_t i = 0; i < resp->cpu_count; ++i) { + if (ci->apicid == cpus[i]->lapic_id) { + pr_trace("Skip %d (BSP)... continue\n", ci->apicid); + continue; + } + + cpus[i]->goto_address = ap_trampoline; + } +} diff --git a/sys/arch/amd64/conf/GENERIC b/sys/arch/amd64/conf/GENERIC index ea6ba76..a7bbc81 100644 --- a/sys/arch/amd64/conf/GENERIC +++ b/sys/arch/amd64/conf/GENERIC @@ -1,2 +1,5 @@ // Kernel options option SPECTRE_IBRS no + +// Kernel constants +setval SCHED_NQUEUE 4 diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index 84391ba..b5420a6 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -32,6 +32,7 @@ #include #include +#include #include struct cpu_info { @@ -39,10 +40,13 @@ struct cpu_info { uint8_t has_x2apic : 1; size_t lapic_tmr_freq; struct tss_entry *tss; + struct proc *curtd; }; void cpu_startup(struct cpu_info *ci); struct cpu_info *this_cpu(void); +void mp_bootstrap_aps(struct cpu_info *ci); + extern struct cpu_info g_bsp_ci; #endif /* !_MACHINE_CPU_H_ */ diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h new file mode 100644 index 0000000..ba47a5c --- /dev/null +++ b/sys/include/sys/proc.h @@ -0,0 +1,48 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _SYS_PROC_H_ +#define _SYS_PROC_H_ + +#include +#include +#if defined(_KERNEL) +#include +#include +#endif /* _KERNEL */ + +#if defined(_KERNEL) + +struct proc { + pid_t pid; + struct cpu_info *cpu; +}; + +#endif /* _KERNEL */ +#endif /* !_SYS_PROC_H_ */ diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h new file mode 100644 index 0000000..33d546d --- /dev/null +++ b/sys/include/sys/sched.h @@ -0,0 +1,39 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _SYS_SCHED_H_ +#define _SYS_SCHED_H_ + +#if defined(_KERNEL) + +void sched_init(void); +void sched_enter(void); + +#endif /* _KERNEL */ +#endif /* !_SYS_SCHED_H_ */ diff --git a/sys/include/sys/schedvar.h b/sys/include/sys/schedvar.h new file mode 100644 index 0000000..00caeb4 --- /dev/null +++ b/sys/include/sys/schedvar.h @@ -0,0 +1,63 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _SYS_SCHEDVAR_H_ +#define _SYS_SCHEDVAR_H_ + +#include +#include +#include + +#if defined(_KERNEL) +#define DEFAULT_TIMESLICE_USEC 1050 +#define SHORT_TIMESLICE_USEC 10 + +#define SCHED_POLICY_MLFQ 0x00U /* Multilevel feedback queue */ +#define SCHED_POLICY_RR 0x01U /* Round robin */ + +typedef uint8_t sched_policy_t; + +/* Might be set by kconf(1) */ +#if defined(__SCHED_NQUEUE) +#define SCHED_NQUEUE __SCHED_NQUEUE +#else +#define SCHED_NQUEUE 4 +#endif /* __SCHED_NQUEUE */ + +/* Ensure SCHED_NQUEUE is an acceptable value */ +__static_assert(SCHED_NQUEUE <= 8, "SCHED_NQUEUE exceeds max"); +__static_assert(SCHED_NQUEUE > 0, "SCHED_NQUEUE cannot be zero"); + +struct sched_queue { + TAILQ_HEAD(, proc) q; + size_t nthread; +}; + +#endif /* _KERNEL */ +#endif /* !_SYS_SCHEDVAR_H_ */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 94fa8c0..6018dfe 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -29,6 +29,7 @@ #include #include +#include #include #include #include @@ -51,6 +52,10 @@ main(void) /* Startup the BSP */ cpu_startup(&g_bsp_ci); + /* Start scheduler and bootstrap APs */ + sched_init(); + mp_bootstrap_aps(&g_bsp_ci); + /* Nothing left to do... halt */ cpu_reboot(REBOOT_HALT); __builtin_unreachable(); diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c new file mode 100644 index 0000000..b79d682 --- /dev/null +++ b/sys/kern/kern_sched.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include + +#define pr_trace(fmt, ...) kprintf("ksched: " fmt, ##__VA_ARGS__) + +void sched_switch(struct trapframe *tf); + +static sched_policy_t policy = SCHED_POLICY_RR; + +/* + * Thread ready queues - all threads ready to be + * scheduled should be added to the toplevel queue. + */ +static struct sched_queue qlist[SCHED_NQUEUE]; + +/* + * Perform timer oneshot + */ +static inline void +sched_oneshot(bool now) +{ + struct timer timer; + size_t usec = now ? SHORT_TIMESLICE_USEC : DEFAULT_TIMESLICE_USEC; + tmrr_status_t tmr_status; + + tmr_status = req_timer(TIMER_SCHED, &timer); + __assert(tmr_status == TMRR_SUCCESS); + + timer.oneshot_us(usec); +} + +/* + * Perform a context switch. + * + * TODO + */ +void +sched_switch(struct trapframe *tf) +{ + static struct spinlock lock = {0}; + + spinlock_acquire(&lock); + spinlock_release(&lock); + sched_oneshot(false); +} + +/* + * Main scheduler loop + */ +void +sched_enter(void) +{ + sched_oneshot(false); + for (;;); +} + +void +sched_init(void) +{ + /* Setup the queues */ + for (int i = 0; i < SCHED_NQUEUE; ++i) { + TAILQ_INIT(&qlist[i].q); + } + + pr_trace("Prepared %d queues (policy=0x%x)\n", + SCHED_NQUEUE, policy); +} -- cgit v1.2.3 From 92cc282d121c2f5b842a661dae9cf4cb199c4d46 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 9 Jun 2024 22:03:12 -0400 Subject: kernel/amd64: pmap: Add initial pmap code Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/pmap.c | 236 +++++++++++++++++++++++++++++++++++++++++++ sys/include/arch/amd64/tlb.h | 42 ++++++++ sys/include/arch/amd64/vas.h | 46 +++++++++ sys/include/vm/pmap.h | 64 ++++++++++++ 4 files changed, 388 insertions(+) create mode 100644 sys/arch/amd64/amd64/pmap.c create mode 100644 sys/include/arch/amd64/tlb.h create mode 100644 sys/include/arch/amd64/vas.h create mode 100644 sys/include/vm/pmap.h (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c new file mode 100644 index 0000000..27bb44d --- /dev/null +++ b/sys/arch/amd64/amd64/pmap.c @@ -0,0 +1,236 @@ +/* + * Copyright (c) 2023-2024 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 +#include +#include +#include +#include +#include +#include +#include +#include +#include + +/* + * Page-Table Entry (PTE) flags + * + * See Intel SDM Vol 3A, Section 4.5, Table 4-19 + */ +#define PTE_ADDR_MASK 0x000FFFFFFFFFF000 +#define PTE_P BIT(0) /* Present */ +#define PTE_RW BIT(1) /* Writable */ +#define PTE_US BIT(2) /* User r/w allowed */ +#define PTE_PWT BIT(3) /* Page-level write-through */ +#define PTE_PCD BIT(4) /* Page-level cache disable */ +#define PTE_ACC BIT(5) /* Accessed */ +#define PTE_DIRTY BIT(6) /* Dirty (written-to page) */ +#define PTE_PAT BIT(7) +#define PTE_GLOBAL BIT(8) +#define PTE_NX BIT(63) /* Execute-disable */ + +/* + * Convert pmap protection flags to PTE flags. + */ +static uint64_t +pmap_prot_to_pte(vm_prot_t prot) +{ + uint64_t pte_flags = PTE_P | PTE_NX; + + if (ISSET(prot, PROT_WRITE)) + pte_flags |= PTE_RW; + if (ISSET(prot, PROT_EXEC)) + pte_flags &= ~(PTE_NX); + if (ISSET(prot, PROT_USER)) + pte_flags |= PTE_US; + + return pte_flags; +} + +/* + * Returns index for a specific pagemap level. + * + * @level: Requested level. + * @va: Virtual address. + */ +static size_t +pmap_get_level_index(uint8_t level, vaddr_t va) +{ + __assert(level <= 4 && level != 0); + + switch (level) { + case 4: + return (va >> 39) & 0x1FF; + case 3: + return (va >> 30) & 0x1FF; + case 2: + return (va >> 21) & 0x1FF; + case 1: + return (va >> 12) & 0x1FF; + default: /* Should not be reachable */ + return 0; + } +} + +/* + * Extract a pagemap level. + */ +static uintptr_t * +pmap_extract(uint8_t level, vaddr_t va, vaddr_t *pmap, bool alloc) +{ + uintptr_t next, level_alloc; + size_t idx = pmap_get_level_index(level, va); + + if (pmap == NULL) { + return NULL; + } + + if (ISSET(pmap[idx], PTE_P)) { + next = (pmap[idx] & PTE_ADDR_MASK); + return PHYS_TO_VIRT(next); + } + + if (!alloc) { + return 0; + } + + /* Allocate the next level */ + level_alloc = vm_alloc_frame(1); + if (level_alloc == 0) + return 0; + + memset(PHYS_TO_VIRT(level_alloc), 0, DEFAULT_PAGESIZE); + pmap[idx] = level_alloc | (PTE_P | PTE_RW | PTE_US); + return PHYS_TO_VIRT(level_alloc); +} + +/* + * Modify a page table by writing `val' to it. + * + * @vas: Virtual address space. + * @va: Virtual address. + * @alloc: True to alloc new entries. + * @res: Result + */ +static int +pmap_get_tbl(struct vas vas, vaddr_t va, bool alloc, uintptr_t **res) +{ + uintptr_t *pml4 = PHYS_TO_VIRT(vas.top_level); + uintptr_t *pdpt, *pd, *tbl; + int status = 0; + + pdpt = pmap_extract(4, va, pml4, alloc); + if (pdpt == NULL) { + status = 1; + goto done; + } + + pd = pmap_extract(3, va, pdpt, alloc); + if (pd == NULL) { + status = 1; + goto done; + } + + tbl = pmap_extract(2, va, pd, alloc); + if (tbl == NULL) { + status = 1; + goto done; + } + + *res = tbl; +done: + return status; +} + +/* + * Update the value in a page table. + * + * @vas: Virtual address space. + * @va: Target virtual address. + * @val: Value to write. + */ +static int +pmap_update_tbl(struct vas vas, vaddr_t va, uint64_t val) +{ + uintptr_t *tbl; + int status; + + if ((status = pmap_get_tbl(vas, va, true, &tbl)) != 0) { + return status; + } + + tbl[pmap_get_level_index(1, va)] = val; + tlb_flush(va); + return 0; +} + +struct vas +pmap_read_vas(void) +{ + struct vas vas; + uint64_t cr3_raw; + + __ASMV("mov %%cr3, %0" + : "=r" (cr3_raw) + : + : "memory" + ); + + vas.cr3_flags = cr3_raw & ~PTE_ADDR_MASK; + vas.top_level = cr3_raw & PTE_ADDR_MASK; + vas.use_l5_paging = false; /* TODO */ + vas.lock.lock = 0; + return vas; +} + +void +pmap_switch_vas(struct vas vas) +{ + uintptr_t cr3_val = vas.cr3_flags | vas.top_level; + + __ASMV("mov %0, %%cr3" + : + : "r" (cr3_val) + : "memory" + ); +} + +int +pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot) +{ + uint32_t flags = pmap_prot_to_pte(prot); + + return pmap_update_tbl(vas, va, (pa | flags)); +} + +int +pmap_unmap(struct vas vas, vaddr_t va) +{ + return pmap_update_tbl(vas, va, 0); +} diff --git a/sys/include/arch/amd64/tlb.h b/sys/include/arch/amd64/tlb.h new file mode 100644 index 0000000..1e5dc40 --- /dev/null +++ b/sys/include/arch/amd64/tlb.h @@ -0,0 +1,42 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_TLB_H_ +#define _MACHINE_TLB_H_ + +#include + +#define tlb_flush(va) \ + __ASMV("invlpg (%0)" \ + : \ + : "r" (va) \ + : "memory" \ + ) + +#endif /* !_MACHINE_TLB_H_ */ diff --git a/sys/include/arch/amd64/vas.h b/sys/include/arch/amd64/vas.h new file mode 100644 index 0000000..35f291f --- /dev/null +++ b/sys/include/arch/amd64/vas.h @@ -0,0 +1,46 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_VAS_H_ +#define _MACHINE_VAS_H_ + +#include +#include + +/* + * VAS structure - describes a virtual address space + */ +struct vas { + size_t cr3_flags; /* CR3 flags */ + uintptr_t top_level; /* PML5 if `use_l5_paging' true, otherwise PML4 */ + bool use_l5_paging; /* True if 5-level paging is supported */ + struct spinlock lock; +}; + +#endif /* !_MACHINE_VAS_H_ */ diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h new file mode 100644 index 0000000..ec669a8 --- /dev/null +++ b/sys/include/vm/pmap.h @@ -0,0 +1,64 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _VM_PMAP_H_ +#define _VM_PMAP_H_ + +#include +#include + +/* Protection flags for mappings */ +#define PROT_READ 0x00000000UL +#define PROT_WRITE BIT(0) /* Writable */ +#define PROT_EXEC BIT(1) /* Executable */ +#define PROT_USER BIT(2) /* User accessible */ + +typedef uint32_t vm_prot_t; + +/* + * Fetch the current address space. + */ +struct vas pmap_read_vas(void); + +/* + * Switch the virtual address space. + */ +void pmap_switch_vas(struct vas vas); + +/* + * Create a virtual memory mapping of a single page. + */ +int pmap_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot); + +/* + * Unmap a virtual memory mapping of a single page. + */ +int pmap_unmap(struct vas vas, vaddr_t va); + +#endif /* !_VM_PMAP_H_ */ -- cgit v1.2.3 From f290314f286b70a8f59becedd5f789c21f675b5d Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 20 Jun 2024 20:35:38 -0400 Subject: kernel/amd64: intr: Add splraise/splx support Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/intr.c | 63 ++++++++++++++++++++++++++++++++++++++++--- sys/arch/amd64/amd64/lapic.c | 2 +- sys/include/arch/amd64/asm.h | 14 ++++++++++ sys/include/arch/amd64/cpu.h | 1 + sys/include/arch/amd64/intr.h | 19 ++++++++++++- 5 files changed, 93 insertions(+), 6 deletions(-) (limited to 'sys/include/arch') diff --git a/sys/arch/amd64/amd64/intr.c b/sys/arch/amd64/amd64/intr.c index b841da7..3e3f309 100644 --- a/sys/arch/amd64/amd64/intr.c +++ b/sys/arch/amd64/amd64/intr.c @@ -28,16 +28,71 @@ */ #include +#include +#include +#include #include +#include +#include +#include + +static struct intr_entry *intrs[256] = {0}; + +void +splraise(uint8_t s) +{ + struct cpu_info *ci = this_cpu(); + + if (s < ci->ipl) { + panic("splraise IPL less than current IPL\n"); + } + + amd64_write_cr8(s); + ci->ipl = s; +} + +void +splx(uint8_t s) +{ + struct cpu_info *ci = this_cpu(); + + if (s > ci->ipl) { + panic("splx IPL greater than current IPL\n"); + } + + amd64_write_cr8(s); + ci->ipl = s; +} int -intr_alloc_vector(void) +intr_alloc_vector(const char *name, uint8_t priority) { - static size_t vec = 0x21; + size_t vec = MAX(priority << IPL_SHIFT, 0x20); + struct intr_entry *intr; - if (vec >= 0xFF) { + /* Sanity check */ + if (vec > NELEM(intrs)) { return -1; } - return vec++; + /* + * Try to allocate an interrupt vector. An IPL is made up + * of 4 bits so there can be 16 vectors per IPL. + */ + for (int i = vec; i < vec + 16; ++i) { + if (intrs[i] != NULL) { + continue; + } + + intr = dynalloc(sizeof(*intr)); + if (intr == NULL) { + return -ENOMEM; + } + + intr->priority = priority; + intrs[i] = intr; + return i; + } + + return -1; } diff --git a/sys/arch/amd64/amd64/lapic.c b/sys/arch/amd64/amd64/lapic.c index b7cefd4..896c2bd 100644 --- a/sys/arch/amd64/amd64/lapic.c +++ b/sys/arch/amd64/amd64/lapic.c @@ -317,7 +317,7 @@ lapic_init(void) /* Allocate a vector if needed */ if (lapic_timer_vec == 0) { - lapic_timer_vec = intr_alloc_vector(); + lapic_timer_vec = intr_alloc_vector("lapictmr", IPL_CLOCK); idt_set_desc(lapic_timer_vec, IDT_INT_GATE, ISR(lapic_tmr_isr), IST_SCHED); } diff --git a/sys/include/arch/amd64/asm.h b/sys/include/arch/amd64/asm.h index d7334fe..e85dd87 100644 --- a/sys/include/arch/amd64/asm.h +++ b/sys/include/arch/amd64/asm.h @@ -84,6 +84,20 @@ amd64_write_cr0(uint64_t val) __ASMV("mov %0, %%cr0" :: "r" (val) : "memory"); } +static inline uint64_t +amd64_read_cr8(void) +{ + uint64_t cr8; + __ASMV("mov %%cr8, %0" : "=r" (cr8) :: "memory"); + return cr8; +} + +static inline void +amd64_write_cr8(uint64_t val) +{ + __ASMV("mov %0, %%cr8" :: "r" (val) : "memory"); +} + static inline uint64_t amd64_read_cr4(void) { diff --git a/sys/include/arch/amd64/cpu.h b/sys/include/arch/amd64/cpu.h index b5420a6..16936e9 100644 --- a/sys/include/arch/amd64/cpu.h +++ b/sys/include/arch/amd64/cpu.h @@ -38,6 +38,7 @@ struct cpu_info { uint32_t apicid; uint8_t has_x2apic : 1; + uint8_t ipl; size_t lapic_tmr_freq; struct tss_entry *tss; struct proc *curtd; diff --git a/sys/include/arch/amd64/intr.h b/sys/include/arch/amd64/intr.h index 3f0da77..af5edf2 100644 --- a/sys/include/arch/amd64/intr.h +++ b/sys/include/arch/amd64/intr.h @@ -36,6 +36,23 @@ #define IST_HW_IRQ 2U #define IST_SW_INT 3U -int intr_alloc_vector(void); +/* Upper 4 bits of interrupt vector */ +#define IPL_SHIFT 4 + +/* + * Interrupt priority levels + */ +#define IPL_NONE 0 /* Don't defer anything */ +#define IPL_BIO 1 /* Block I/O */ +#define IPL_CLOCK 2 /* Clock */ +#define IPL_HIGH 3 /* Defer everything */ + +struct intr_entry { + int priority; +}; + +int intr_alloc_vector(const char *name, uint8_t priority); +void splraise(uint8_t s); +void splx(uint8_t s); #endif -- cgit v1.2.3 From aa8d940e7e1cadf651054a58d6953fee03149587 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 22:23:53 -0400 Subject: kernel/amd64: gdt: Add user CS/DS defines Signed-off-by: Ian Moffett --- sys/include/arch/amd64/gdt.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sys/include/arch') diff --git a/sys/include/arch/amd64/gdt.h b/sys/include/arch/amd64/gdt.h index ce7dd60..f87416f 100644 --- a/sys/include/arch/amd64/gdt.h +++ b/sys/include/arch/amd64/gdt.h @@ -6,6 +6,8 @@ #define KERNEL_CS 0x08 #define KERNEL_DS 0x10 +#define USER_CS 0x18 +#define USER_DS 0x20 #define GDT_TSS 5 struct __packed gdt_entry { -- cgit v1.2.3 From 00245135a7df4028df60f62f4041c1302e5b3381 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 22:25:13 -0400 Subject: kernel: sched: Add PCB and context switching Signed-off-by: Ian Moffett --- sys/include/arch/amd64/pcb.h | 40 +++++++++++++++++++++ sys/include/sys/proc.h | 11 ++++-- sys/include/sys/sched.h | 3 ++ sys/kern/kern_sched.c | 83 ++++++++++++++++++++++++++++++++++++++++++-- 4 files changed, 132 insertions(+), 5 deletions(-) create mode 100644 sys/include/arch/amd64/pcb.h (limited to 'sys/include/arch') diff --git a/sys/include/arch/amd64/pcb.h b/sys/include/arch/amd64/pcb.h new file mode 100644 index 0000000..5d06ade --- /dev/null +++ b/sys/include/arch/amd64/pcb.h @@ -0,0 +1,40 @@ +/* + * Copyright (c) 2023-2024 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. + */ + +#ifndef _MACHINE_PCB_H_ +#define _MACHINE_PCB_H_ + +#include +#include + +struct pcb { + struct vas addrsp; +}; + +#endif /* !_MACHINE_PCB_H_ */ diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index ba47a5c..b74cb00 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -32,17 +32,24 @@ #include #include +#include #if defined(_KERNEL) -#include #include +#include #endif /* _KERNEL */ #if defined(_KERNEL) struct proc { pid_t pid; - struct cpu_info *cpu; + struct trapframe tf; + struct pcb pcb; + size_t priority; + uintptr_t stack_base; + TAILQ_ENTRY(proc) link; }; +struct proc *this_td(void); + #endif /* _KERNEL */ #endif /* !_SYS_PROC_H_ */ diff --git a/sys/include/sys/sched.h b/sys/include/sys/sched.h index 33d546d..ae59d5f 100644 --- a/sys/include/sys/sched.h +++ b/sys/include/sys/sched.h @@ -30,10 +30,13 @@ #ifndef _SYS_SCHED_H_ #define _SYS_SCHED_H_ +#include + #if defined(_KERNEL) void sched_init(void); void sched_enter(void); +void sched_enqueue_td(struct proc *td); #endif /* _KERNEL */ #endif /* !_SYS_SCHED_H_ */ diff --git a/sys/kern/kern_sched.c b/sys/kern/kern_sched.c index b79d682..c370311 100644 --- a/sys/kern/kern_sched.c +++ b/sys/kern/kern_sched.c @@ -33,8 +33,11 @@ #include #include #include +#include +#include #include #include +#include #define pr_trace(fmt, ...) kprintf("ksched: " fmt, ##__VA_ARGS__) @@ -48,6 +51,12 @@ static sched_policy_t policy = SCHED_POLICY_RR; */ static struct sched_queue qlist[SCHED_NQUEUE]; +/* + * Thread queue lock - all operations to `qlist' + * must be done with this lock acquired. + */ +__cacheline_aligned static struct spinlock tdq_lock = {0}; + /* * Perform timer oneshot */ @@ -64,6 +73,54 @@ sched_oneshot(bool now) timer.oneshot_us(usec); } +static struct proc * +sched_dequeue_td(void) +{ + struct sched_queue *queue; + struct proc *td = NULL; + + spinlock_acquire(&tdq_lock); + + for (size_t i = 0; i < SCHED_NQUEUE; ++i) { + queue = &qlist[i]; + if (!TAILQ_EMPTY(&queue->q)) { + td = TAILQ_FIRST(&queue->q); + TAILQ_REMOVE(&queue->q, td, link); + break; + } + } + + spinlock_release(&tdq_lock); + return td; +} + +/* + * Add a thread to the scheduler. + */ +void +sched_enqueue_td(struct proc *td) +{ + struct sched_queue *queue; + + spinlock_acquire(&tdq_lock); + queue = &qlist[td->priority]; + + TAILQ_INSERT_TAIL(&queue->q, td, link); + spinlock_release(&tdq_lock); +} + +/* + * Return the currently running thread. + */ +struct proc * +this_td(void) +{ + struct cpu_info *ci; + + ci = this_cpu(); + return ci->curtd; +} + /* * Perform a context switch. * @@ -72,10 +129,30 @@ sched_oneshot(bool now) void sched_switch(struct trapframe *tf) { - static struct spinlock lock = {0}; + struct cpu_info *ci; + struct pcb *pcbp; + struct proc *next_td, *td; + + ci = this_cpu(); + td = ci->curtd; + + /* Do we have threads to switch to? */ + if ((next_td = sched_dequeue_td()) == NULL) { + sched_oneshot(false); + return; + } + + /* Re-enqueue the old thread */ + if (td != NULL) { + memcpy(&td->tf, tf, sizeof(td->tf)); + sched_enqueue_td(td); + } + + memcpy(tf, &next_td->tf, sizeof(*tf)); + ci->curtd = next_td; + pcbp = &next_td->pcb; - spinlock_acquire(&lock); - spinlock_release(&lock); + pmap_switch_vas(pcbp->addrsp); sched_oneshot(false); } -- cgit v1.2.3