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 ++++++ sys/include/dev/cons/cons.h | 54 +++++ sys/include/dev/cons/font.h | 40 +++ sys/include/dev/video/fbdev.h | 55 +++++ sys/include/lib/stdarg.h | 44 ++++ sys/include/lib/string.h | 43 ++++ sys/include/sys/ascii.h | 45 ++++ sys/include/sys/cdefs.h | 37 +++ sys/include/sys/limine.h | 498 ++++++++++++++++++++++++++++++++++++++ sys/include/sys/param.h | 43 ++++ sys/include/sys/reboot.h | 43 ++++ sys/include/sys/sio.h | 51 ++++ sys/include/sys/spinlock.h | 46 ++++ sys/include/sys/syslog.h | 43 ++++ sys/include/sys/types.h | 61 +++++ 24 files changed, 1752 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 create mode 100644 sys/include/dev/cons/cons.h create mode 100644 sys/include/dev/cons/font.h create mode 100644 sys/include/dev/video/fbdev.h create mode 100644 sys/include/lib/stdarg.h create mode 100644 sys/include/lib/string.h create mode 100644 sys/include/sys/ascii.h create mode 100644 sys/include/sys/cdefs.h create mode 100644 sys/include/sys/limine.h create mode 100644 sys/include/sys/param.h create mode 100644 sys/include/sys/reboot.h create mode 100644 sys/include/sys/sio.h create mode 100644 sys/include/sys/spinlock.h create mode 100644 sys/include/sys/syslog.h create mode 100644 sys/include/sys/types.h (limited to 'sys/include') 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_ */ diff --git a/sys/include/dev/cons/cons.h b/sys/include/dev/cons/cons.h new file mode 100644 index 0000000..15a7f59 --- /dev/null +++ b/sys/include/dev/cons/cons.h @@ -0,0 +1,54 @@ +/* + * 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 _DEV_CONS_H_ +#define _DEV_CONS_H_ + +#include +#include + +struct cons_screen { + struct fbdev fbdev; + uint32_t fg; + uint32_t bg; + + /* Private */ + uint32_t *fb_mem; + uint32_t nrows; + uint32_t ncols; + uint32_t ch_col; /* Current col */ + uint32_t ch_row; /* Current row */ +}; + +void cons_init(void); +int cons_putch(struct cons_screen *scr, char c); + +extern struct cons_screen g_root_scr; + +#endif /* !_DEV_CONS_H_ */ diff --git a/sys/include/dev/cons/font.h b/sys/include/dev/cons/font.h new file mode 100644 index 0000000..b9130fd --- /dev/null +++ b/sys/include/dev/cons/font.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 _CONS_FONT_H_ +#define _CONS_FONT_H_ + +#include + +#define FONT_WIDTH 8 +#define FONT_HEIGHT 16 + +extern const uint8_t CONS_FONT[]; + +#endif /* !_CONS_FONT_H_ */ diff --git a/sys/include/dev/video/fbdev.h b/sys/include/dev/video/fbdev.h new file mode 100644 index 0000000..33f8547 --- /dev/null +++ b/sys/include/dev/video/fbdev.h @@ -0,0 +1,55 @@ +/* + * 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 _DEV_FBDEV_H_ +#define _DEV_FBDEV_H_ + +#include +#include + +struct fbdev { + uint32_t *mem; + uint32_t width; + uint32_t height; + uint32_t pitch; +}; + +/* + * Get the index into the framebuffer with an x and y + * position. + */ +__always_inline static inline size_t +fbdev_get_index(const struct fbdev *fbdev, uint32_t x, uint32_t y) +{ + return x + y * (fbdev->pitch / 4); +} + +struct fbdev fbdev_get(void); + +#endif /* !_DEV_FBDEV_H_ */ diff --git a/sys/include/lib/stdarg.h b/sys/include/lib/stdarg.h new file mode 100644 index 0000000..5a3d67d --- /dev/null +++ b/sys/include/lib/stdarg.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 _LIB_STDARG_H_ +#define _LIB_STDARG_H_ + +#ifndef __GNUC_VA_LIST +#define __GNUC_VA_LIST +typedef __builtin_va_list __gnuc_va_list; +#endif /* __GNUC_VA_LIST */ + +typedef __gnuc_va_list va_list; + +#define va_start(ap, last) __builtin_va_start((ap), last) +#define va_end(ap) __builtin_va_end((ap)) +#define va_arg(ap, type) __builtin_va_arg((ap), type) + +#endif /* !_LIB_STDARG_H_ */ diff --git a/sys/include/lib/string.h b/sys/include/lib/string.h new file mode 100644 index 0000000..b96902b --- /dev/null +++ b/sys/include/lib/string.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 _LIB_STRING_H_ +#define _LIB_STRING_H_ + +#include +#include + +size_t strlen(const char *s); +char *itoa(int64_t value, char *buf, int base); + +int vsnprintf(char *s, size_t size, const char *fmt, va_list ap); +int snprintf(char *s, size_t size, const char *fmt, ...); +void *memcpy(void *dest, const void *src, size_t n); + +#endif /* !_LIB_STRING_H_ */ diff --git a/sys/include/sys/ascii.h b/sys/include/sys/ascii.h new file mode 100644 index 0000000..248c903 --- /dev/null +++ b/sys/include/sys/ascii.h @@ -0,0 +1,45 @@ +/* + * 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_ASCII_H_ +#define _SYS_ASCII_H_ + +#define ASCII_NUL 0x00 /* Nul */ +#define ASCII_BEL 0x07 /* Bell */ +#define ASCII_BS 0x08 /* Backspace */ +#define ASCII_HT 0x09 /* Horizontal tab */ +#define ASCII_LF 0x0A /* Line feed */ +#define ASCII_VT 0x0B /* Vertical tab */ +#define ASCII_FF 0x0C /* Form feed */ +#define ASCII_CR 0x0D /* Carriage return */ +#define ASCII_SO 0x0E /* Shift out */ +#define ASCII_SI 0x0F /* Shift in */ +#define ASCII_ESC 0x1B /* Escape */ + +#endif /* !_SYS_ASCII_H_ */ diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h new file mode 100644 index 0000000..9c1a466 --- /dev/null +++ b/sys/include/sys/cdefs.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 _SYS_CDEFS_H_ +#define _SYS_CDEFS_H_ + +#define __ASMV __asm__ __volatile__ +#define __always_inline __attribute__((__always_inline__)) +#define __packed __attribute__((__packed__)) + +#endif /* !_SYS_CDEFS_H_ */ diff --git a/sys/include/sys/limine.h b/sys/include/sys/limine.h new file mode 100644 index 0000000..57ccc4a --- /dev/null +++ b/sys/include/sys/limine.h @@ -0,0 +1,498 @@ +/* BSD Zero Clause License */ + +/* Copyright (C) 2022-2023 mintsuki and contributors. + * + * Permission to use, copy, modify, and/or distribute this software for any + * purpose with or without fee is hereby granted. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY + * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION + * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN + * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _LIMINE_H +#define _LIMINE_H 1 + +#if defined(_KERNEL) + +#ifdef __cplusplus +extern "C" { +#endif + +#include + +/* Misc */ + +#ifdef LIMINE_NO_POINTERS +# define LIMINE_PTR(TYPE) uint64_t +#else +# define LIMINE_PTR(TYPE) TYPE +#endif + +#ifdef __GNUC__ +# define LIMINE_DEPRECATED __attribute__((__deprecated__)) +# define LIMINE_DEPRECATED_IGNORE_START \ + _Pragma("GCC diagnostic push") \ + _Pragma("GCC diagnostic ignored \"-Wdeprecated-declarations\"") +# define LIMINE_DEPRECATED_IGNORE_END \ + _Pragma("GCC diagnostic pop") +#else +# define LIMINE_DEPRECATED +# define LIMINE_DEPRECATED_IGNORE_START +# define LIMINE_DEPRECATED_IGNORE_END +#endif + +#define LIMINE_COMMON_MAGIC 0xc7b1dd30df4c8b88, 0x0a82e883a194f07b + +struct limine_uuid { + uint32_t a; + uint16_t b; + uint16_t c; + uint8_t d[8]; +}; + +#define LIMINE_MEDIA_TYPE_GENERIC 0 +#define LIMINE_MEDIA_TYPE_OPTICAL 1 +#define LIMINE_MEDIA_TYPE_TFTP 2 + +struct limine_file { + uint64_t revision; + LIMINE_PTR(void *) address; + uint64_t size; + LIMINE_PTR(char *) path; + LIMINE_PTR(char *) cmdline; + uint32_t media_type; + uint32_t unused; + uint32_t tftp_ip; + uint32_t tftp_port; + uint32_t partition_index; + uint32_t mbr_disk_id; + struct limine_uuid gpt_disk_uuid; + struct limine_uuid gpt_part_uuid; + struct limine_uuid part_uuid; +}; + +/* Boot info */ + +#define LIMINE_BOOTLOADER_INFO_REQUEST { LIMINE_COMMON_MAGIC, 0xf55038d8e2a1202f, 0x279426fcf5f59740 } + +struct limine_bootloader_info_response { + uint64_t revision; + LIMINE_PTR(char *) name; + LIMINE_PTR(char *) version; +}; + +struct limine_bootloader_info_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_bootloader_info_response *) response; +}; + +/* Stack size */ + +#define LIMINE_STACK_SIZE_REQUEST { LIMINE_COMMON_MAGIC, 0x224ef0460a8e8926, 0xe1cb0fc25f46ea3d } + +struct limine_stack_size_response { + uint64_t revision; +}; + +struct limine_stack_size_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_stack_size_response *) response; + uint64_t stack_size; +}; + +/* HHDM */ + +#define LIMINE_HHDM_REQUEST { LIMINE_COMMON_MAGIC, 0x48dcf1cb8ad2b852, 0x63984e959a98244b } + +struct limine_hhdm_response { + uint64_t revision; + uint64_t offset; +}; + +struct limine_hhdm_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_hhdm_response *) response; +}; + +/* Framebuffer */ + +#define LIMINE_FRAMEBUFFER_REQUEST { LIMINE_COMMON_MAGIC, 0x9d5827dcd881dd75, 0xa3148604f6fab11b } + +#define LIMINE_FRAMEBUFFER_RGB 1 + +struct limine_video_mode { + uint64_t pitch; + uint64_t width; + uint64_t height; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; +}; + +struct limine_framebuffer { + LIMINE_PTR(void *) address; + uint64_t width; + uint64_t height; + uint64_t pitch; + uint16_t bpp; + uint8_t memory_model; + uint8_t red_mask_size; + uint8_t red_mask_shift; + uint8_t green_mask_size; + uint8_t green_mask_shift; + uint8_t blue_mask_size; + uint8_t blue_mask_shift; + uint8_t unused[7]; + uint64_t edid_size; + LIMINE_PTR(void *) edid; + /* Response revision 1 */ + uint64_t mode_count; + LIMINE_PTR(struct limine_video_mode **) modes; +}; + +struct limine_framebuffer_response { + uint64_t revision; + uint64_t framebuffer_count; + LIMINE_PTR(struct limine_framebuffer **) framebuffers; +}; + +struct limine_framebuffer_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_framebuffer_response *) response; +}; + +/* Terminal */ + +#define LIMINE_TERMINAL_REQUEST { LIMINE_COMMON_MAGIC, 0xc8ac59310c2b0844, 0xa68d0c7265d38878 } + +#define LIMINE_TERMINAL_CB_DEC 10 +#define LIMINE_TERMINAL_CB_BELL 20 +#define LIMINE_TERMINAL_CB_PRIVATE_ID 30 +#define LIMINE_TERMINAL_CB_STATUS_REPORT 40 +#define LIMINE_TERMINAL_CB_POS_REPORT 50 +#define LIMINE_TERMINAL_CB_KBD_LEDS 60 +#define LIMINE_TERMINAL_CB_MODE 70 +#define LIMINE_TERMINAL_CB_LINUX 80 + +#define LIMINE_TERMINAL_CTX_SIZE ((uint64_t)(-1)) +#define LIMINE_TERMINAL_CTX_SAVE ((uint64_t)(-2)) +#define LIMINE_TERMINAL_CTX_RESTORE ((uint64_t)(-3)) +#define LIMINE_TERMINAL_FULL_REFRESH ((uint64_t)(-4)) + +/* Response revision 1 */ +#define LIMINE_TERMINAL_OOB_OUTPUT_GET ((uint64_t)(-10)) +#define LIMINE_TERMINAL_OOB_OUTPUT_SET ((uint64_t)(-11)) + +#define LIMINE_TERMINAL_OOB_OUTPUT_OCRNL (1 << 0) +#define LIMINE_TERMINAL_OOB_OUTPUT_OFDEL (1 << 1) +#define LIMINE_TERMINAL_OOB_OUTPUT_OFILL (1 << 2) +#define LIMINE_TERMINAL_OOB_OUTPUT_OLCUC (1 << 3) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONLCR (1 << 4) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONLRET (1 << 5) +#define LIMINE_TERMINAL_OOB_OUTPUT_ONOCR (1 << 6) +#define LIMINE_TERMINAL_OOB_OUTPUT_OPOST (1 << 7) + +LIMINE_DEPRECATED_IGNORE_START + +struct LIMINE_DEPRECATED limine_terminal; + +typedef void (*limine_terminal_write)(struct limine_terminal *, const char *, uint64_t); +typedef void (*limine_terminal_callback)(struct limine_terminal *, uint64_t, uint64_t, uint64_t, uint64_t); + +struct LIMINE_DEPRECATED limine_terminal { + uint64_t columns; + uint64_t rows; + LIMINE_PTR(struct limine_framebuffer *) framebuffer; +}; + +struct LIMINE_DEPRECATED limine_terminal_response { + uint64_t revision; + uint64_t terminal_count; + LIMINE_PTR(struct limine_terminal **) terminals; + LIMINE_PTR(limine_terminal_write) write; +}; + +struct LIMINE_DEPRECATED limine_terminal_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_terminal_response *) response; + LIMINE_PTR(limine_terminal_callback) callback; +}; + +LIMINE_DEPRECATED_IGNORE_END + +/* 5-level paging */ + +#define LIMINE_5_LEVEL_PAGING_REQUEST { LIMINE_COMMON_MAGIC, 0x94469551da9b3192, 0xebe5e86db7382888 } + +struct limine_5_level_paging_response { + uint64_t revision; +}; + +struct limine_5_level_paging_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_5_level_paging_response *) response; +}; + +/* SMP */ + +#define LIMINE_SMP_REQUEST { LIMINE_COMMON_MAGIC, 0x95a67b819a1b857e, 0xa0b61b723b6a73e0 } + +struct limine_smp_info; + +typedef void (*limine_goto_address)(struct limine_smp_info *); + +#if defined (__x86_64__) || defined (__i386__) + +#define LIMINE_SMP_X2APIC (1 << 0) + +struct limine_smp_info { + uint32_t processor_id; + uint32_t lapic_id; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_smp_response { + uint64_t revision; + uint32_t flags; + uint32_t bsp_lapic_id; + uint64_t cpu_count; + LIMINE_PTR(struct limine_smp_info **) cpus; +}; + +#elif defined (__aarch64__) + +struct limine_smp_info { + uint32_t processor_id; + uint32_t gic_iface_no; + uint64_t mpidr; + uint64_t reserved; + LIMINE_PTR(limine_goto_address) goto_address; + uint64_t extra_argument; +}; + +struct limine_smp_response { + uint64_t revision; + uint32_t flags; + uint64_t bsp_mpidr; + uint64_t cpu_count; + LIMINE_PTR(struct limine_smp_info **) cpus; +}; + +#else +#error Unknown architecture +#endif + +struct limine_smp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smp_response *) response; + uint64_t flags; +}; + +/* Memory map */ + +#define LIMINE_MEMMAP_REQUEST { LIMINE_COMMON_MAGIC, 0x67cf3d9d378a806f, 0xe304acdfc50c3c62 } + +#define LIMINE_MEMMAP_USABLE 0 +#define LIMINE_MEMMAP_RESERVED 1 +#define LIMINE_MEMMAP_ACPI_RECLAIMABLE 2 +#define LIMINE_MEMMAP_ACPI_NVS 3 +#define LIMINE_MEMMAP_BAD_MEMORY 4 +#define LIMINE_MEMMAP_BOOTLOADER_RECLAIMABLE 5 +#define LIMINE_MEMMAP_KERNEL_AND_MODULES 6 +#define LIMINE_MEMMAP_FRAMEBUFFER 7 + +struct limine_memmap_entry { + uint64_t base; + uint64_t length; + uint64_t type; +}; + +struct limine_memmap_response { + uint64_t revision; + uint64_t entry_count; + LIMINE_PTR(struct limine_memmap_entry **) entries; +}; + +struct limine_memmap_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_memmap_response *) response; +}; + +/* Entry point */ + +#define LIMINE_ENTRY_POINT_REQUEST { LIMINE_COMMON_MAGIC, 0x13d86c035a1cd3e1, 0x2b0caa89d8f3026a } + +typedef void (*limine_entry_point)(void); + +struct limine_entry_point_response { + uint64_t revision; +}; + +struct limine_entry_point_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_entry_point_response *) response; + LIMINE_PTR(limine_entry_point) entry; +}; + +/* Kernel File */ + +#define LIMINE_KERNEL_FILE_REQUEST { LIMINE_COMMON_MAGIC, 0xad97e90e83f1ed67, 0x31eb5d1c5ff23b69 } + +struct limine_kernel_file_response { + uint64_t revision; + LIMINE_PTR(struct limine_file *) kernel_file; +}; + +struct limine_kernel_file_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_kernel_file_response *) response; +}; + +/* Module */ + +#define LIMINE_MODULE_REQUEST { LIMINE_COMMON_MAGIC, 0x3e7e279702be32af, 0xca1c4f3bd1280cee } + +#define LIMINE_INTERNAL_MODULE_REQUIRED (1 << 0) + +struct limine_internal_module { + LIMINE_PTR(const char *) path; + LIMINE_PTR(const char *) cmdline; + uint64_t flags; +}; + +struct limine_module_response { + uint64_t revision; + uint64_t module_count; + LIMINE_PTR(struct limine_file **) modules; +}; + +struct limine_module_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_module_response *) response; + + /* Request revision 1 */ + uint64_t internal_module_count; + LIMINE_PTR(struct limine_internal_module **) internal_modules; +}; + +/* RSDP */ + +#define LIMINE_RSDP_REQUEST { LIMINE_COMMON_MAGIC, 0xc5e77b6b397e7b43, 0x27637845accdcf3c } + +struct limine_rsdp_response { + uint64_t revision; + LIMINE_PTR(void *) address; +}; + +struct limine_rsdp_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_rsdp_response *) response; +}; + +/* SMBIOS */ + +#define LIMINE_SMBIOS_REQUEST { LIMINE_COMMON_MAGIC, 0x9e9046f11e095391, 0xaa4a520fefbde5ee } + +struct limine_smbios_response { + uint64_t revision; + LIMINE_PTR(void *) entry_32; + LIMINE_PTR(void *) entry_64; +}; + +struct limine_smbios_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_smbios_response *) response; +}; + +/* EFI system table */ + +#define LIMINE_EFI_SYSTEM_TABLE_REQUEST { LIMINE_COMMON_MAGIC, 0x5ceba5163eaaf6d6, 0x0a6981610cf65fcc } + +struct limine_efi_system_table_response { + uint64_t revision; + LIMINE_PTR(void *) address; +}; + +struct limine_efi_system_table_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_efi_system_table_response *) response; +}; + +/* Boot time */ + +#define LIMINE_BOOT_TIME_REQUEST { LIMINE_COMMON_MAGIC, 0x502746e184c088aa, 0xfbc5ec83e6327893 } + +struct limine_boot_time_response { + uint64_t revision; + int64_t boot_time; +}; + +struct limine_boot_time_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_boot_time_response *) response; +}; + +/* Kernel address */ + +#define LIMINE_KERNEL_ADDRESS_REQUEST { LIMINE_COMMON_MAGIC, 0x71ba76863cc55f63, 0xb2644a48c516a487 } + +struct limine_kernel_address_response { + uint64_t revision; + uint64_t physical_base; + uint64_t virtual_base; +}; + +struct limine_kernel_address_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_kernel_address_response *) response; +}; + +/* Device Tree Blob */ + +#define LIMINE_DTB_REQUEST { LIMINE_COMMON_MAGIC, 0xb40ddb48fb54bac7, 0x545081493f81ffb7 } + +struct limine_dtb_response { + uint64_t revision; + LIMINE_PTR(void *) dtb_ptr; +}; + +struct limine_dtb_request { + uint64_t id[4]; + uint64_t revision; + LIMINE_PTR(struct limine_dtb_response *) response; +}; + +#ifdef __cplusplus +} +#endif /* _KERNEL */ +#endif + +#endif diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h new file mode 100644 index 0000000..7631057 --- /dev/null +++ b/sys/include/sys/param.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 _SYS_PARAM_H_ +#define _SYS_PARAM_H_ + +/* Bit related macros */ +#define ISSET(v, f) ((v) & (f)) +#define BIT(n) (1 << (n)) + +/* Min/max macros */ +#define MIN(a,b) (((a) < (b)) ? (a) : (b)) +#define MAX(a,b) (((a) > (b)) ? (a) : (b)) + +#define NELEM(a) (sizeof(a) / sizeof(a[0])) + +#endif /* _SYS_PARAM_H_ */ diff --git a/sys/include/sys/reboot.h b/sys/include/sys/reboot.h new file mode 100644 index 0000000..21b7e7a --- /dev/null +++ b/sys/include/sys/reboot.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 _SYS_REBOOT_H_ +#define _SYS_REBOOT_H_ + +#include +#include + +#define REBOOT_HALT BIT(0) /* Halt instead of rebooting */ + +#if defined(_KERNEL) + +void cpu_reboot(int method); + +#endif /* _KERNEL */ +#endif /* _SYS_REBOOT_H_ */ diff --git a/sys/include/sys/sio.h b/sys/include/sys/sio.h new file mode 100644 index 0000000..b4da6a8 --- /dev/null +++ b/sys/include/sys/sio.h @@ -0,0 +1,51 @@ +/* + * 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_SIO_H_ +#define _SYS_SIO_H_ + +#include + +#if defined(_KERNEL) + +/* + * System I/O transaction + * + * This structure describes a system I/O transaction + * and contains common fields that are used + * with system I/O. + */ +struct sio_txn { + void *buf; /* Source/dest buffer */ + off_t offset; /* Transfer offset */ + size_t len; /* Length in bytes */ +}; + +#endif /* _KERNEL */ +#endif /* _SYS_SIO_H_ */ diff --git a/sys/include/sys/spinlock.h b/sys/include/sys/spinlock.h new file mode 100644 index 0000000..42f6848 --- /dev/null +++ b/sys/include/sys/spinlock.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 _SYS_SPINLOCK_H_ +#define _SYS_SPINLOCK_H_ + +#include + +struct spinlock { + volatile bool lock; +}; + +#if defined(_KERNEL) + +void spinlock_acquire(struct spinlock *lock); +void spinlock_release(struct spinlock *lock); + +#endif + +#endif /* !_SYS_SPINLOCK_H_ */ diff --git a/sys/include/sys/syslog.h b/sys/include/sys/syslog.h new file mode 100644 index 0000000..9a044b9 --- /dev/null +++ b/sys/include/sys/syslog.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 _SYS_SYSLOG_H_ +#define _SYS_SYSLOG_H_ + +#include + +#if defined(_KERNEL) + +#define OMIT_TIMESTAMP "\x01" + +void kprintf(const char *fmt, ...); +void vkprintf(const char *fmt, va_list *ap); + +#endif /* !_KERNEL */ +#endif /* !_SYS_SYSLOG_H_ */ diff --git a/sys/include/sys/types.h b/sys/include/sys/types.h new file mode 100644 index 0000000..fad34c7 --- /dev/null +++ b/sys/include/sys/types.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 _SYS_TYPES_H_ +#define _SYS_TYPES_H_ + +#define true 1 +#define false 0 +#define NULL ((void *)0) + +typedef signed char int8_t; +typedef unsigned char uint8_t; +typedef short int16_t; +typedef unsigned short uint16_t; +typedef int int32_t; +typedef unsigned int uint32_t; +#if __SIZEOF_LONG__ == 8 +typedef long int64_t; +typedef unsigned long uint64_t; +#endif + +#if __SIZEOF_SIZE_T__ == 8 +typedef uint64_t size_t; +typedef int64_t ssize_t; /* Byte count or error */ +#elif __SIZEOF_SIZE_T__ == 4 +typedef uint32_t size_t; +typedef int32_t ssize_t; /* Byte count or error */ +#else +#error "Unsupported size_t size" +#endif + +typedef size_t uintptr_t; +typedef _Bool bool; + +#endif /* _SYS_TYPES_H_ */ -- cgit v1.2.3 From 758ffd773a962c3d2e3f95f0d342d5b5d4ea6f08 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 14:55:49 -0400 Subject: kernel: Add initial virtual memory code Signed-off-by: Ian Moffett --- sys/include/vm/vm.h | 42 ++++++++++++++++++++++++++++++++++++++++++ sys/vm/vm_init.c | 36 ++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) create mode 100644 sys/include/vm/vm.h create mode 100644 sys/vm/vm_init.c (limited to 'sys/include') diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h new file mode 100644 index 0000000..a4a073f --- /dev/null +++ b/sys/include/vm/vm.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 _VM_H_ +#define _VM_H_ + +#include +#include + +extern volatile struct limine_hhdm_request g_hhdm_request; + +#define VM_HIGHER_HALF (g_hhdm_request.response->offset) +#define PHYS_TO_VIRT(phys) (void *)((uintptr_t)phys + VM_HIGHER_HALF) +#define VIRT_TO_PHYS(virt) ((uintptr_t)virt - VM_HIGHER_HALF) + +#endif diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c new file mode 100644 index 0000000..255821a --- /dev/null +++ b/sys/vm/vm_init.c @@ -0,0 +1,36 @@ +/* + * 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 + +volatile struct limine_hhdm_request g_hhdm_request = { + .id = LIMINE_HHDM_REQUEST, + .revision = 0 +}; -- cgit v1.2.3 From 54096dae0fd8ae38161caa27c76355657a1bcf84 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 14:56:28 -0400 Subject: kernel: lib: Add memcmp() Signed-off-by: Ian Moffett --- sys/include/lib/string.h | 2 ++ sys/lib/string/memcmp.c | 45 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 47 insertions(+) create mode 100644 sys/lib/string/memcmp.c (limited to 'sys/include') diff --git a/sys/include/lib/string.h b/sys/include/lib/string.h index b96902b..a9ceb64 100644 --- a/sys/include/lib/string.h +++ b/sys/include/lib/string.h @@ -38,6 +38,8 @@ char *itoa(int64_t value, char *buf, int base); int vsnprintf(char *s, size_t size, const char *fmt, va_list ap); int snprintf(char *s, size_t size, const char *fmt, ...); + void *memcpy(void *dest, const void *src, size_t n); +int memcmp(const void *s1, const void *s2, size_t n); #endif /* !_LIB_STRING_H_ */ diff --git a/sys/lib/string/memcmp.c b/sys/lib/string/memcmp.c new file mode 100644 index 0000000..fb6eeaf --- /dev/null +++ b/sys/lib/string/memcmp.c @@ -0,0 +1,45 @@ +/* + * 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 + +int +memcmp(const void *s1, const void *s2, size_t n) +{ + if (n != 0) { + const unsigned char *p1 = s1, *p2 = s2; + + do { + if (*p1++ != *p2++) { + return (*--p1 - *--p2); + } + } while (--n != 0); + } + return 0; +} -- cgit v1.2.3 From c38ba8e13a554d0bcc7a99d8ada5216ebc449b81 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 14:56:48 -0400 Subject: kernel: Add mmio(9) Signed-off-by: Ian Moffett --- sys/include/sys/mmio.h | 118 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 118 insertions(+) create mode 100644 sys/include/sys/mmio.h (limited to 'sys/include') diff --git a/sys/include/sys/mmio.h b/sys/include/sys/mmio.h new file mode 100644 index 0000000..8f573c3 --- /dev/null +++ b/sys/include/sys/mmio.h @@ -0,0 +1,118 @@ +/* + * 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. + */ + +/* + * For documentation: See mmio(9) + */ + +#ifndef _SYS_MMIO_H_ +#define _SYS_MMIO_H_ + +#include +#include +#if defined(_KERNEL) +#include +#endif + +#if defined(_KERNEL) + + +/* + * mmio_write - Writes to MMIO address with specific size + * + * @addr: Address to write to. + * @val: Value to write. + * + * These functions will add the higher half + * offset (VM_HIGHER_HALF) if the MMIO address + * is less than VM_HIGHER_HALF as it'll be safe + * to assume it's a physical address. Page faults + * from writes could be due to the resulting virtual + * address not being mapped. + */ +#define _MMIO_WRITE_TYPE(TYPE, SUFFIX) \ + static inline void \ + mmio_write##SUFFIX(volatile void *addr, TYPE val) \ + { \ + uintptr_t tmp; \ + \ + tmp = (uintptr_t)addr; \ + if (tmp < VM_HIGHER_HALF) { \ + tmp += VM_HIGHER_HALF; \ + } \ + *(volatile TYPE *)tmp = val; \ + __ASMV("" ::: "memory"); \ + } + +/* + * mmio_read - Does the same as mmio_write but for reading + * + * @addr: Address to read from. + */ +#define _MMIO_READ_TYPE(TYPE, SUFFIX) \ + static inline TYPE \ + mmio_read##SUFFIX(volatile void *addr) \ + { \ + uintptr_t tmp; \ + \ + tmp = (uintptr_t)addr; \ + if (tmp < VM_HIGHER_HALF) { \ + tmp += VM_HIGHER_HALF; \ + } \ + \ + __ASMV("" ::: "memory"); \ + return *(volatile TYPE *)tmp; \ + } + +/* + * To write to an MMIO address of, for example, + * 8 bits, use mmio_write8(addr, val) + */ +_MMIO_WRITE_TYPE(uint8_t, 8) +_MMIO_WRITE_TYPE(uint16_t, 16) +_MMIO_WRITE_TYPE(uint32_t, 32) +#if __SIZEOF_SIZE_T__ == 8 +_MMIO_WRITE_TYPE(uint64_t, 64) +#endif +__extension__ + +/* + * To read from an MMIO address of, for example, + * 8 bits, use mmio_read8(addr) + */ +_MMIO_READ_TYPE(uint8_t, 8) +_MMIO_READ_TYPE(uint16_t, 16) +_MMIO_READ_TYPE(uint32_t, 32) +#if __SIZEOF_SIZE_T__ == 8 +_MMIO_READ_TYPE(uint64_t, 64) +#endif +__extension__ + +#endif /* _KERNEL */ +#endif /* !_SYS_MMIO_H_ */ -- cgit v1.2.3 From 0263d78126287fdc81998ab2278379af9e9fab6f Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 14:57:45 -0400 Subject: kernel: Add panic() Signed-off-by: Ian Moffett --- sys/include/sys/panic.h | 38 ++++++++++++++++++++++++++++++++ sys/kern/kern_panic.c | 58 +++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 96 insertions(+) create mode 100644 sys/include/sys/panic.h create mode 100644 sys/kern/kern_panic.c (limited to 'sys/include') diff --git a/sys/include/sys/panic.h b/sys/include/sys/panic.h new file mode 100644 index 0000000..d3e6211 --- /dev/null +++ b/sys/include/sys/panic.h @@ -0,0 +1,38 @@ +/* + * 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_PANIC_H_ +#define _SYS_PANIC_H_ + +#if defined(_KERNEL) + +void panic(const char *fmt, ...); + +#endif /* _KERNEL */ +#endif /* !_SYS_PANIC_H_ */ diff --git a/sys/kern/kern_panic.c b/sys/kern/kern_panic.c new file mode 100644 index 0000000..0a17456 --- /dev/null +++ b/sys/kern/kern_panic.c @@ -0,0 +1,58 @@ +/* + * 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 + +/* + * Tells the user something terribly wrong happened then + * halting the system as soon as possible. + * + * XXX: There is no need to cleanup stuff here (e.g `va_list ap`) + * as we won't be returning from here anyways and the source + * of the panic could be *anywhere* so it's best not to mess with + * things. + */ +void +panic(const char *fmt, ...) +{ + va_list ap; + static struct spinlock lock = {0}; + + spinlock_acquire(&lock); /* Never released */ + va_start(ap, fmt); + + kprintf(OMIT_TIMESTAMP "panic: "); + vkprintf(fmt, &ap); + + cpu_reboot(REBOOT_HALT); + __builtin_unreachable(); +} -- cgit v1.2.3 From d6f85b7c3f4c4d28d1a80799618535786af24b8f Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 15:49:22 -0400 Subject: kernel: Add timer abstraction Signed-off-by: Ian Moffett --- sys/dev/timer.c | 112 ++++++++++++++++++++++++++++++++++++++++++++++++ sys/include/dev/timer.h | 87 +++++++++++++++++++++++++++++++++++++ 2 files changed, 199 insertions(+) create mode 100644 sys/dev/timer.c create mode 100644 sys/include/dev/timer.h (limited to 'sys/include') diff --git a/sys/dev/timer.c b/sys/dev/timer.c new file mode 100644 index 0000000..4293508 --- /dev/null +++ b/sys/dev/timer.c @@ -0,0 +1,112 @@ +/* + * 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 + +/* + * When a timer on the machine has been registered + * to the Hyra kernel, they'll be added to the Hyra timer + * registry. + */ +static const struct timer *tmr_registry[TIMER_ID_COUNT] = { 0 }; + +/* + * Returns true if the timer ID given + * is valid. + * + * @id: ID to verify. + */ +static inline bool +is_timer_id_valid(timer_id_t id) +{ + return id < TIMER_ID_COUNT; +} + +/* + * Adds timer on the machine to the timer registry. To be specific, + * this function writes information about the specific timer to the + * timer registry. However, it will not overwrite an entry. To do this + * you must use tmr_registry_overwrite(), of course with caution. + * + * @id: ID of timer to register. + * @tmr: Timer descriptor to register. + */ +tmrr_status_t +register_timer(timer_id_t id, const struct timer *tmr) +{ + if (!is_timer_id_valid(id)) + return TMRR_INVALID_TYPE; + + if (tmr_registry[id] != NULL) + return TMRR_HAS_ENTRY; + + tmr_registry[id] = tmr; + return TMRR_SUCCESS; +} + +/* + * Overwrites an entry within the timer registery. + * Use with caution. + * + * @id: ID of entry to overwrite. + * @tmr: Timer descriptor to write. + */ +tmrr_status_t +tmr_registry_overwrite(timer_id_t id, const struct timer *tmr) +{ + if (!is_timer_id_valid(id)) + return TMRR_INVALID_TYPE; + + tmr_registry[id] = tmr; + return TMRR_SUCCESS; +} + +/* + * Requests a specific timer descriptor + * with a specific ID. + * + * @id: ID to request. + * @tmr_out: Pointer to memory that'll hold the + * requested descriptor. + */ +tmrr_status_t +req_timer(timer_id_t id, struct timer *tmr_out) +{ + if (!is_timer_id_valid(id)) + return TMRR_INVALID_TYPE; + + if (tmr_registry[id] == NULL) + return TMRR_EMPTY_ENTRY; + + if (tmr_out == NULL) + return TMRR_INVALID_ARG; + + *tmr_out = *tmr_registry[id]; + return TMRR_SUCCESS; +} diff --git a/sys/include/dev/timer.h b/sys/include/dev/timer.h new file mode 100644 index 0000000..813f2aa --- /dev/null +++ b/sys/include/dev/timer.h @@ -0,0 +1,87 @@ +/* + * 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 _DEV_TIMER_H_ +#define _DEV_TIMER_H_ + +#include + +/* Timer IDs */ +#define TIMER_SCHED 0x00000000U /* Scheduler reserved timer */ +#define TIMER_GP 0x00000001U /* General purpose timer */ + +/* Number of timer IDs, adjust when adding timer IDs */ +#define TIMER_ID_COUNT 2 + +/* Timer registry status */ +#define TMRR_SUCCESS 0x00000000U /* Successful */ +#define TMRR_HAS_ENTRY 0x00000001U /* Already has an entry */ +#define TMRR_INVALID_TYPE 0x00000002U /* Invalid timer id */ +#define TMRR_EMPTY_ENTRY 0x00000003U /* Entry is empty */ +#define TMRR_INVALID_ARG 0x00000004U /* Invalid iface arg */ + +/* See timer ID defines */ +typedef uint8_t timer_id_t; + +/* See timer registry status */ +typedef int tmrr_status_t; + +/* + * Represents a timer, pointer fields + * are optional and may be set to NULL, therefore + * it is paramount to verify any function or general + * pointer field within this struct is checked for + * a NULL value. Fields should be NULL if the timer + * driver implementation doesn't implement support + * for a functionality. + * + * XXX: The msleep, usleep, ... functions must return + * either EXIT_SUCCESS and EXIT_FAILURE from sys/errno.h + * ONLY. + */ +struct timer { + const char *name; /* e.g "HPET" */ + size_t(*calibrate)(void); /* Returns frequency, 0 for unspecified */ + size_t(*get_time_usec)(void); /* Time since init (microseconds) */ + size_t(*get_time_sec)(void); /* Time since init (seconds) */ + int(*msleep)(size_t ms); + int(*usleep)(size_t us); + int(*nsleep)(size_t ns); + void(*periodic_ms)(size_t ms); + void(*periodic_us)(size_t ms); + void(*oneshot_ms)(size_t ms); + void(*oneshot_us)(size_t ms); + void(*stop)(void); +}; + +tmrr_status_t register_timer(timer_id_t id, const struct timer *tmr); +tmrr_status_t tmr_registry_overwrite(timer_id_t, const struct timer *tmr); +tmrr_status_t req_timer(timer_id_t id, struct timer *tmr_out); + +#endif /* !_DEV_TIMER_H_ */ -- cgit v1.2.3 From 996e41f4d86d9369d62700383ab090bdba2be9a7 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 15:50:57 -0400 Subject: kernel: Add initial ACPI code Signed-off-by: Ian Moffett --- sys/dev/acpi/acpi_init.c | 110 ++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_subr.c | 82 ++++++++++++++++++++++++++ sys/include/dev/acpi/acpi.h | 36 ++++++++++++ sys/include/dev/acpi/acpivar.h | 40 +++++++++++++ sys/include/dev/acpi/tables.h | 130 +++++++++++++++++++++++++++++++++++++++++ sys/kern/init_main.c | 4 ++ 6 files changed, 402 insertions(+) create mode 100644 sys/dev/acpi/acpi_init.c create mode 100644 sys/dev/acpi/acpi_subr.c create mode 100644 sys/include/dev/acpi/acpi.h create mode 100644 sys/include/dev/acpi/acpivar.h create mode 100644 sys/include/dev/acpi/tables.h (limited to 'sys/include') diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c new file mode 100644 index 0000000..a8423e4 --- /dev/null +++ b/sys/dev/acpi/acpi_init.c @@ -0,0 +1,110 @@ +/* + * 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 +#if defined(__x86_64__) +#include +#endif /* __x86_64__ */ + +#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) + +static struct acpi_root_sdt *root_sdt = NULL; +static size_t root_sdt_entries = 0; +static volatile struct limine_rsdp_request rsdp_req = { + .id = LIMINE_RSDP_REQUEST, + .revision = 0 +}; + +/* + * Writes out OEMID of ACPI header. + * + * @type: Type of structure (e.g RSDP) + * @oemid: OEMID of structure. + */ +static void +acpi_print_oemid(const char *type, char oemid[OEMID_SIZE]) +{ + if (type != NULL) { + pr_trace("%s OEMID: ", type); + } + + for (size_t i = 0; i < OEMID_SIZE; ++i) { + kprintf(OMIT_TIMESTAMP "%c", oemid[i]); + } + + kprintf(OMIT_TIMESTAMP "\n"); +} + +struct acpi_root_sdt * +acpi_get_root_sdt(void) +{ + return root_sdt; +} + +size_t +acpi_get_root_sdt_len(void) +{ + return root_sdt_entries; +} + +void +acpi_init(void) +{ + struct acpi_rsdp *rsdp; + + if (rsdp_req.response == NULL) { + panic("RSDP request has no response\n"); + } + + /* Fetch the RSDP */ + rsdp = rsdp_req.response->address; + acpi_print_oemid("RSDP", rsdp->oemid); + + /* Fetch the root SDT */ + if (rsdp->revision >= 2) { + root_sdt = PHYS_TO_VIRT(rsdp->xsdt_addr); + pr_trace("Using XSDT as root SDT\n"); + } else { + root_sdt = PHYS_TO_VIRT(rsdp->rsdt_addr); + pr_trace("Using RSDT as root SDT\n"); + } + + if (acpi_checksum(&root_sdt->hdr) != 0) { + panic("Root SDT checksum is invalid!\n"); + } + + root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; +} diff --git a/sys/dev/acpi/acpi_subr.c b/sys/dev/acpi/acpi_subr.c new file mode 100644 index 0000000..7cf3287 --- /dev/null +++ b/sys/dev/acpi/acpi_subr.c @@ -0,0 +1,82 @@ +/* + * 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 + +/* + * Compute the ACPI checksum of a header. + * + * @hdr: HDR to check. + * + * Must return zero to be a valid checksum! + */ +uint8_t +acpi_checksum(struct acpi_header *hdr) +{ + uint8_t sum = 0; + + for (int i = 0; i < hdr->length; ++i) { + sum += ((char *)hdr)[i]; + } + + return sum; +} + +/* + * Looks up an ACPI table with a specific + * signature e.g "APIC" for MADT (if present). + * + * @query: The specific query to make e.g "APIC" + */ +void * +acpi_query(const char *query) +{ + struct acpi_header *hdr; + struct acpi_root_sdt *root_sdt; + size_t root_sdt_len, signature_len; + + root_sdt = acpi_get_root_sdt(); + root_sdt_len = acpi_get_root_sdt_len(); + signature_len = sizeof(hdr->signature); + + for (size_t i = 0; i < root_sdt_len; ++i) { + hdr = (struct acpi_header *)PHYS_TO_VIRT(root_sdt->tables[i]); + + if (memcmp(hdr->signature, query, signature_len) == 0) { + return (void *)hdr; + } + } + + return NULL; +} diff --git a/sys/include/dev/acpi/acpi.h b/sys/include/dev/acpi/acpi.h new file mode 100644 index 0000000..4c5b7d9 --- /dev/null +++ b/sys/include/dev/acpi/acpi.h @@ -0,0 +1,36 @@ +/* + * 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 _ACPI_H_ +#define _ACPI_H_ + +void *acpi_query(const char *query); +void acpi_init(void); + +#endif /* !_ACPI_H_ */ diff --git a/sys/include/dev/acpi/acpivar.h b/sys/include/dev/acpi/acpivar.h new file mode 100644 index 0000000..9a37dfb --- /dev/null +++ b/sys/include/dev/acpi/acpivar.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 _ACPI_ACPIVAR_H_ +#define _ACPI_ACPIVAR_H_ + +#include +#include + +uint8_t acpi_checksum(struct acpi_header *hdr); +struct acpi_root_sdt *acpi_get_root_sdt(void); +size_t acpi_get_root_sdt_len(void); + +#endif /* !_ACPI_ACPIVAR_H_ */ diff --git a/sys/include/dev/acpi/tables.h b/sys/include/dev/acpi/tables.h new file mode 100644 index 0000000..d5bfd52 --- /dev/null +++ b/sys/include/dev/acpi/tables.h @@ -0,0 +1,130 @@ +/* + * 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 _ACPI_TABLES_H_ +#define _ACPI_TABLES_H_ + +#include +#include + +#define OEMID_SIZE 6 + +struct __packed acpi_header { + char signature[4]; /* ASCII signature string */ + uint32_t length; /* Length of table in bytes */ + uint8_t revision; /* Revision of the structure */ + uint8_t checksum; /* Checksum of the header */ + char oemid[OEMID_SIZE]; /* OEM-supplied string that IDs the OEM */ + char oem_table_id[8]; /* OEM-supplied string (used by OEM) */ + uint32_t oem_revision; /* OEM-supplied revision number */ + uint32_t creator_id; /* Vendor ID of creator utility */ + uint32_t creator_revision; /* Revision of creator utility */ +}; + +struct __packed acpi_rsdp { + uint64_t signature; /* RSD PTR */ + uint8_t checksum; /* Structure checksum */ + char oemid[OEMID_SIZE]; /* OEM-supplied string that IDs the OEM */ + uint8_t revision; /* Revision of the structure */ + uint32_t rsdt_addr; /* RSDT physical address */ + + /* Reserved if revision < 2 */ + uint32_t length; /* Length of table in bytes */ + uint64_t xsdt_addr; /* XSDT physical address */ + uint8_t ext_checksum; /* Extended checksum */ + uint8_t reserved[3]; +}; + +/* + * XSDT or RSDT depending + * on what revision the header + * says. + */ +struct __packed acpi_root_sdt { + struct acpi_header hdr; + uint32_t tables[]; +}; + +struct __packed acpi_madt { + struct acpi_header hdr; + uint32_t lapic_addr; + uint32_t flags; +}; + +struct __packed apic_header { + uint8_t type; + uint8_t length; +}; + +struct __packed local_apic { + struct apic_header hdr; + uint8_t processor_id; + uint8_t apic_id; + uint32_t flags; +}; + +struct __packed ioapic { + struct apic_header hdr; + uint8_t ioapic_id; + uint8_t reserved; + uint32_t ioapic_addr; + uint32_t gsi_base; +}; + +struct __packed interrupt_override { + struct apic_header hdr; + uint8_t bus; + uint8_t source; /* IRQ */ + uint32_t interrupt; /* GSI */ + uint16_t flags; +}; + +struct __packed acpi_gas { + uint8_t address_space_id; + uint8_t register_bit_width; + uint8_t register_bit_offset; + uint8_t reserved; + uint64_t address; +}; + +struct __packed acpi_hpet { + struct acpi_header hdr; + uint8_t hardware_rev_id; + uint8_t comparator_count : 5; + uint8_t counter_size : 1; + uint8_t reserved : 1; + uint8_t legacy_replacement : 1; + uint16_t pci_vendor_id; + struct acpi_gas gas; + uint8_t hpet_number; + uint16_t minimum_tick; + uint8_t page_protection; +}; + +#endif /* _ACPI_TABLES_H_ */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index d520542..0071a20 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include int @@ -40,6 +41,9 @@ main(void) kprintf("Starting Hyra/%s v%s: %s\n", HYRA_ARCH, HYRA_VERSION, HYRA_BUILDDATE); + /* Start the ACPI subsystem */ + acpi_init(); + /* Startup the BSP */ cpu_startup(); -- 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') 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 4f8e9e197cd55a4a7b05a782996d66a9ca1b212f Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 17:37:24 -0400 Subject: kernel: Add bitmap helper macros Signed-off-by: Ian Moffett --- sys/include/sys/param.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sys/include') diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h index 7631057..91566ae 100644 --- a/sys/include/sys/param.h +++ b/sys/include/sys/param.h @@ -38,6 +38,11 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) +/* Bitmap helper macros */ +#define setbit(a, b) ((a)[(b) >> 3] |= BIT(b % 8)) +#define clrbit(a, b) ((a)[(b) >> 3] &= ~BIT(b % 8)) +#define testbit(a, b) (ISSET((a)[(b) >> 3], BIT(b % 8))) + #define NELEM(a) (sizeof(a) / sizeof(a[0])) #endif /* _SYS_PARAM_H_ */ -- cgit v1.2.3 From bba9dc6afbd65a81e61093e1f16bd354fb34885e Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 17:37:38 -0400 Subject: kernel: Add ALIGN_UP/ALIGN_DOWN macros Signed-off-by: Ian Moffett --- sys/include/sys/param.h | 4 ++++ 1 file changed, 4 insertions(+) (limited to 'sys/include') diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h index 91566ae..d6c5a2b 100644 --- a/sys/include/sys/param.h +++ b/sys/include/sys/param.h @@ -38,6 +38,10 @@ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) #define MAX(a,b) (((a) > (b)) ? (a) : (b)) +/* Align up/down a value */ +#define ALIGN_DOWN(value, align) ((value) & ~((align)-1)) +#define ALIGN_UP(value, align) (((value) + (align)-1) & ~((align)-1)) + /* Bitmap helper macros */ #define setbit(a, b) ((a)[(b) >> 3] |= BIT(b % 8)) #define clrbit(a, b) ((a)[(b) >> 3] &= ~BIT(b % 8)) -- cgit v1.2.3 From 45d9b05c8e5f18d566631260267b47ea779e7743 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 17:41:08 -0400 Subject: kernel: lib: Add memset() Signed-off-by: Ian Moffett --- sys/include/lib/string.h | 1 + sys/lib/string/memset.c | 40 ++++++++++++++++++++++++++++++++++++++++ 2 files changed, 41 insertions(+) create mode 100644 sys/lib/string/memset.c (limited to 'sys/include') diff --git a/sys/include/lib/string.h b/sys/include/lib/string.h index a9ceb64..89c728f 100644 --- a/sys/include/lib/string.h +++ b/sys/include/lib/string.h @@ -41,5 +41,6 @@ int snprintf(char *s, size_t size, const char *fmt, ...); void *memcpy(void *dest, const void *src, size_t n); int memcmp(const void *s1, const void *s2, size_t n); +void *memset(void *s, int c, size_t n); #endif /* !_LIB_STRING_H_ */ diff --git a/sys/lib/string/memset.c b/sys/lib/string/memset.c new file mode 100644 index 0000000..76c453d --- /dev/null +++ b/sys/lib/string/memset.c @@ -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. + */ + +#include + +void * +memset(void *s, int c, size_t n) +{ + for (size_t i = 0; i < n; ++i) { + ((char *)s)[i] = c; + } + + return s; +} -- cgit v1.2.3 From 8d545ea74f1387c7c99b88ee12ed26fe84bf6061 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 17:42:10 -0400 Subject: kernel: vm: Add physical memory allocator Signed-off-by: Ian Moffett --- sys/include/vm/physmem.h | 39 ++++++++++ sys/include/vm/vm.h | 4 ++ sys/vm/vm_init.c | 7 ++ sys/vm/vm_physmem.c | 184 +++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 234 insertions(+) create mode 100644 sys/include/vm/physmem.h create mode 100644 sys/vm/vm_physmem.c (limited to 'sys/include') diff --git a/sys/include/vm/physmem.h b/sys/include/vm/physmem.h new file mode 100644 index 0000000..196a9a8 --- /dev/null +++ b/sys/include/vm/physmem.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 _VM_PHYSMEM_H_ +#define _VM_PHYSMEM_H_ + +#include + +void vm_physmem_init(void); +uintptr_t vm_alloc_frame(size_t count); +void vm_free_frame(uintptr_t base, size_t count); + +#endif /* !_VM_PHYSMEM_H_ */ diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h index a4a073f..a2caa8c 100644 --- a/sys/include/vm/vm.h +++ b/sys/include/vm/vm.h @@ -39,4 +39,8 @@ extern volatile struct limine_hhdm_request g_hhdm_request; #define PHYS_TO_VIRT(phys) (void *)((uintptr_t)phys + VM_HIGHER_HALF) #define VIRT_TO_PHYS(virt) ((uintptr_t)virt - VM_HIGHER_HALF) +#define DEFAULT_PAGESIZE 4096 + +void vm_init(void); + #endif diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index 255821a..3e9718d 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -29,8 +29,15 @@ #include #include +#include volatile struct limine_hhdm_request g_hhdm_request = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; + +void +vm_init(void) +{ + vm_physmem_init(); +} diff --git a/sys/vm/vm_physmem.c b/sys/vm/vm_physmem.c new file mode 100644 index 0000000..19e3927 --- /dev/null +++ b/sys/vm/vm_physmem.c @@ -0,0 +1,184 @@ +/* + * 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 + +size_t highest_frame_idx = 0; +size_t bitmap_size = 0; +size_t bitmap_free_start = 0; + +uint8_t *bitmap; +static struct limine_memmap_response *resp = NULL; +static struct spinlock lock = {0}; + +static struct limine_memmap_request mmap_req = { + .id = LIMINE_MEMMAP_REQUEST, + .revision = 0 +}; + +/* + * Populate physical memory bitmap. + */ +static void +physmem_populate_bitmap(void) +{ + struct limine_memmap_entry *ent; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + /* This memory is not usable */ + continue; + } + + if (bitmap_free_start == 0) { + bitmap_free_start = ent->base / DEFAULT_PAGESIZE; + } + + for (size_t j = 0; j < ent->length; j += DEFAULT_PAGESIZE) { + clrbit(bitmap, (ent->base + j) / DEFAULT_PAGESIZE); + } + } +} + +/* + * Allocate physical memory for the bitmap + * we'll use to keep track of free memory. + */ +static void +physmem_alloc_bitmap(void) +{ + struct limine_memmap_entry *ent; + uintptr_t highest_addr = 0; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + /* This memory is not usable */ + continue; + } + + if (ent->length >= bitmap_size) { + bitmap = PHYS_TO_VIRT(ent->base); + memset(bitmap, 0xFF, bitmap_size); + ent->length -= bitmap_size; + ent->base += bitmap_size; + return; + } + + highest_addr = MAX(highest_addr, ent->base + ent->length); + } +} + + +/* + * Init the physical memory bitmap. + */ +static void +physmem_init_bitmap(void) +{ + uintptr_t highest_addr = 0; + struct limine_memmap_entry *ent; + + for (size_t i = 0; i < resp->entry_count; ++i) { + ent = resp->entries[i]; + + if (ent->type != LIMINE_MEMMAP_USABLE) { + continue; + } + + highest_addr = MAX(highest_addr, ent->base + ent->length); + } + + highest_frame_idx = highest_addr / DEFAULT_PAGESIZE; + bitmap_size = ALIGN_UP(highest_frame_idx / 8, DEFAULT_PAGESIZE); + + physmem_alloc_bitmap(); + physmem_populate_bitmap(); +} + +/* + * Allocate page frames. + * + * @count: Number of frames to allocate. + */ +uintptr_t +vm_alloc_frame(size_t count) +{ + size_t frames = 0; + uintptr_t ret = 0; + + spinlock_acquire(&lock); + for (size_t i = 0; i < highest_frame_idx; ++i) { + if (!testbit(bitmap, i)) { + /* We have a free page */ + if (++frames != count) { + continue; + } + + for (size_t j = i; j < i + count; ++j) { + setbit(bitmap, j); + } + + ret = i * DEFAULT_PAGESIZE; + break; + } + } + + spinlock_release(&lock); + return ret; +} + +void +vm_free_frame(uintptr_t base, size_t count) +{ + size_t stop_at = base + (count * DEFAULT_PAGESIZE); + + spinlock_acquire(&lock); + for (uintptr_t p = base; p < stop_at; p += DEFAULT_PAGESIZE) { + clrbit(bitmap, p / DEFAULT_PAGESIZE); + } + spinlock_release(&lock); +} + +void +vm_physmem_init(void) +{ + resp = mmap_req.response; + physmem_init_bitmap(); +} -- 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') 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 f04bb79fcab54e1ec3a03706e9c02f50a7317cd6 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 22:16:16 -0400 Subject: kernel: Add sys/errno.h Signed-off-by: Ian Moffett --- sys/include/sys/errno.h | 156 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 156 insertions(+) create mode 100644 sys/include/sys/errno.h (limited to 'sys/include') diff --git a/sys/include/sys/errno.h b/sys/include/sys/errno.h new file mode 100644 index 0000000..769c71c --- /dev/null +++ b/sys/include/sys/errno.h @@ -0,0 +1,156 @@ +/* + * 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_ERRNO_H_ +#define _SYS_ERRNO_H_ + +#define EPERM 1 /* Not super-user */ +#define ENOENT 2 /* No such file or directory */ +#define ESRCH 3 /* No such process */ +#define EINTR 4 /* Interrupted system call */ +#define EIO 5 /* I/O error */ +#define ENXIO 6 /* No such device or address */ +#define E2BIG 7 /* Arg list too long */ +#define ENOEXEC 8 /* Exec format error */ +#define EBADF 9 /* Bad file number */ +#define ECHILD 10 /* No children */ +#define EAGAIN 11 /* No more processes */ +#define ENOMEM 12 /* Not enough core */ +#define EACCES 13 /* Permission denied */ +#define EFAULT 14 /* Bad address */ +#define ENOTBLK 15 /* Block device required */ +#define EBUSY 16 /* Mount device busy */ +#define EEXIST 17 /* File exists */ +#define EXDEV 18 /* Cross-device link */ +#define ENODEV 19 /* No such device */ +#define ENOTDIR 20 /* Not a directory */ +#define EISDIR 21 /* Is a directory */ +#define EINVAL 22 /* Invalid argument */ +#define ENFILE 23 /* Too many open files in system */ +#define EMFILE 24 /* Too many open files */ +#define ENOTTY 25 /* Not a typewriter */ +#define ETXTBSY 26 /* Text file busy */ +#define EFBIG 27 /* File too large */ +#define ENOSPC 28 /* No space left on device */ +#define ESPIPE 29 /* Illegal seek */ +#define EROFS 30 /* Read only file system */ +#define EMLINK 31 /* Too many links */ +#define EPIPE 32 /* Broken pipe */ +#define EDOM 33 /* Math arg out of domain of func */ +#define ERANGE 34 /* Math result not representable */ +#define ENOMSG 35 /* No message of desired type */ +#define EIDRM 36 /* Identifier removed */ +#define ECHRNG 37 /* Channel number out of range */ +#define EL2NSYNC 38 /* Level 2 not synchronized */ +#define EL3HLT 39 /* Level 3 halted */ +#define EL3RST 40 /* Level 3 reset */ +#define ELNRNG 41 /* Link number out of range */ +#define EUNATCH 42 /* Protocol driver not attached */ +#define ENOCSI 43 /* No CSI structure available */ +#define EL2HLT 44 /* Level 2 halted */ +#define EDEADLK 45 /* Deadlock condition */ +#define ENOLCK 46 /* No record locks available */ +#define EBADE 50 /* Invalid exchange */ +#define EBADR 51 /* Invalid request descriptor */ +#define EXFULL 52 /* Exchange full */ +#define ENOANO 53 /* No anode */ +#define EBADRQC 54 /* Invalid request code */ +#define EBADSLT 55 /* Invalid slot */ +#define EDEADLOCK 56 /* File locking deadlock error */ +#define EBFONT 57 /* Bad font file fmt */ +#define ENOSTR 60 /* Device not a stream */ +#define ENODATA 61 /* No data (for no delay io) */ +#define ETIME 62 /* Timer expired */ +#define ENOSR 63 /* Out of streams resources */ +#define ENONET 64 /* Machine is not on the network */ +#define ENOPKG 65 /* Package not installed */ +#define EREMOTE 66 /* The object is remote */ +#define ENOLINK 67 /* The link has been severed */ +#define EADV 68 /* Advertise error */ +#define ESRMNT 69 /* Srmount error */ +#define ECOMM 70 /* Communication error on send */ +#define EPROTO 71 /* Protocol error */ +#define EMULTIHOP 74 /* Multihop attempted */ +#define ELBIN 75 /* Inode is remote (not really error) */ +#define EDOTDOT 76 /* Cross mount point (not really error) */ +#define EBADMSG 77 /* Trying to read unreadable message */ +#define EFTYPE 79 /* Inappropriate file type or format */ +#define ENOTUNIQ 80 /* Given log. name not unique */ +#define EBADFD 81 /* f.d. invalid for this operation */ +#define EREMCHG 82 /* Remote address changed */ +#define ELIBACC 83 /* Can't access a needed shared lib */ +#define ELIBBAD 84 /* Accessing a corrupted shared lib */ +#define ELIBSCN 85 /* .lib section in a.out corrupted */ +#define ELIBMAX 86 /* Attempting to link in too many libs */ +#define ELIBEXEC 87 /* Attempting to exec a shared library */ +#define ENOSYS 88 /* Function not implemented */ +#define ENMFILE 89 /* No more files */ +#define ENOTEMPTY 90 /* Directory not empty */ +#define ENAMETOOLONG 91 /* File or path name too long */ +#define ELOOP 92 /* Too many symbolic links */ +#define EOPNOTSUPP 95 /* Operation not supported on transport endpoint */ +#define EPFNOSUPPORT 96 /* Protocol family not supported */ +#define ECONNRESET 104 /* Connection reset by peer */ +#define ENOBUFS 105 /* No buffer space available */ +#define EAFNOSUPPORT 106 /* Address family not supported by protocol family */ +#define EPROTOTYPE 107 /* Protocol wrong type for socket */ +#define ENOTSOCK 108 /* Socket operation on non-socket */ +#define ENOPROTOOPT 109 /* Protocol not available */ +#define ESHUTDOWN 110 /* Can't send after socket shutdown */ +#define ECONNREFUSED 111 /* Connection refused */ +#define EADDRINUSE 112 /* Address already in use */ +#define ECONNABORTED 113 /* Connection aborted */ +#define ENETUNREACH 114 /* Network is unreachable */ +#define ENETDOWN 115 /* Network interface is not configured */ +#define ETIMEDOUT 116 /* Connection timed out */ +#define EHOSTDOWN 117 /* Host is down */ +#define EHOSTUNREACH 118 /* Host is unreachable */ +#define EINPROGRESS 119 /* Connection already in progress */ +#define EALREADY 120 /* Socket already connected */ +#define EDESTADDRREQ 121 /* Destination address required */ +#define EMSGSIZE 122 /* Message too long */ +#define EPROTONOSUPPORT 123 /* Unknown protocol */ +#define ESOCKTNOSUPPORT 124 /* Socket type not supported */ +#define EADDRNOTAVAIL 125 /* Address not available */ +#define ENETRESET 126 +#define EISCONN 127 /* Socket is already connected */ +#define ENOTCONN 128 /* Socket is not connected */ +#define ETOOMANYREFS 129 +#define EPROCLIM 130 +#define EUSERS 131 +#define EDQUOT 132 +#define ESTALE 133 +#define ENOTSUP 134 /* Not supported */ +#define ENOMEDIUM 135 /* No medium (in tape drive) */ +#define ENOSHARE 136 /* No such host or network path */ +#define ECASECLASH 137 /* Filename exists with different case */ +#define EILSEQ 138 +#define EOVERFLOW 139 /* Value too large for defined data type */ + +#endif -- cgit v1.2.3 From efb3cd0e2ad09f409d66534d44ff07a55e9f1171 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 4 Jun 2024 22:17:28 -0400 Subject: kernel/amd64: acpi: Support parsing MADT Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/acpi_machdep.c | 74 +++++++++++++++++++++++++++++++++++++ sys/dev/acpi/acpi_init.c | 1 + sys/include/dev/acpi/acpivar.h | 2 + sys/include/dev/acpi/tables.h | 5 +++ 4 files changed, 82 insertions(+) create mode 100644 sys/arch/amd64/amd64/acpi_machdep.c (limited to 'sys/include') diff --git a/sys/arch/amd64/amd64/acpi_machdep.c b/sys/arch/amd64/amd64/acpi_machdep.c new file mode 100644 index 0000000..5f3b3bf --- /dev/null +++ b/sys/arch/amd64/amd64/acpi_machdep.c @@ -0,0 +1,74 @@ +/* + * 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 + +#define pr_trace(fmt, ...) kprintf("acpi: " fmt, ##__VA_ARGS__) + +int +acpi_init_madt(void) +{ + struct acpi_madt *madt = acpi_query("APIC"); + struct apic_header *apichdr; + struct ioapic *ioapic = NULL; + uint8_t *cur, *end; + + if (madt == NULL) { + panic("Could not find MADT!\n"); + } + + cur = (uint8_t *)(madt + 1); + end = (uint8_t *)madt + madt->hdr.length; + + while (cur < end) { + apichdr = (void *)cur; + if (apichdr->type == APIC_TYPE_IO_APIC) { + /* + * TODO: Figure out how to use multiple I/O APICs + */ + if (ioapic != NULL) { + pr_trace("Skipping I/O APIC with ID %d\n", ioapic->ioapic_id); + break; + } + + ioapic = (struct ioapic *)cur; + pr_trace("Detected I/O APIC (id=%d, gsi_base=%d)\n", + ioapic->ioapic_id, ioapic->gsi_base); + } + + cur += apichdr->length; + } + + return 0; + +} diff --git a/sys/dev/acpi/acpi_init.c b/sys/dev/acpi/acpi_init.c index f445d95..4c0ae1b 100644 --- a/sys/dev/acpi/acpi_init.c +++ b/sys/dev/acpi/acpi_init.c @@ -118,4 +118,5 @@ acpi_init(void) root_sdt_entries = (root_sdt->hdr.length - sizeof(root_sdt->hdr)) / 4; acpi_init_hpet(); + acpi_init_madt(); } diff --git a/sys/include/dev/acpi/acpivar.h b/sys/include/dev/acpi/acpivar.h index 9a37dfb..9cfe945 100644 --- a/sys/include/dev/acpi/acpivar.h +++ b/sys/include/dev/acpi/acpivar.h @@ -35,6 +35,8 @@ uint8_t acpi_checksum(struct acpi_header *hdr); struct acpi_root_sdt *acpi_get_root_sdt(void); + size_t acpi_get_root_sdt_len(void); +int acpi_init_madt(void); #endif /* !_ACPI_ACPIVAR_H_ */ diff --git a/sys/include/dev/acpi/tables.h b/sys/include/dev/acpi/tables.h index d5bfd52..1dca890 100644 --- a/sys/include/dev/acpi/tables.h +++ b/sys/include/dev/acpi/tables.h @@ -33,6 +33,11 @@ #include #include +/* MADT APIC header types */ +#define APIC_TYPE_LOCAL_APIC 0 +#define APIC_TYPE_IO_APIC 1 +#define APIC_TYPE_INTERRUPT_OVERRIDE 2 + #define OEMID_SIZE 6 struct __packed acpi_header { -- 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') 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') 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 694b5c9b8f1964fc6bf4352637055b85db135368 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 5 Jun 2024 23:26:48 -0400 Subject: kernel: Add __assert() Signed-off-by: Ian Moffett --- sys/include/lib/assert.h | 42 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 42 insertions(+) create mode 100644 sys/include/lib/assert.h (limited to 'sys/include') diff --git a/sys/include/lib/assert.h b/sys/include/lib/assert.h new file mode 100644 index 0000000..78ebe05 --- /dev/null +++ b/sys/include/lib/assert.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 _LIB_ASSERT_H_ +#define _LIB_ASSERT_H_ + +#include +#include + +#define __assert(condition) \ + if ((uintptr_t)(condition) == 0) { \ + panic("Assert \"%s\" failed (%s() at %s:%d)\n", #condition, \ + __func__, __FILE__, __LINE__); \ + } + +#endif /* !_LIB_ASSERT_H_ */ -- cgit v1.2.3 From e67e3a62edf7d1948d721e0fc62917906798add1 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 5 Jun 2024 23:27:21 -0400 Subject: kernel: vm: Add port of TLSF Signed-off-by: Ian Moffett --- sys/include/vm/dynalloc.h | 39 ++ sys/include/vm/tlsf.h | 90 ++++ sys/include/vm/vm.h | 10 + sys/vm/tlsf.c | 1264 +++++++++++++++++++++++++++++++++++++++++++++ sys/vm/vm_dynalloc.c | 81 +++ sys/vm/vm_init.c | 24 + 6 files changed, 1508 insertions(+) create mode 100644 sys/include/vm/dynalloc.h create mode 100644 sys/include/vm/tlsf.h create mode 100644 sys/vm/tlsf.c create mode 100644 sys/vm/vm_dynalloc.c (limited to 'sys/include') diff --git a/sys/include/vm/dynalloc.h b/sys/include/vm/dynalloc.h new file mode 100644 index 0000000..11d8f31 --- /dev/null +++ b/sys/include/vm/dynalloc.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 _VM_DYNALLOC_H_ +#define _VM_DYNALLOC_H_ + +#include + +void *dynalloc(size_t sz); +void *dynrealloc(void *old_ptr, size_t newsize); +void dynfree(void *ptr); + +#endif /* !_VM_DYNALLOC_H_ */ diff --git a/sys/include/vm/tlsf.h b/sys/include/vm/tlsf.h new file mode 100644 index 0000000..e9b5a91 --- /dev/null +++ b/sys/include/vm/tlsf.h @@ -0,0 +1,90 @@ +#ifndef INCLUDED_tlsf +#define INCLUDED_tlsf + +/* +** Two Level Segregated Fit memory allocator, version 3.1. +** Written by Matthew Conte +** http://tlsf.baisoku.org +** +** Based on the original documentation by Miguel Masmano: +** http://www.gii.upv.es/tlsf/main/docs +** +** This implementation was written to the specification +** of the document, therefore no GPL restrictions apply. +** +** Copyright (c) 2006-2016, Matthew Conte +** All rights reserved. +** +** Redistribution and use in source and binary forms, with or without +** modification, are permitted provided that the following conditions are met: +** * Redistributions of source code must retain the above copyright +** notice, this list of conditions and the following disclaimer. +** * 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. +** * Neither the name of the copyright holder 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 MATTHEW CONTE 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 + +#if defined(__cplusplus) +extern "C" { +#endif + +/* tlsf_t: a TLSF structure. Can contain 1 to N pools. */ +/* pool_t: a block of memory that TLSF can manage. */ +typedef void* tlsf_t; +typedef void* pool_t; + +/* Create/destroy a memory pool. */ +tlsf_t tlsf_create(void* mem); +tlsf_t tlsf_create_with_pool(void* mem, size_t bytes); +void tlsf_destroy(tlsf_t tlsf); +pool_t tlsf_get_pool(tlsf_t tlsf); + +/* Add/remove memory pools. */ +pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes); +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool); + +/* malloc/memalign/realloc/free replacements. */ +void* tlsf_malloc(tlsf_t tlsf, size_t bytes); +void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t bytes); +void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size); +void tlsf_free(tlsf_t tlsf, void* ptr); + +/* Returns internal block size, not original request size */ +size_t tlsf_block_size(void* ptr); + +/* Overheads/limits of internal structures. */ +size_t tlsf_size(void); +size_t tlsf_align_size(void); +size_t tlsf_block_size_min(void); +size_t tlsf_block_size_max(void); +size_t tlsf_pool_overhead(void); +size_t tlsf_alloc_overhead(void); + +/* Debugging. */ +typedef void (*tlsf_walker)(void* ptr, size_t size, int used, void* user); +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user); +/* Returns nonzero if any internal consistency check fails. */ +int tlsf_check(tlsf_t tlsf); +int tlsf_check_pool(pool_t pool); + +#if defined(__cplusplus) +}; +#endif + +#endif diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h index a2caa8c..bf49e67 100644 --- a/sys/include/vm/vm.h +++ b/sys/include/vm/vm.h @@ -32,6 +32,8 @@ #include #include +#include +#include extern volatile struct limine_hhdm_request g_hhdm_request; @@ -41,6 +43,14 @@ extern volatile struct limine_hhdm_request g_hhdm_request; #define DEFAULT_PAGESIZE 4096 +struct vm_ctx { + size_t dynalloc_pool_sz; + uintptr_t dynalloc_pool_pa; + struct spinlock dynalloc_lock; + tlsf_t tlsf_ctx; +}; + +struct vm_ctx *vm_get_ctx(void); void vm_init(void); #endif diff --git a/sys/vm/tlsf.c b/sys/vm/tlsf.c new file mode 100644 index 0000000..d4a6ddf --- /dev/null +++ b/sys/vm/tlsf.c @@ -0,0 +1,1264 @@ +#include +#include +#include +#include +#include +#include + +#define printf kprintf + +#if defined(__cplusplus) +#define tlsf_decl inline +#else +#define tlsf_decl static +#endif + +/* +** Architecture-specific bit manipulation routines. +** +** TLSF achieves O(1) cost for malloc and free operations by limiting +** the search for a free block to a free list of guaranteed size +** adequate to fulfill the request, combined with efficient free list +** queries using bitmasks and architecture-specific bit-manipulation +** routines. +** +** Most modern processors provide instructions to count leading zeroes +** in a word, find the lowest and highest set bit, etc. These +** specific implementations will be used when available, falling back +** to a reasonably efficient generic implementation. +** +** NOTE: TLSF spec relies on ffs/fls returning value 0..31. +** ffs/fls return 1-32 by default, returning 0 for error. +*/ + +/* +** Detect whether or not we are building for a 32- or 64-bit (LP/LLP) +** architecture. There is no reliable portable method at compile-time. +*/ +#if defined (__alpha__) || defined (__ia64__) || defined (__x86_64__) \ + || defined (_WIN64) || defined (__LP64__) || defined (__LLP64__) +#define TLSF_64BIT +#endif + +/* +** gcc 3.4 and above have builtin support, specialized for architecture. +** Some compilers masquerade as gcc; patchlevel test filters them out. +*/ +#if defined (__GNUC__) && (__GNUC__ > 3 || (__GNUC__ == 3 && __GNUC_MINOR__ >= 4)) \ + && defined (__GNUC_PATCHLEVEL__) + +#if defined (__SNC__) +/* SNC for Playstation 3. */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __builtin_clz(reverse); + return bit - 1; +} + +#else + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return __builtin_ffs(word) - 1; +} + +#endif + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __builtin_clz(word) : 0; + return bit - 1; +} + +#elif defined (_MSC_VER) && (_MSC_VER >= 1400) && (defined (_M_IX86) || defined (_M_X64)) +/* Microsoft Visual C++ support on x86/X64 architectures. */ + +#include + +#pragma intrinsic(_BitScanReverse) +#pragma intrinsic(_BitScanForward) + +tlsf_decl int tlsf_fls(unsigned int word) +{ + unsigned long index; + return _BitScanReverse(&index, word) ? index : -1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + unsigned long index; + return _BitScanForward(&index, word) ? index : -1; +} + +#elif defined (_MSC_VER) && defined (_M_PPC) +/* Microsoft Visual C++ support on PowerPC architectures. */ + +#include + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = 32 - _CountLeadingZeros(word); + return bit - 1; +} + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - _CountLeadingZeros(reverse); + return bit - 1; +} + +#elif defined (__ARMCC_VERSION) +/* RealView Compilation Tools for ARM */ + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __clz(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __clz(word) : 0; + return bit - 1; +} + +#elif defined (__ghs__) +/* Green Hills support for PowerPC */ + +#include + +tlsf_decl int tlsf_ffs(unsigned int word) +{ + const unsigned int reverse = word & (~word + 1); + const int bit = 32 - __CLZ32(reverse); + return bit - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + const int bit = word ? 32 - __CLZ32(word) : 0; + return bit - 1; +} + +#else +/* Fall back to generic implementation. */ + +tlsf_decl int tlsf_fls_generic(unsigned int word) +{ + int bit = 32; + + if (!word) bit -= 1; + if (!(word & 0xffff0000)) { word <<= 16; bit -= 16; } + if (!(word & 0xff000000)) { word <<= 8; bit -= 8; } + if (!(word & 0xf0000000)) { word <<= 4; bit -= 4; } + if (!(word & 0xc0000000)) { word <<= 2; bit -= 2; } + if (!(word & 0x80000000)) { word <<= 1; bit -= 1; } + + return bit; +} + +/* Implement ffs in terms of fls. */ +tlsf_decl int tlsf_ffs(unsigned int word) +{ + return tlsf_fls_generic(word & (~word + 1)) - 1; +} + +tlsf_decl int tlsf_fls(unsigned int word) +{ + return tlsf_fls_generic(word) - 1; +} + +#endif + +/* Possibly 64-bit version of tlsf_fls. */ +#if defined (TLSF_64BIT) +tlsf_decl int tlsf_fls_sizet(size_t size) +{ + int high = (int)(size >> 32); + int bits = 0; + if (high) + { + bits = 32 + tlsf_fls(high); + } + else + { + bits = tlsf_fls((int)size & 0xffffffff); + + } + return bits; +} +#else +#define tlsf_fls_sizet tlsf_fls +#endif + +#undef tlsf_decl + +/* +** Constants. +*/ + +/* Public constants: may be modified. */ +enum tlsf_public +{ + /* log2 of number of linear subdivisions of block sizes. Larger + ** values require more memory in the control structure. Values of + ** 4 or 5 are typical. + */ + SL_INDEX_COUNT_LOG2 = 5, +}; + +/* Private constants: do not modify. */ +enum tlsf_private +{ +#if defined (TLSF_64BIT) + /* All allocation sizes and addresses are aligned to 8 bytes. */ + ALIGN_SIZE_LOG2 = 3, +#else + /* All allocation sizes and addresses are aligned to 4 bytes. */ + ALIGN_SIZE_LOG2 = 2, +#endif + ALIGN_SIZE = (1 << ALIGN_SIZE_LOG2), + + /* + ** We support allocations of sizes up to (1 << FL_INDEX_MAX) bits. + ** However, because we linearly subdivide the second-level lists, and + ** our minimum size granularity is 4 bytes, it doesn't make sense to + ** create first-level lists for sizes smaller than SL_INDEX_COUNT * 4, + ** or (1 << (SL_INDEX_COUNT_LOG2 + 2)) bytes, as there we will be + ** trying to split size ranges into more slots than we have available. + ** Instead, we calculate the minimum threshold size, and place all + ** blocks below that size into the 0th first-level list. + */ + +#if defined (TLSF_64BIT) + /* + ** TODO: We can increase this to support larger sizes, at the expense + ** of more overhead in the TLSF structure. + */ + FL_INDEX_MAX = 32, +#else + FL_INDEX_MAX = 30, +#endif + SL_INDEX_COUNT = (1 << SL_INDEX_COUNT_LOG2), + FL_INDEX_SHIFT = (SL_INDEX_COUNT_LOG2 + ALIGN_SIZE_LOG2), + FL_INDEX_COUNT = (FL_INDEX_MAX - FL_INDEX_SHIFT + 1), + + SMALL_BLOCK_SIZE = (1 << FL_INDEX_SHIFT), +}; + +/* +** Cast and min/max macros. +*/ + +#define tlsf_cast(t, exp) ((t) (exp)) +#define tlsf_min(a, b) ((a) < (b) ? (a) : (b)) +#define tlsf_max(a, b) ((a) > (b) ? (a) : (b)) + +/* +** Set assert macro, if it has not been provided by the user. +*/ +#if !defined (tlsf_assert) +#define tlsf_assert __assert +#endif + +/* +** Static assertion mechanism. +*/ + +#define _tlsf_glue2(x, y) x ## y +#define _tlsf_glue(x, y) _tlsf_glue2(x, y) +#define tlsf_static_assert(exp) \ + typedef char _tlsf_glue(static_assert, __LINE__) [(exp) ? 1 : -1] + +/* This code has been tested on 32- and 64-bit (LP/LLP) architectures. */ +tlsf_static_assert(sizeof(int) * CHAR_BIT == 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT >= 32); +tlsf_static_assert(sizeof(size_t) * CHAR_BIT <= 64); + +/* SL_INDEX_COUNT must be <= number of bits in sl_bitmap's storage type. */ +tlsf_static_assert(sizeof(unsigned int) * CHAR_BIT >= SL_INDEX_COUNT); + +/* Ensure we've properly tuned our sizes. */ +tlsf_static_assert(ALIGN_SIZE == SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + +/* +** Data structures and associated constants. +*/ + +/* +** Block header structure. +** +** There are several implementation subtleties involved: +** - The prev_phys_block field is only valid if the previous block is free. +** - The prev_phys_block field is actually stored at the end of the +** previous block. It appears at the beginning of this structure only to +** simplify the implementation. +** - The next_free / prev_free fields are only valid if the block is free. +*/ +typedef struct block_header_t +{ + /* Points to the previous physical block. */ + struct block_header_t* prev_phys_block; + + /* The size of this block, excluding the block header. */ + size_t size; + + /* Next and previous free blocks. */ + struct block_header_t* next_free; + struct block_header_t* prev_free; +} block_header_t; + +/* +** Since block sizes are always at least a multiple of 4, the two least +** significant bits of the size field are used to store the block status: +** - bit 0: whether block is busy or free +** - bit 1: whether previous block is busy or free +*/ +static const size_t block_header_free_bit = 1 << 0; +static const size_t block_header_prev_free_bit = 1 << 1; + +/* +** The size of the block header exposed to used blocks is the size field. +** The prev_phys_block field is stored *inside* the previous free block. +*/ +static const size_t block_header_overhead = sizeof(size_t); + +/* User data starts directly after the size field in a used block. */ +static const size_t block_start_offset = + offsetof(block_header_t, size) + sizeof(size_t); + +/* +** A free block must be large enough to store its header minus the size of +** the prev_phys_block field, and no larger than the number of addressable +** bits for FL_INDEX. +*/ +static const size_t block_size_min = + sizeof(block_header_t) - sizeof(block_header_t*); +static const size_t block_size_max = tlsf_cast(size_t, 1) << FL_INDEX_MAX; + + +/* The TLSF control structure. */ +typedef struct control_t +{ + /* Empty lists point at this block to indicate they are free. */ + block_header_t block_null; + + /* Bitmaps for free lists. */ + unsigned int fl_bitmap; + unsigned int sl_bitmap[FL_INDEX_COUNT]; + + /* Head of free lists. */ + block_header_t* blocks[FL_INDEX_COUNT][SL_INDEX_COUNT]; +} control_t; + +/* A type used for casting when doing pointer arithmetic. */ +typedef ptrdiff_t tlsfptr_t; + +/* +** block_header_t member functions. +*/ + +static size_t block_size(const block_header_t* block) +{ + return block->size & ~(block_header_free_bit | block_header_prev_free_bit); +} + +static void block_set_size(block_header_t* block, size_t size) +{ + const size_t oldsize = block->size; + block->size = size | (oldsize & (block_header_free_bit | block_header_prev_free_bit)); +} + +static int block_is_last(const block_header_t* block) +{ + return block_size(block) == 0; +} + +static int block_is_free(const block_header_t* block) +{ + return tlsf_cast(int, block->size & block_header_free_bit); +} + +static void block_set_free(block_header_t* block) +{ + block->size |= block_header_free_bit; +} + +static void block_set_used(block_header_t* block) +{ + block->size &= ~block_header_free_bit; +} + +static int block_is_prev_free(const block_header_t* block) +{ + return tlsf_cast(int, block->size & block_header_prev_free_bit); +} + +static void block_set_prev_free(block_header_t* block) +{ + block->size |= block_header_prev_free_bit; +} + +static void block_set_prev_used(block_header_t* block) +{ + block->size &= ~block_header_prev_free_bit; +} + +static block_header_t* block_from_ptr(const void* ptr) +{ + return tlsf_cast(block_header_t*, + tlsf_cast(unsigned char*, ptr) - block_start_offset); +} + +static void* block_to_ptr(const block_header_t* block) +{ + return tlsf_cast(void*, + tlsf_cast(unsigned char*, block) + block_start_offset); +} + +/* Return location of next block after block of given size. */ +static block_header_t* offset_to_block(const void* ptr, size_t size) +{ + return tlsf_cast(block_header_t*, tlsf_cast(tlsfptr_t, ptr) + size); +} + +/* Return location of previous block. */ +static block_header_t* block_prev(const block_header_t* block) +{ + tlsf_assert(block_is_prev_free(block) && "previous block must be free"); + return block->prev_phys_block; +} + +/* Return location of next existing block. */ +static block_header_t* block_next(const block_header_t* block) +{ + block_header_t* next = offset_to_block(block_to_ptr(block), + block_size(block) - block_header_overhead); + tlsf_assert(!block_is_last(block)); + return next; +} + +/* Link a new block with its physical neighbor, return the neighbor. */ +static block_header_t* block_link_next(block_header_t* block) +{ + block_header_t* next = block_next(block); + next->prev_phys_block = block; + return next; +} + +static void block_mark_as_free(block_header_t* block) +{ + /* Link the block to the next block, first. */ + block_header_t* next = block_link_next(block); + block_set_prev_free(next); + block_set_free(block); +} + +static void block_mark_as_used(block_header_t* block) +{ + block_header_t* next = block_next(block); + block_set_prev_used(next); + block_set_used(block); +} + +static size_t align_up(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return (x + (align - 1)) & ~(align - 1); +} + +static size_t align_down(size_t x, size_t align) +{ + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return x - (x & (align - 1)); +} + +static void* align_ptr(const void* ptr, size_t align) +{ + const tlsfptr_t aligned = + (tlsf_cast(tlsfptr_t, ptr) + (align - 1)) & ~(align - 1); + tlsf_assert(0 == (align & (align - 1)) && "must align to a power of two"); + return tlsf_cast(void*, aligned); +} + +/* +** Adjust an allocation size to be aligned to word size, and no smaller +** than internal minimum. +*/ +static size_t adjust_request_size(size_t size, size_t align) +{ + size_t adjust = 0; + if (size) + { + const size_t aligned = align_up(size, align); + + /* aligned sized must not exceed block_size_max or we'll go out of bounds on sl_bitmap */ + if (aligned < block_size_max) + { + adjust = tlsf_max(aligned, block_size_min); + } + } + return adjust; +} + +/* +** TLSF utility functions. In most cases, these are direct translations of +** the documentation found in the white paper. +*/ + +static void mapping_insert(size_t size, int* fli, int* sli) +{ + int fl, sl; + if (size < SMALL_BLOCK_SIZE) + { + /* Store small blocks in first list. */ + fl = 0; + sl = tlsf_cast(int, size) / (SMALL_BLOCK_SIZE / SL_INDEX_COUNT); + } + else + { + fl = tlsf_fls_sizet(size); + sl = tlsf_cast(int, size >> (fl - SL_INDEX_COUNT_LOG2)) ^ (1 << SL_INDEX_COUNT_LOG2); + fl -= (FL_INDEX_SHIFT - 1); + } + *fli = fl; + *sli = sl; +} + +/* This version rounds up to the next block size (for allocations) */ +static void mapping_search(size_t size, int* fli, int* sli) +{ + if (size >= SMALL_BLOCK_SIZE) + { + const size_t round = (1 << (tlsf_fls_sizet(size) - SL_INDEX_COUNT_LOG2)) - 1; + size += round; + } + mapping_insert(size, fli, sli); +} + +static block_header_t* search_suitable_block(control_t* control, int* fli, int* sli) +{ + int fl = *fli; + int sl = *sli; + + /* + ** First, search for a block in the list associated with the given + ** fl/sl index. + */ + unsigned int sl_map = control->sl_bitmap[fl] & (~0U << sl); + if (!sl_map) + { + /* No block exists. Search in the next largest first-level list. */ + const unsigned int fl_map = control->fl_bitmap & (~0U << (fl + 1)); + if (!fl_map) + { + /* No free blocks available, memory has been exhausted. */ + return 0; + } + + fl = tlsf_ffs(fl_map); + *fli = fl; + sl_map = control->sl_bitmap[fl]; + } + tlsf_assert(sl_map && "internal error - second level bitmap is null"); + sl = tlsf_ffs(sl_map); + *sli = sl; + + /* Return the first block in the free list. */ + return control->blocks[fl][sl]; +} + +/* Remove a free block from the free list.*/ +static void remove_free_block(control_t* control, block_header_t* block, int fl, int sl) +{ + block_header_t* prev = block->prev_free; + block_header_t* next = block->next_free; + tlsf_assert(prev && "prev_free field can not be null"); + tlsf_assert(next && "next_free field can not be null"); + next->prev_free = prev; + prev->next_free = next; + + /* If this block is the head of the free list, set new head. */ + if (control->blocks[fl][sl] == block) + { + control->blocks[fl][sl] = next; + + /* If the new head is null, clear the bitmap. */ + if (next == &control->block_null) + { + control->sl_bitmap[fl] &= ~(1U << sl); + + /* If the second bitmap is now empty, clear the fl bitmap. */ + if (!control->sl_bitmap[fl]) + { + control->fl_bitmap &= ~(1U << fl); + } + } + } +} + +/* Insert a free block into the free block list. */ +static void insert_free_block(control_t* control, block_header_t* block, int fl, int sl) +{ + block_header_t* current = control->blocks[fl][sl]; + tlsf_assert(current && "free list cannot have a null entry"); + tlsf_assert(block && "cannot insert a null entry into the free list"); + block->next_free = current; + block->prev_free = &control->block_null; + current->prev_free = block; + + tlsf_assert((uintptr_t)block_to_ptr(block) == (uintptr_t)align_ptr(block_to_ptr(block), ALIGN_SIZE) + && "block not aligned properly"); + /* + ** Insert the new block at the head of the list, and mark the first- + ** and second-level bitmaps appropriately. + */ + control->blocks[fl][sl] = block; + control->fl_bitmap |= (1U << fl); + control->sl_bitmap[fl] |= (1U << sl); +} + +/* Remove a given block from the free list. */ +static void block_remove(control_t* control, block_header_t* block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* Insert a given block into the free list. */ +static void block_insert(control_t* control, block_header_t* block) +{ + int fl, sl; + mapping_insert(block_size(block), &fl, &sl); + insert_free_block(control, block, fl, sl); +} + +static int block_can_split(block_header_t* block, size_t size) +{ + return block_size(block) >= sizeof(block_header_t) + size; +} + +/* Split a block into two, the second of which is free. */ +static block_header_t* block_split(block_header_t* block, size_t size) +{ + /* Calculate the amount of space left in the remaining block. */ + block_header_t* remaining = + offset_to_block(block_to_ptr(block), size - block_header_overhead); + + const size_t remain_size = block_size(block) - (size + block_header_overhead); + + tlsf_assert((uintptr_t)block_to_ptr(remaining) == (uintptr_t)align_ptr(block_to_ptr(remaining), ALIGN_SIZE) + && "remaining block not aligned properly"); + + tlsf_assert(block_size(block) == remain_size + size + block_header_overhead); + block_set_size(remaining, remain_size); + tlsf_assert(block_size(remaining) >= block_size_min && "block split with invalid size"); + + block_set_size(block, size); + block_mark_as_free(remaining); + + return remaining; +} + +/* Absorb a free block's storage into an adjacent previous free block. */ +static block_header_t* block_absorb(block_header_t* prev, block_header_t* block) +{ + tlsf_assert(!block_is_last(prev) && "previous block can't be last"); + /* Note: Leaves flags untouched. */ + prev->size += block_size(block) + block_header_overhead; + block_link_next(prev); + return prev; +} + +/* Merge a just-freed block with an adjacent previous free block. */ +static block_header_t* block_merge_prev(control_t* control, block_header_t* block) +{ + if (block_is_prev_free(block)) + { + block_header_t* prev = block_prev(block); + tlsf_assert(prev && "prev physical block can't be null"); + tlsf_assert(block_is_free(prev) && "prev block is not free though marked as such"); + block_remove(control, prev); + block = block_absorb(prev, block); + } + + return block; +} + +/* Merge a just-freed block with an adjacent free block. */ +static block_header_t* block_merge_next(control_t* control, block_header_t* block) +{ + block_header_t* next = block_next(block); + tlsf_assert(next && "next physical block can't be null"); + + if (block_is_free(next)) + { + tlsf_assert(!block_is_last(block) && "previous block can't be last"); + block_remove(control, next); + block = block_absorb(block, next); + } + + return block; +} + +/* Trim any trailing block space off the end of a block, return to pool. */ +static void block_trim_free(control_t* control, block_header_t* block, size_t size) +{ + tlsf_assert(block_is_free(block) && "block must be free"); + if (block_can_split(block, size)) + { + block_header_t* remaining_block = block_split(block, size); + block_link_next(block); + block_set_prev_free(remaining_block); + block_insert(control, remaining_block); + } +} + +/* Trim any trailing block space off the end of a used block, return to pool. */ +static void block_trim_used(control_t* control, block_header_t* block, size_t size) +{ + tlsf_assert(!block_is_free(block) && "block must be used"); + if (block_can_split(block, size)) + { + /* If the next block is free, we must coalesce. */ + block_header_t* remaining_block = block_split(block, size); + block_set_prev_used(remaining_block); + + remaining_block = block_merge_next(control, remaining_block); + block_insert(control, remaining_block); + } +} + +static block_header_t* block_trim_free_leading(control_t* control, block_header_t* block, size_t size) +{ + block_header_t* remaining_block = block; + if (block_can_split(block, size)) + { + /* We want the 2nd block. */ + remaining_block = block_split(block, size - block_header_overhead); + block_set_prev_free(remaining_block); + + block_link_next(block); + block_insert(control, block); + } + + return remaining_block; +} + +static block_header_t* block_locate_free(control_t* control, size_t size) +{ + int fl = 0, sl = 0; + block_header_t* block = 0; + + if (size) + { + mapping_search(size, &fl, &sl); + + /* + ** mapping_search can futz with the size, so for excessively large sizes it can sometimes wind up + ** with indices that are off the end of the block array. + ** So, we protect against that here, since this is the only callsite of mapping_search. + ** Note that we don't need to check sl, since it comes from a modulo operation that guarantees it's always in range. + */ + if (fl < FL_INDEX_COUNT) + { + block = search_suitable_block(control, &fl, &sl); + } + } + + if (block) + { + tlsf_assert(block_size(block) >= size); + remove_free_block(control, block, fl, sl); + } + + return block; +} + +static void* block_prepare_used(control_t* control, block_header_t* block, size_t size) +{ + void* p = 0; + if (block) + { + tlsf_assert(size && "size must be non-zero"); + block_trim_free(control, block, size); + block_mark_as_used(block); + p = block_to_ptr(block); + } + return p; +} + +/* Clear structure and point all empty lists at the null block. */ +static void control_construct(control_t* control) +{ + int i, j; + + control->block_null.next_free = &control->block_null; + control->block_null.prev_free = &control->block_null; + + control->fl_bitmap = 0; + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + control->sl_bitmap[i] = 0; + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + control->blocks[i][j] = &control->block_null; + } + } +} + +/* +** Debugging utilities. +*/ + +typedef struct integrity_t +{ + int prev_status; + int status; +} integrity_t; + +#define tlsf_insist(x) { tlsf_assert(x); if (!(x)) { status--; } } + +static void integrity_walker(void* ptr, size_t size, int used, void* user) +{ + block_header_t* block = block_from_ptr(ptr); + integrity_t* integ = tlsf_cast(integrity_t*, user); + const int this_prev_status = block_is_prev_free(block) ? 1 : 0; + const int this_status = block_is_free(block) ? 1 : 0; + const size_t this_block_size = block_size(block); + + int status = 0; + (void)used; + tlsf_insist(integ->prev_status == this_prev_status && "prev status incorrect"); + tlsf_insist(size == this_block_size && "block size incorrect"); + + integ->prev_status = this_status; + integ->status += status; +} + +int tlsf_check(tlsf_t tlsf) +{ + int i, j; + + control_t* control = tlsf_cast(control_t*, tlsf); + int status = 0; + + /* Check that the free lists and bitmaps are accurate. */ + for (i = 0; i < FL_INDEX_COUNT; ++i) + { + for (j = 0; j < SL_INDEX_COUNT; ++j) + { + const int fl_map = control->fl_bitmap & (1U << i); + const int sl_list = control->sl_bitmap[i]; + const int sl_map = sl_list & (1U << j); + const block_header_t* block = control->blocks[i][j]; + + /* Check that first- and second-level lists agree. */ + if (!fl_map) + { + tlsf_insist(!sl_map && "second-level map must be null"); + } + + if (!sl_map) + { + tlsf_insist((uint64_t)block == (uint64_t)&control->block_null && "block list must be null"); + continue; + } + + /* Check that there is at least one free block. */ + tlsf_insist(sl_list && "no free blocks in second-level map"); + tlsf_insist((uintptr_t)block != (uintptr_t)&control->block_null && "block should not be null"); + + while (block != &control->block_null) + { + int fli, sli; + tlsf_insist(block_is_free(block) && "block should be free"); + tlsf_insist(!block_is_prev_free(block) && "blocks should have coalesced"); + tlsf_insist(!block_is_free(block_next(block)) && "blocks should have coalesced"); + tlsf_insist(block_is_prev_free(block_next(block)) && "block should be free"); + tlsf_insist(block_size(block) >= block_size_min && "block not minimum size"); + + mapping_insert(block_size(block), &fli, &sli); + tlsf_insist(fli == i && sli == j && "block size indexed in wrong list"); + block = block->next_free; + } + } + } + + return status; +} + +#undef tlsf_insist + +static void default_walker(void* ptr, size_t size, int used, void* user) +{ + (void)user; + printf("\t%p %s size: %x (%p)\n", ptr, used ? "used" : "free", (unsigned int)size, block_from_ptr(ptr)); +} + +void tlsf_walk_pool(pool_t pool, tlsf_walker walker, void* user) +{ + tlsf_walker pool_walker = walker ? walker : default_walker; + block_header_t* block = + offset_to_block(pool, -(int)block_header_overhead); + + while (block && !block_is_last(block)) + { + pool_walker( + block_to_ptr(block), + block_size(block), + !block_is_free(block), + user); + block = block_next(block); + } +} + +size_t tlsf_block_size(void* ptr) +{ + size_t size = 0; + if (ptr) + { + const block_header_t* block = block_from_ptr(ptr); + size = block_size(block); + } + return size; +} + +int tlsf_check_pool(pool_t pool) +{ + /* Check that the blocks are physically correct. */ + integrity_t integ = { 0, 0 }; + tlsf_walk_pool(pool, integrity_walker, &integ); + + return integ.status; +} + +/* +** Size of the TLSF structures in a given memory block passed to +** tlsf_create, equal to the size of a control_t +*/ +size_t tlsf_size(void) +{ + return sizeof(control_t); +} + +size_t tlsf_align_size(void) +{ + return ALIGN_SIZE; +} + +size_t tlsf_block_size_min(void) +{ + return block_size_min; +} + +size_t tlsf_block_size_max(void) +{ + return block_size_max; +} + +/* +** Overhead of the TLSF structures in a given memory block passed to +** tlsf_add_pool, equal to the overhead of a free block and the +** sentinel block. +*/ +size_t tlsf_pool_overhead(void) +{ + return 2 * block_header_overhead; +} + +size_t tlsf_alloc_overhead(void) +{ + return block_header_overhead; +} + +pool_t tlsf_add_pool(tlsf_t tlsf, void* mem, size_t bytes) +{ + block_header_t* block; + block_header_t* next; + + const size_t pool_overhead = tlsf_pool_overhead(); + const size_t pool_bytes = align_down(bytes - pool_overhead, ALIGN_SIZE); + + if (((ptrdiff_t)mem % ALIGN_SIZE) != 0) + { + printf("tlsf_add_pool: Memory must be aligned by %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return 0; + } + + if (pool_bytes < block_size_min || pool_bytes > block_size_max) + { +#if defined (TLSF_64BIT) + printf("tlsf_add_pool: Memory size must be between 0x%x and 0x%x00 bytes.\n", + (unsigned int)(pool_overhead + block_size_min), + (unsigned int)((pool_overhead + block_size_max) / 256)); +#else + printf("tlsf_add_pool: Memory size must be between %u and %u bytes.\n", + (unsigned int)(pool_overhead + block_size_min), + (unsigned int)(pool_overhead + block_size_max)); +#endif + return 0; + } + + /* + ** Create the main free block. Offset the start of the block slightly + ** so that the prev_phys_block field falls outside of the pool - + ** it will never be used. + */ + block = offset_to_block(mem, -(tlsfptr_t)block_header_overhead); + block_set_size(block, pool_bytes); + block_set_free(block); + block_set_prev_used(block); + block_insert(tlsf_cast(control_t*, tlsf), block); + + /* Split the block to create a zero-size sentinel block. */ + next = block_link_next(block); + block_set_size(next, 0); + block_set_used(next); + block_set_prev_free(next); + + return mem; +} + +void tlsf_remove_pool(tlsf_t tlsf, pool_t pool) +{ + control_t* control = tlsf_cast(control_t*, tlsf); + block_header_t* block = offset_to_block(pool, -(int)block_header_overhead); + + int fl = 0, sl = 0; + + tlsf_assert(block_is_free(block) && "block should be free"); + tlsf_assert(!block_is_free(block_next(block)) && "next block should not be free"); + tlsf_assert(block_size(block_next(block)) == 0 && "next block size should be zero"); + + mapping_insert(block_size(block), &fl, &sl); + remove_free_block(control, block, fl, sl); +} + +/* +** TLSF main interface. +*/ + +#if _DEBUG +int test_ffs_fls() +{ + /* Verify ffs/fls work properly. */ + int rv = 0; + rv += (tlsf_ffs(0) == -1) ? 0 : 0x1; + rv += (tlsf_fls(0) == -1) ? 0 : 0x2; + rv += (tlsf_ffs(1) == 0) ? 0 : 0x4; + rv += (tlsf_fls(1) == 0) ? 0 : 0x8; + rv += (tlsf_ffs(0x80000000) == 31) ? 0 : 0x10; + rv += (tlsf_ffs(0x80008000) == 15) ? 0 : 0x20; + rv += (tlsf_fls(0x80000008) == 31) ? 0 : 0x40; + rv += (tlsf_fls(0x7FFFFFFF) == 30) ? 0 : 0x80; + +#if defined (TLSF_64BIT) + rv += (tlsf_fls_sizet(0x80000000) == 31) ? 0 : 0x100; + rv += (tlsf_fls_sizet(0x100000000) == 32) ? 0 : 0x200; + rv += (tlsf_fls_sizet(0xffffffffffffffff) == 63) ? 0 : 0x400; +#endif + + if (rv) + { + printf("test_ffs_fls: %x ffs/fls tests failed.\n", rv); + } + return rv; +} +#endif + +tlsf_t tlsf_create(void* mem) +{ +#if _DEBUG + if (test_ffs_fls()) + { + return 0; + } +#endif + + if (((tlsfptr_t)mem % ALIGN_SIZE) != 0) + { + printf("tlsf_create: Memory must be aligned to %u bytes.\n", + (unsigned int)ALIGN_SIZE); + return 0; + } + + control_construct(tlsf_cast(control_t*, mem)); + + return tlsf_cast(tlsf_t, mem); +} + +tlsf_t tlsf_create_with_pool(void* mem, size_t bytes) +{ + tlsf_t tlsf = tlsf_create(mem); + tlsf_add_pool(tlsf, (char*)mem + tlsf_size(), bytes - tlsf_size()); + return tlsf; +} + +void tlsf_destroy(tlsf_t tlsf) +{ + /* Nothing to do. */ + (void)tlsf; +} + +pool_t tlsf_get_pool(tlsf_t tlsf) +{ + return tlsf_cast(pool_t, (char*)tlsf + tlsf_size()); +} + +void* tlsf_malloc(tlsf_t tlsf, size_t size) +{ + control_t* control = tlsf_cast(control_t*, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + block_header_t* block = block_locate_free(control, adjust); + return block_prepare_used(control, block, adjust); +} + +void* tlsf_memalign(tlsf_t tlsf, size_t align, size_t size) +{ + control_t* control = tlsf_cast(control_t*, tlsf); + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + /* + ** We must allocate an additional minimum block size bytes so that if + ** our free block will leave an alignment gap which is smaller, we can + ** trim a leading free block and release it back to the pool. We must + ** do this because the previous physical block is in use, therefore + ** the prev_phys_block field is not valid, and we can't simply adjust + ** the size of that block. + */ + const size_t gap_minimum = sizeof(block_header_t); + const size_t size_with_gap = adjust_request_size(adjust + align + gap_minimum, align); + + /* + ** If alignment is less than or equals base alignment, we're done. + ** If we requested 0 bytes, return null, as tlsf_malloc(0) does. + */ + const size_t aligned_size = (adjust && align > ALIGN_SIZE) ? size_with_gap : adjust; + + block_header_t* block = block_locate_free(control, aligned_size); + + /* This can't be a static assert. */ + tlsf_assert(sizeof(block_header_t) == block_size_min + block_header_overhead); + + if (block) + { + void* ptr = block_to_ptr(block); + void* aligned = align_ptr(ptr, align); + size_t gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + + /* If gap size is too small, offset to next aligned boundary. */ + if (gap && gap < gap_minimum) + { + const size_t gap_remain = gap_minimum - gap; + const size_t offset = tlsf_max(gap_remain, align); + const void* next_aligned = tlsf_cast(void*, + tlsf_cast(tlsfptr_t, aligned) + offset); + + aligned = align_ptr(next_aligned, align); + gap = tlsf_cast(size_t, + tlsf_cast(tlsfptr_t, aligned) - tlsf_cast(tlsfptr_t, ptr)); + } + + if (gap) + { + tlsf_assert(gap >= gap_minimum && "gap size too small"); + block = block_trim_free_leading(control, block, gap); + } + } + + return block_prepare_used(control, block, adjust); +} + +void tlsf_free(tlsf_t tlsf, void* ptr) +{ + /* Don't attempt to free a NULL pointer. */ + if (ptr) + { + control_t* control = tlsf_cast(control_t*, tlsf); + block_header_t* block = block_from_ptr(ptr); + tlsf_assert(!block_is_free(block) && "block already marked as free"); + block_mark_as_free(block); + block = block_merge_prev(control, block); + block = block_merge_next(control, block); + block_insert(control, block); + } +} + +/* +** The TLSF block information provides us with enough information to +** provide a reasonably intelligent implementation of realloc, growing or +** shrinking the currently allocated block as required. +** +** This routine handles the somewhat esoteric edge cases of realloc: +** - a non-zero size with a null pointer will behave like malloc +** - a zero size with a non-null pointer will behave like free +** - a request that cannot be satisfied will leave the original buffer +** untouched +** - an extended buffer size will leave the newly-allocated area with +** contents undefined +*/ +void* tlsf_realloc(tlsf_t tlsf, void* ptr, size_t size) +{ + control_t* control = tlsf_cast(control_t*, tlsf); + void* p = 0; + + /* Zero-size requests are treated as free. */ + if (ptr && size == 0) + { + tlsf_free(tlsf, ptr); + } + /* Requests with NULL pointers are treated as malloc. */ + else if (!ptr) + { + p = tlsf_malloc(tlsf, size); + } + else + { + block_header_t* block = block_from_ptr(ptr); + block_header_t* next = block_next(block); + + const size_t cursize = block_size(block); + const size_t combined = cursize + block_size(next) + block_header_overhead; + const size_t adjust = adjust_request_size(size, ALIGN_SIZE); + + tlsf_assert(!block_is_free(block) && "block already marked as free"); + + /* + ** If the next block is used, or when combined with the current + ** block, does not offer enough space, we must reallocate and copy. + */ + if (adjust > cursize && (!block_is_free(next) || adjust > combined)) + { + p = tlsf_malloc(tlsf, size); + if (p) + { + const size_t minsize = tlsf_min(cursize, size); + memcpy(p, ptr, minsize); + tlsf_free(tlsf, ptr); + } + } + else + { + /* Do we need to expand to the next block? */ + if (adjust > cursize) + { + block_merge_next(control, block); + block_mark_as_used(block); + } + + /* Trim the resulting block and return the original pointer. */ + block_trim_used(control, block, adjust); + p = ptr; + } + } + + return p; +} diff --git a/sys/vm/vm_dynalloc.c b/sys/vm/vm_dynalloc.c new file mode 100644 index 0000000..0b8d668 --- /dev/null +++ b/sys/vm/vm_dynalloc.c @@ -0,0 +1,81 @@ +/* + * 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 + +/* + * Dynamically allocates memory + * + * @sz: The amount of bytes to allocate + */ +void * +dynalloc(size_t sz) +{ + struct vm_ctx *vm_ctx = vm_get_ctx(); + void *tmp; + + spinlock_acquire(&vm_ctx->dynalloc_lock); + tmp = tlsf_malloc(vm_ctx->tlsf_ctx, sz); + spinlock_release(&vm_ctx->dynalloc_lock); + return tmp; +} + +/* + * Reallocates memory pool created by `dynalloc()' + * + * @old_ptr: Pointer to old pool. + * @newsize: Size of new pool. + */ +void * +dynrealloc(void *old_ptr, size_t newsize) +{ + struct vm_ctx *vm_ctx = vm_get_ctx(); + void *tmp; + + spinlock_acquire(&vm_ctx->dynalloc_lock); + tmp = tlsf_realloc(vm_ctx->tlsf_ctx, old_ptr, newsize); + spinlock_release(&vm_ctx->dynalloc_lock); + return tmp; +} + +/* + * Free dynamically allocated memory + * + * @ptr: Pointer to base of memory. + */ +void +dynfree(void *ptr) +{ + struct vm_ctx *vm_ctx = vm_get_ctx(); + + spinlock_acquire(&vm_ctx->dynalloc_lock); + tlsf_free(vm_ctx->tlsf_ctx, ptr); + spinlock_release(&vm_ctx->dynalloc_lock); +} diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index 3e9718d..703942b 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -28,16 +28,40 @@ */ #include +#include #include #include +#include +#define DYNALLOC_POOL_SZ 0x400000 /* 4 MiB */ +#define DYNALLOC_POOL_PAGES (DYNALLOC_POOL_SZ / DEFAULT_PAGESIZE) + +static struct vm_ctx vm_ctx; volatile struct limine_hhdm_request g_hhdm_request = { .id = LIMINE_HHDM_REQUEST, .revision = 0 }; +struct vm_ctx * +vm_get_ctx(void) +{ + return &vm_ctx; +} + void vm_init(void) { + void *pool; + vm_physmem_init(); + + vm_ctx.dynalloc_pool_sz = DYNALLOC_POOL_SZ; + vm_ctx.dynalloc_pool_pa = vm_alloc_frame(DYNALLOC_POOL_PAGES); + if (vm_ctx.dynalloc_pool_pa == 0) { + panic("Failed to allocate dynamic pool\n"); + } + + pool = PHYS_TO_VIRT(vm_ctx.dynalloc_pool_pa); + vm_ctx.tlsf_ctx = tlsf_create_with_pool(pool, DYNALLOC_POOL_SZ); + __assert(vm_ctx.tlsf_ctx != 0); } -- cgit v1.2.3 From fbb0bcffc19e2b0ff26cfb6d85e0ee2719cc9c88 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 15:11:52 -0400 Subject: kernel: param: Add bit combining macros Signed-off-by: Ian Moffett --- sys/include/sys/param.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sys/include') diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h index d6c5a2b..a35a094 100644 --- a/sys/include/sys/param.h +++ b/sys/include/sys/param.h @@ -47,6 +47,11 @@ #define clrbit(a, b) ((a)[(b) >> 3] &= ~BIT(b % 8)) #define testbit(a, b) (ISSET((a)[(b) >> 3], BIT(b % 8))) +/* Combine bits */ +#define COMBINE8(h, l) ((uint16_t)((uint16_t)(h) << 8) | (l)) +#define COMBINE16(h, l) ((uint32_t)((uint32_t)(h) << 16) | (l)) +#define COMBINE32(h, l) ((uint64_t)((uint64_t)(h) << 32) | (l)) + #define NELEM(a) (sizeof(a) / sizeof(a[0])) #endif /* _SYS_PARAM_H_ */ -- 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') 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 57398708554c74a069c6a5d07c36e5576a6666fb Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 6 Jun 2024 15:33:38 -0400 Subject: kernel: cdefs: Add __likely() and __unlikely() Signed-off-by: Ian Moffett --- sys/include/sys/cdefs.h | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sys/include') diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h index 9c1a466..fc21750 100644 --- a/sys/include/sys/cdefs.h +++ b/sys/include/sys/cdefs.h @@ -33,5 +33,7 @@ #define __ASMV __asm__ __volatile__ #define __always_inline __attribute__((__always_inline__)) #define __packed __attribute__((__packed__)) +#define __likely(exp) __builtin_expect(((exp) != 0), 1) +#define __unlikely(exp) __builtin_expect(((exp) != 0), 0) #endif /* !_SYS_CDEFS_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') 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') 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') 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 f8ce8234aa7247c8f3a4317f5671b5fd40ffb8c8 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Fri, 7 Jun 2024 21:25:10 -0400 Subject: kernel: Add __cacheline_aligned macro This commit introduces a "__cacheline_aligned" macro which aligns data by the cache line size (COHERENCY_UNIT bytes). This is useful for heavily contended locks. Signed-off-by: Ian Moffett --- sys/arch/amd64/conf/link.ld | 8 +++++++- sys/include/sys/cdefs.h | 17 +++++++++++++++++ sys/include/sys/param.h | 5 +++++ 3 files changed, 29 insertions(+), 1 deletion(-) (limited to 'sys/include') diff --git a/sys/arch/amd64/conf/link.ld b/sys/arch/amd64/conf/link.ld index b073054..9c47a81 100644 --- a/sys/arch/amd64/conf/link.ld +++ b/sys/arch/amd64/conf/link.ld @@ -32,7 +32,7 @@ SECTIONS . += CONSTANT(MAXPAGESIZE); .data : { - *(.data .data.*) + *(.data) } :data .bss : { @@ -40,6 +40,12 @@ SECTIONS *(.bss .bss.*) } :data + /* -- Cache line alignment -- */ + . = ALIGN(64); + .data.cacheline_aligned : { + *(.data.cacheline_aligned) + } + /DISCARD/ : { *(.eh_frame) *(.note .note.*) diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h index fc21750..655a023 100644 --- a/sys/include/sys/cdefs.h +++ b/sys/include/sys/cdefs.h @@ -30,10 +30,27 @@ #ifndef _SYS_CDEFS_H_ #define _SYS_CDEFS_H_ +#include + #define __ASMV __asm__ __volatile__ #define __always_inline __attribute__((__always_inline__)) #define __packed __attribute__((__packed__)) #define __likely(exp) __builtin_expect(((exp) != 0), 1) #define __unlikely(exp) __builtin_expect(((exp) != 0), 0) +#if defined(_KERNEL) +/* + * Align data on a cache line boundary. This is + * mostly useful for certain locks to ensure they + * have their own cache line to reduce contention. + * + */ +#ifndef __cacheline_aligned +#define __cacheline_aligned \ + __attribute__((__aligned__(COHERENCY_UNIT), \ + __section__(".data.cacheline_aligned"))) + +#endif /* __cacheline_aligned */ +#endif /* _KERNEL */ + #endif /* !_SYS_CDEFS_H_ */ diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h index a35a094..483dc15 100644 --- a/sys/include/sys/param.h +++ b/sys/include/sys/param.h @@ -30,6 +30,11 @@ #ifndef _SYS_PARAM_H_ #define _SYS_PARAM_H_ +/* Assumed cache line size */ +#ifndef COHERENCY_UNIT +#define COHERENCY_UNIT 64 +#endif + /* Bit related macros */ #define ISSET(v, f) ((v) & (f)) #define BIT(n) (1 << (n)) -- 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') 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') 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 bb537181b48bba16aee0b601d579547d0a5c8122 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 8 Jun 2024 18:18:56 -0400 Subject: kernel: Add __static_assert macro Signed-off-by: Ian Moffett --- sys/include/sys/cdefs.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sys/include') diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h index 655a023..fa0c028 100644 --- a/sys/include/sys/cdefs.h +++ b/sys/include/sys/cdefs.h @@ -37,6 +37,7 @@ #define __packed __attribute__((__packed__)) #define __likely(exp) __builtin_expect(((exp) != 0), 1) #define __unlikely(exp) __builtin_expect(((exp) != 0), 0) +#define __static_assert _Static_assert #if defined(_KERNEL) /* -- cgit v1.2.3 From 71f56e9075d34fa560b23a448d58731c270aa050 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sat, 8 Jun 2024 18:19:14 -0400 Subject: kernel: types: Add pid_t Signed-off-by: Ian Moffett --- sys/include/sys/types.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sys/include') diff --git a/sys/include/sys/types.h b/sys/include/sys/types.h index fad34c7..c77663c 100644 --- a/sys/include/sys/types.h +++ b/sys/include/sys/types.h @@ -57,5 +57,6 @@ typedef int32_t ssize_t; /* Byte count or error */ typedef size_t uintptr_t; typedef _Bool bool; +typedef int pid_t; #endif /* _SYS_TYPES_H_ */ -- 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') 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 495d6670fff76a17f79bb96956bbb0589225cdae Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 9 Jun 2024 18:20:04 -0400 Subject: kernel: cdefs: Cleanup comment Signed-off-by: Ian Moffett --- sys/include/sys/cdefs.h | 1 - 1 file changed, 1 deletion(-) (limited to 'sys/include') diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h index fa0c028..8ccf5cc 100644 --- a/sys/include/sys/cdefs.h +++ b/sys/include/sys/cdefs.h @@ -44,7 +44,6 @@ * Align data on a cache line boundary. This is * mostly useful for certain locks to ensure they * have their own cache line to reduce contention. - * */ #ifndef __cacheline_aligned #define __cacheline_aligned \ -- cgit v1.2.3 From 8511af817034267ecdf6cba75351429ad884a4c5 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 9 Jun 2024 20:11:39 -0400 Subject: kernel: param: Expand supported bit width Signed-off-by: Ian Moffett --- sys/include/sys/param.h | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'sys/include') diff --git a/sys/include/sys/param.h b/sys/include/sys/param.h index 483dc15..612e282 100644 --- a/sys/include/sys/param.h +++ b/sys/include/sys/param.h @@ -37,7 +37,7 @@ /* Bit related macros */ #define ISSET(v, f) ((v) & (f)) -#define BIT(n) (1 << (n)) +#define BIT(n) (1ULL << (n)) /* Min/max macros */ #define MIN(a,b) (((a) < (b)) ? (a) : (b)) -- cgit v1.2.3 From 05011a452c0ba6a6b2ae2c815cadc2714e4ddb5c Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 9 Jun 2024 22:02:32 -0400 Subject: kernel: types: Add paddr_t and vaddr_t Signed-off-by: Ian Moffett --- sys/include/sys/types.h | 5 +++++ 1 file changed, 5 insertions(+) (limited to 'sys/include') diff --git a/sys/include/sys/types.h b/sys/include/sys/types.h index c77663c..2078e78 100644 --- a/sys/include/sys/types.h +++ b/sys/include/sys/types.h @@ -59,4 +59,9 @@ typedef size_t uintptr_t; typedef _Bool bool; typedef int pid_t; +#if defined(_KERNEL) +typedef uintptr_t paddr_t; +typedef uintptr_t vaddr_t; +#endif /* _KERNEL */ + #endif /* _SYS_TYPES_H_ */ -- 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') 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 19916128eeb882338f39c756945ad978eab13a49 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Mon, 10 Jun 2024 23:51:40 -0400 Subject: kernel: vm: Add initial code for MI layer Add initial code for the machine independent virtual memory layer Signed-off-by: Ian Moffett --- sys/include/vm/map.h | 40 ++++++++++++++++ sys/vm/vm_map.c | 132 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 172 insertions(+) create mode 100644 sys/include/vm/map.h create mode 100644 sys/vm/vm_map.c (limited to 'sys/include') diff --git a/sys/include/vm/map.h b/sys/include/vm/map.h new file mode 100644 index 0000000..936df5e --- /dev/null +++ b/sys/include/vm/map.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 _VM_MAP_H_ +#define _VM_MAP_H_ + +#include +#include +#include + +int vm_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, size_t count); +int vm_unmap(struct vas vas, vaddr_t va, size_t count); + +#endif /* !_VM_MAP_H_ */ diff --git a/sys/vm/vm_map.c b/sys/vm/vm_map.c new file mode 100644 index 0000000..d89cff5 --- /dev/null +++ b/sys/vm/vm_map.c @@ -0,0 +1,132 @@ +/* + * 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 + +/* + * Create/destroy virtual memory mappings in a specific + * address space. + * + * @vas: Address space. + * @va: Virtual address. + * @pa: Physical address (zero if `unmap` is true) + * @prot: Protection flags (zero if `unmap` is true) + * @unmap: True to unmap. + * @count: Count of bytes to be mapped which is aligned to the + * machine's page granularity. + * + * Returns 0 on success. On failure, this routine + * returns a less than zero value or greater than zero + * value that contains the offset into the memory where the + * mapping failed. + */ +static int +vm_map_modify(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, bool unmap, + size_t count) +{ + size_t misalign = va & (DEFAULT_PAGESIZE - 1); + int s; + + if (count == 0) { + return -EINVAL; + } + + /* Ensure we fully span pages */ + count = ALIGN_UP(count + misalign, DEFAULT_PAGESIZE); + va = ALIGN_DOWN(va, DEFAULT_PAGESIZE); + pa = ALIGN_DOWN(pa, DEFAULT_PAGESIZE); + + for (uintptr_t i = 0; i < count; i += DEFAULT_PAGESIZE) { + /* See if we should map or unmap the range */ + if (unmap) { + s = pmap_unmap(vas, va + i); + } else { + s = pmap_map(vas, va + i, pa + i, prot); + } + + if (s != 0) { + /* Something went wrong, return the offset */ + return i; + } + } + + return 0; +} + +/* + * Create a virtual memory mapping in a specific + * address space. + * + * @vas: Address space. + * @va: Virtual address. + * @pa: Physical address. + * @prot: Protection flags. + * @count: Count of bytes to be mapped (aligned to page granularity). + * + * Returns 0 on success, and a less than zero errno + * on failure. + */ +int +vm_map(struct vas vas, vaddr_t va, paddr_t pa, vm_prot_t prot, size_t count) +{ + int retval; + + va = ALIGN_UP(va, DEFAULT_PAGESIZE); + retval = vm_map_modify(vas, va, pa, prot, false, count); + + /* Return on success */ + if (retval == 0) + return 0; + + /* Failure, clean up */ + for (int i = 0; i < retval; i += DEFAULT_PAGESIZE) { + pmap_unmap(vas, va + i); + } + + return -1; +} + +/* + * Unmap a virtual memory mapping in a specific + * address space. + * + * @vas: Address space. + * @va: Virtual address to start unmapping at. + * @count: Bytes to unmap (aligned to page granularity) + */ +int +vm_unmap(struct vas vas, vaddr_t va, size_t count) +{ + return vm_map_modify(vas, va, 0, 0, true, count); +} -- cgit v1.2.3 From 2549674ff1f949928818129fa7572e2e31bbc0d8 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 11 Jun 2024 20:11:30 -0400 Subject: kernel: types: Add off_t Signed-off-by: Ian Moffett --- sys/include/sys/types.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sys/include') diff --git a/sys/include/sys/types.h b/sys/include/sys/types.h index 2078e78..943b54c 100644 --- a/sys/include/sys/types.h +++ b/sys/include/sys/types.h @@ -56,6 +56,7 @@ typedef int32_t ssize_t; /* Byte count or error */ #endif typedef size_t uintptr_t; +typedef size_t off_t; typedef _Bool bool; typedef int pid_t; -- cgit v1.2.3 From 2b5b3c8ca233d13fd4757e6e88ac60cfd00653ac Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Tue, 11 Jun 2024 20:14:18 -0400 Subject: kernel: Add sys/atomic.h Signed-off-by: Ian Moffett --- sys/include/sys/atomic.h | 65 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 65 insertions(+) create mode 100644 sys/include/sys/atomic.h (limited to 'sys/include') diff --git a/sys/include/sys/atomic.h b/sys/include/sys/atomic.h new file mode 100644 index 0000000..1e60ac7 --- /dev/null +++ b/sys/include/sys/atomic.h @@ -0,0 +1,65 @@ +/* + * 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_ATOMIC_H_ +#define _SYS_ATOMIC_H_ + +static inline unsigned long +atomic_add_long_nv(volatile unsigned long *p, unsigned long v) +{ + return __sync_add_and_fetch(p, v); +} + +static inline unsigned int +atomic_add_int_nv(volatile unsigned int *p, unsigned int v) +{ + return __sync_add_and_fetch(p, v); +} + +static inline unsigned long +atomic_sub_long_nv(volatile unsigned long *p, unsigned long v) +{ + return __sync_sub_and_fetch(p, v); +} + +static inline unsigned int +atomic_sub_int_nv(volatile unsigned int *p, unsigned int v) +{ + return __sync_sub_and_fetch(p, v); +} + +/* Atomic increment (and fetch) operations */ +#define atoimc_inc_long(P) atomic_add_long_nv((P), 1) +#define atomic_inc_int(P) atomic_add_int_nv((P), 1) + +/* Atomic decrement (and fetch) operations */ +#define atomic_dec_long(P) atomic_sub_long_nv((P), 1) +#define atomic_dec_int(P) atomic_sub_int_nv((P), 1) + +#endif /* !_SYS_ATOMIC_H_ */ -- cgit v1.2.3 From 7221137c81b87a25c800b0aa186f0c2a566355d0 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 13 Jun 2024 18:30:55 -0400 Subject: kernel: string: Add strcmp() Signed-off-by: Ian Moffett --- sys/include/lib/string.h | 2 ++ sys/lib/string/strcmp.c | 42 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 44 insertions(+) create mode 100644 sys/lib/string/strcmp.c (limited to 'sys/include') diff --git a/sys/include/lib/string.h b/sys/include/lib/string.h index 89c728f..3ae33ea 100644 --- a/sys/include/lib/string.h +++ b/sys/include/lib/string.h @@ -41,6 +41,8 @@ int snprintf(char *s, size_t size, const char *fmt, ...); void *memcpy(void *dest, const void *src, size_t n); int memcmp(const void *s1, const void *s2, size_t n); + void *memset(void *s, int c, size_t n); +int strcmp(const char *s1, const char *s2); #endif /* !_LIB_STRING_H_ */ diff --git a/sys/lib/string/strcmp.c b/sys/lib/string/strcmp.c new file mode 100644 index 0000000..f0a3569 --- /dev/null +++ b/sys/lib/string/strcmp.c @@ -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. + */ + +#include + +int +strcmp(const char *s1, const char *s2) +{ + while (*s1 == *s2++) { + if (*s1++ == 0) { + return (0); + } + } + + return (*(unsigned char *)s1 - *(unsigned char *)--s2); +} -- cgit v1.2.3 From ef12b6d88bf847e17d7412e36e312517cb0ed170 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 19 Jun 2024 22:16:01 -0400 Subject: kernel: types: Add mode_t Signed-off-by: Ian Moffett --- sys/include/sys/types.h | 1 + 1 file changed, 1 insertion(+) (limited to 'sys/include') diff --git a/sys/include/sys/types.h b/sys/include/sys/types.h index 943b54c..3d565e5 100644 --- a/sys/include/sys/types.h +++ b/sys/include/sys/types.h @@ -59,6 +59,7 @@ typedef size_t uintptr_t; typedef size_t off_t; typedef _Bool bool; typedef int pid_t; +typedef uint32_t mode_t; #if defined(_KERNEL) typedef uintptr_t paddr_t; -- cgit v1.2.3 From 8c5afdb1601a1864e9fd0416b9d2f42d0bdf489a Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 19 Jun 2024 22:16:26 -0400 Subject: kernel: lib: Add strncmp() Signed-off-by: Ian Moffett --- sys/include/lib/string.h | 1 + sys/lib/string/strncmp.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 51 insertions(+) create mode 100644 sys/lib/string/strncmp.c (limited to 'sys/include') diff --git a/sys/include/lib/string.h b/sys/include/lib/string.h index 3ae33ea..8500af2 100644 --- a/sys/include/lib/string.h +++ b/sys/include/lib/string.h @@ -44,5 +44,6 @@ int memcmp(const void *s1, const void *s2, size_t n); void *memset(void *s, int c, size_t n); int strcmp(const char *s1, const char *s2); +int strncmp(const char *s1, const char *s2, size_t n); #endif /* !_LIB_STRING_H_ */ diff --git a/sys/lib/string/strncmp.c b/sys/lib/string/strncmp.c new file mode 100644 index 0000000..b68fa58 --- /dev/null +++ b/sys/lib/string/strncmp.c @@ -0,0 +1,50 @@ +/* + * 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 + +int +strncmp(const char *s1, const char *s2, size_t n) +{ + if (n == 0) { + return 0; + } + + do { + if (*s1 != *s2++) { + return (*(unsigned char *)s1 - *(unsigned char *)--s2); + } + + if (*s1++ == 0) { + break; + } + } while (--n != 0); + + return 0; +} -- cgit v1.2.3 From c2056f5a365c85780dd2d2835547723f6f60c192 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Wed, 19 Jun 2024 22:18:16 -0400 Subject: kernel: Add initramfs and initial VFS code Signed-off-by: Ian Moffett --- Makefile.in | 9 +- builddeps/limine.cfg | 2 +- sys/fs/initramfs.c | 263 +++++++++++++++++++++++++++++++++++++++++++++ sys/include/fs/initramfs.h | 37 +++++++ sys/include/sys/mount.h | 84 +++++++++++++++ sys/include/sys/namei.h | 44 ++++++++ sys/include/sys/vnode.h | 74 +++++++++++++ sys/kern/init_main.c | 4 + sys/kern/vfs_init.c | 70 ++++++++++++ sys/kern/vfs_lookup.c | 83 ++++++++++++++ sys/kern/vfs_subr.c | 122 +++++++++++++++++++++ 11 files changed, 790 insertions(+), 2 deletions(-) create mode 100644 sys/fs/initramfs.c create mode 100644 sys/include/fs/initramfs.h create mode 100644 sys/include/sys/mount.h create mode 100644 sys/include/sys/namei.h create mode 100644 sys/include/sys/vnode.h create mode 100644 sys/kern/vfs_init.c create mode 100644 sys/kern/vfs_lookup.c create mode 100644 sys/kern/vfs_subr.c (limited to 'sys/include') diff --git a/Makefile.in b/Makefile.in index 0142b13..b6af9d9 100644 --- a/Makefile.in +++ b/Makefile.in @@ -46,7 +46,7 @@ override KERNEL_ASMOBJECTS = $(KERNEL_ASMFILES:.S=.S.o) override KERNEL_HEADER_DEPS = $(KERNEL_CFILES:.c=.d) .PHONY: all -all: base base/boot/hyra-kernel iso +all: base base/boot/hyra-kernel ramfs iso rm -f sys/include/machine rm -rf iso_root @@ -60,6 +60,12 @@ base: run: $(QEMU) $(QEMU_FLAGS) +.PHONY: ramfs +ramfs: + cd base/; find . -name "*" | cpio --create --format=odc \ + --no-absolute-filenames > ../ramfs.cpio + $(PROMPT) " RAMFS " $(shell pwd)/ramfs.cpio + .PHONY: clean clean: rm -f $(KERNEL_ASMOBJECTS) $(KERNEL_OBJECTS) $(KERNEL_HEADER_DEPS) @@ -70,6 +76,7 @@ iso: mkdir -p iso_root/boot/ mkdir -p iso_root/EFI/BOOT/ cp stand/limine/BOOTX64.EFI iso_root/EFI/BOOT/ + mv ramfs.cpio iso_root/boot/ cp builddeps/limine.cfg stand/limine/limine-bios.sys \ stand/limine/limine-bios-cd.bin stand/limine/limine-uefi-cd.bin iso_root/ cp base/boot/* iso_root/boot/ diff --git a/builddeps/limine.cfg b/builddeps/limine.cfg index ec496b7..87b39de 100644 --- a/builddeps/limine.cfg +++ b/builddeps/limine.cfg @@ -4,5 +4,5 @@ TIMEOUT=0 PROTOCOL=limine KERNEL_PATH=boot:///boot/hyra-kernel -MODULE_PATH=boot:///boot/initramfs.tar +MODULE_PATH=boot:///boot/ramfs.cpio EDITOR_ENABLED=no diff --git a/sys/fs/initramfs.c b/sys/fs/initramfs.c new file mode 100644 index 0000000..4c47da8 --- /dev/null +++ b/sys/fs/initramfs.c @@ -0,0 +1,263 @@ +/* + * 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 CPIO_TRAILER "TRAILER!!!" + +/* + * File or directory. + */ +struct initramfs_node { + const char *path; /* Path */ + void *data; /* File data */ + size_t size; /* File size */ + mode_t mode; /* Perms and type */ +}; + +/* + * ODC CPIO header + */ +struct cpio_hdr { + char c_magic[6]; + char c_dev[6]; + char c_ino[6]; + char c_mode[6]; + char c_uid[6]; + char c_gid[6]; + char c_nlink[6]; + char c_rdev[6]; + char c_mtime[11]; + char c_namesize[6]; + char c_filesize[11]; +}; + +static volatile struct limine_module_request mod_req = { + .id = LIMINE_MODULE_REQUEST, + .revision = 0 +}; + +static const char *initramfs = NULL; +static uint64_t initramfs_size; + +/* + * Fetch a module from the bootloader. + * This is used to fetch the ramfs image. + */ +static char * +get_module(const char *path, uint64_t *size) { + for (uint64_t i = 0; i < mod_req.response->module_count; ++i) { + if (strcmp(mod_req.response->modules[i]->path, path) == 0) { + *size = mod_req.response->modules[i]->size; + return mod_req.response->modules[i]->address; + } + } + + return NULL; +} + +/* + * Convert octal to base 10 + */ +static uint32_t +oct2dec(const char *in, size_t sz) +{ + size_t val = 0; + + for (size_t i = 0; i < sz; ++i) { + val = val * 8 + (in[i] - '0'); + } + + return val; +} + +/* + * Get a file from initramfs + * + * @path: Path of file to get. + * @res: Pointer to new resulting node. + */ +static int +initramfs_get_file(const char *path, struct initramfs_node *res) +{ + const struct cpio_hdr *hdr; + struct initramfs_node node; + uintptr_t addr; + size_t namesize, filesize; + mode_t mode; + + addr = (uintptr_t)initramfs; + for (;;) { + hdr = (void *)addr; + namesize = oct2dec(hdr->c_namesize, sizeof(hdr->c_namesize)); + filesize = oct2dec(hdr->c_filesize, sizeof(hdr->c_filesize)); + mode = oct2dec(hdr->c_mode, sizeof(hdr->c_mode)); + + /* Make sure the magic is correct */ + if (strncmp(hdr->c_magic, "070707", 6) != 0) { + return -EINVAL; + } + + addr += sizeof(struct cpio_hdr); + node.path = (const char *)addr; + + /* Is this the requested file? */ + if (strcmp(node.path, path) == 0) { + node.data = (void *)(addr + namesize); + node.size = filesize; + node.mode = mode; + *res = node; + return 0; + } + + /* Get next header and see if we are at the end */ + addr += (namesize + filesize); + if (strcmp(node.path, CPIO_TRAILER) == 0) { + break; + } + } + + return -ENOENT; +} + +static int +initramfs_lookup(struct vop_lookup_args *args) +{ + int status, vtype; + struct initramfs_node *n; + struct vnode *vp; + const char *path = args->name; + + if (*path == '/') { + ++path; + } + + n = dynalloc(sizeof(*n)); + if (n == NULL) { + return -ENOMEM; + } + + /* Now does this file exist? */ + if ((status = initramfs_get_file(path, n)) != 0) { + dynfree(n); + return status; + } + + vtype = ISSET(n->mode, 0040000) ? VDIR : VREG; + + /* Try to create a new vnode */ + if ((status = vfs_alloc_vnode(&vp, vtype)) != 0) { + dynfree(n); + return status; + } + + vp->data = n; + vp->vops = &g_initramfs_vops; + *args->vpp = vp; + return 0; +} + +static int +initramfs_read(struct vnode *vp, struct sio_txn *sio) +{ + struct initramfs_node *n = vp->data; + uint8_t *src, *dest; + uint32_t count = 0; + + /* Ensure pointers are valid */ + if (n == NULL) + return -EIO; + if (sio->buf == NULL) + return -EIO; + + src = n->data; + dest = sio->buf; + + /* Copy the file data */ + for (size_t i = 0; i < sio->len; ++i) { + if ((sio->offset + i) >= n->size) { + break; + } + dest[i] = src[sio->offset + i]; + ++count; + } + + return count; +} + +static int +initramfs_reclaim(struct vnode *vp) +{ + if (vp->data != NULL) { + dynfree(vp->data); + } + + return 0; +} + +static int +initramfs_init(struct fs_info *fip) +{ + struct mount *mp; + int status; + + initramfs = get_module("/boot/ramfs.cpio", &initramfs_size); + if (initramfs == NULL) { + panic("Failed to open initramfs cpio image\n"); + } + + status = vfs_alloc_vnode(&g_root_vnode, VDIR); + if (__unlikely(status != 0)) { + panic("Failed to create root vnode for ramfs\n"); + } + + g_root_vnode->vops = &g_initramfs_vops; + mp = vfs_alloc_mount(g_root_vnode, fip); + TAILQ_INSERT_TAIL(&g_mountlist, mp, mnt_list); + return 0; +} + +const struct vops g_initramfs_vops = { + .lookup = initramfs_lookup, + .read = initramfs_read, + .reclaim = initramfs_reclaim +}; + +const struct vfsops g_initramfs_vfsops = { + .init = initramfs_init +}; diff --git a/sys/include/fs/initramfs.h b/sys/include/fs/initramfs.h new file mode 100644 index 0000000..897079c --- /dev/null +++ b/sys/include/fs/initramfs.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 _INITRAMFS_H_ +#define _INITRAMFS_H_ + +#include + +extern const struct vops g_initramfs_vops; + +#endif /* _INITRAMFS_H_ */ diff --git a/sys/include/sys/mount.h b/sys/include/sys/mount.h new file mode 100644 index 0000000..e46cda9 --- /dev/null +++ b/sys/include/sys/mount.h @@ -0,0 +1,84 @@ +/* + * 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_MOUNT_H_ +#define _SYS_MOUNT_H_ + +#include +#include +#include +#include +#include + +#if defined(_KERNEL) + +#define FS_NAME_MAX 16 /* Length of fs name including nul */ + +/* + * Filesystem types. + */ +#define MOUNT_RAMFS "initramfs" + +struct vfsops; +struct mount; + +/* Mount list */ +typedef TAILQ_HEAD(, mount) mountlist_t; +extern mountlist_t g_mountlist; + +/* Filesystem operations */ +extern const struct vfsops g_initramfs_vfsops; + +struct mount { + struct spinlock lock; + struct vnode *vp; + const struct vfsops *mnt_ops; + void *data; + TAILQ_ENTRY(mount) mnt_list; +}; + +struct fs_info { + char name[FS_NAME_MAX]; /* FS Type name */ + const struct vfsops *vfsops; /* Operations vector */ + int flags; /* Flags for this filesystem */ + int refcount; /* Mount count of this type */ +}; + +struct vfsops { + int(*init)(struct fs_info *fip); + int(*mount)(struct mount *mp, const char *path, void *data, + struct nameidata *ndp); +}; + +void vfs_init(void); +struct mount *vfs_alloc_mount(struct vnode *vp, struct fs_info *fip); +struct fs_info *vfs_byname(const char *name); + +#endif /* _KERNEL */ +#endif /* _SYS_MOUNT_H_ */ diff --git a/sys/include/sys/namei.h b/sys/include/sys/namei.h new file mode 100644 index 0000000..bd3c0db --- /dev/null +++ b/sys/include/sys/namei.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 _SYS_NAMEI_H_ +#define _SYS_NAMEI_H_ + +#include +#include + +struct nameidata { + const char *path; /* Pathname */ + uint32_t flags; + struct vnode *vp; /* Vnode result */ +}; + +int namei(struct nameidata *ndp); + +#endif /* !_SYS_NAMEI_H_ */ diff --git a/sys/include/sys/vnode.h b/sys/include/sys/vnode.h new file mode 100644 index 0000000..1caf2cb --- /dev/null +++ b/sys/include/sys/vnode.h @@ -0,0 +1,74 @@ +/* + * 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_VNODE_H_ +#define _SYS_VNODE_H_ + +#include + +#if defined(_KERNEL) + +struct vops; + +struct vnode { + int type; + int flags; + void *data; + const struct vops *vops; +}; + +/* Vnode type flags */ +#define VNON 0x00 /* Uninitialized */ +#define VREG 0x01 /* Regular file */ +#define VDIR 0x02 /* Directory */ +#define VCHR 0x03 /* Character device */ +#define VBLK 0x04 /* Block device */ + +struct vop_lookup_args { + const char *name; /* Current path component */ + struct vnode *dirvp; /* Directory vnode */ + struct vnode **vpp; /* Result vnode */ +}; + +struct vops { + int(*lookup)(struct vop_lookup_args *args); + int(*read)(struct vnode *vp, struct sio_txn *sio); + int(*reclaim)(struct vnode *vp); +}; + +extern struct vnode *g_root_vnode; + +int vfs_alloc_vnode(struct vnode **res, int type); +int vfs_release_vnode(struct vnode *vp); + +int vfs_vop_lookup(struct vnode *vp, struct vop_lookup_args *args); +int vfs_vop_read(struct vnode *vp, struct sio_txn *sio); + +#endif /* _KERNEL */ +#endif /* !_SYS_VNODE_H_ */ diff --git a/sys/kern/init_main.c b/sys/kern/init_main.c index 6018dfe..09b8d2d 100644 --- a/sys/kern/init_main.c +++ b/sys/kern/init_main.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -52,6 +53,9 @@ main(void) /* Startup the BSP */ cpu_startup(&g_bsp_ci); + /* Init the virtual file system */ + vfs_init(); + /* Start scheduler and bootstrap APs */ sched_init(); mp_bootstrap_aps(&g_bsp_ci); diff --git a/sys/kern/vfs_init.c b/sys/kern/vfs_init.c new file mode 100644 index 0000000..aafbc00 --- /dev/null +++ b/sys/kern/vfs_init.c @@ -0,0 +1,70 @@ +/* + * 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 + +struct vnode *g_root_vnode = NULL; +static struct fs_info fs_list[] = { + {MOUNT_RAMFS, &g_initramfs_vfsops, 0, 0}, +}; + +void +vfs_init(void) +{ + struct fs_info *fs; + const struct vfsops *vfsops; + + TAILQ_INIT(&g_mountlist); + + for (size_t i= 0; i < NELEM(fs_list); ++i) { + fs = &fs_list[i]; + vfsops = fs->vfsops; + + /* Try to initialize the filesystem */ + if (vfsops->init != NULL) { + vfsops->init(fs); + } + } +} + +struct fs_info * +vfs_byname(const char *name) +{ + for (int i = 0; i < NELEM(fs_list); ++i) { + if (strcmp(fs_list[i].name, name) == 0) { + return &fs_list[i]; + } + } + + return NULL; +} diff --git a/sys/kern/vfs_lookup.c b/sys/kern/vfs_lookup.c new file mode 100644 index 0000000..83924c6 --- /dev/null +++ b/sys/kern/vfs_lookup.c @@ -0,0 +1,83 @@ +/* + * 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 + +/* + * Convert a path to a vnode. + * + * @ndp: Nameidata containing the path and resulting + * vnode. + * + * TODO: Add support for lookups with individual + * path components + */ +int +namei(struct nameidata *ndp) +{ + struct vnode *vp; + struct vop_lookup_args lookup_args; + const char *path = ndp->path; + int status; + + if (path == NULL) { + return -EINVAL; + } + + /* Path must start with "/" */ + if (*path != '/') { + return -EINVAL; + } + + /* Just return the root vnode if we can */ + if (strcmp(path, "/") == 0) { + ndp->vp = g_root_vnode; + return 0; + } + + /* + * Some filesystems (like initramfs) may only understand + * full paths, so try passing it through. + */ + lookup_args.name = path; + lookup_args.dirvp = g_root_vnode; + lookup_args.vpp = &vp; + status = vfs_vop_lookup(lookup_args.dirvp, &lookup_args); + + if (status != 0) { + return status; + } + + ndp->vp = vp; + return 0; +} diff --git a/sys/kern/vfs_subr.c b/sys/kern/vfs_subr.c new file mode 100644 index 0000000..04d64e3 --- /dev/null +++ b/sys/kern/vfs_subr.c @@ -0,0 +1,122 @@ +/* + * 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 + +mountlist_t g_mountlist; + +int +vfs_alloc_vnode(struct vnode **res, int type) +{ + struct vnode *vp = dynalloc(sizeof(struct vnode)); + + if (vp == NULL) { + return -ENOMEM; + } + + memset(vp, 0, sizeof(*vp)); + vp->type = type; + *res = vp; + return 0; +} + +/* + * Allocate a mount structure. + * + * @vp: Vnode this mount structure covers. + * @fip: File system information. + */ +struct mount * +vfs_alloc_mount(struct vnode *vp, struct fs_info *fip) +{ + struct mount *mp; + + mp = dynalloc(sizeof(*mp)); + + if (mp == NULL) { + return NULL; + } + + memset(mp, 0, sizeof(*mp)); + mp->vp = vp; + mp->mnt_ops = fip->vfsops; + return mp; +} + +/* + * Release a vnode and its resources from + * memory. + */ +int +vfs_release_vnode(struct vnode *vp) +{ + const struct vops *vops = vp->vops; + int status = 0; + + if (vp == NULL) { + return -EINVAL; + } + + if (vops->reclaim != NULL) { + status = vops->reclaim(vp); + } + + dynfree(vp); + return status; +} + +int +vfs_vop_lookup(struct vnode *vp, struct vop_lookup_args *args) +{ + const struct vops *vops = vp->vops; + + if (vops == NULL) + return -EIO; + if (vops->lookup == NULL) + return -EIO; + + return vops->lookup(args); +} + +int +vfs_vop_read(struct vnode *vp, struct sio_txn *sio) +{ + const struct vops *vops = vp->vops; + + if (vops == NULL) + return -EIO; + if (vops->read == NULL) + return -EIO; + + return vops->read(vp, sio); +} -- cgit v1.2.3 From d8ba24147205e083a00ee76933cf047a8f8f5727 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Thu, 20 Jun 2024 15:28:10 -0400 Subject: kernel: queue: Add sys/queue.h Signed-off-by: Ian Moffett --- sys/include/sys/queue.h | 294 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 294 insertions(+) create mode 100644 sys/include/sys/queue.h (limited to 'sys/include') diff --git a/sys/include/sys/queue.h b/sys/include/sys/queue.h new file mode 100644 index 0000000..818df84 --- /dev/null +++ b/sys/include/sys/queue.h @@ -0,0 +1,294 @@ +/* + * 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 + +#ifndef _QUEUE_H_ +#define _QUEUE_H_ + +#define _Q_INVALIDATE(a) + +/* + * Tail queue definitions. + */ +#define TAILQ_HEAD(name, type) \ +struct name { \ + struct type *tqh_first; /* first element */ \ + struct type **tqh_last; /* addr of last next element */ \ + size_t nelem; /* Number of elements */ \ +} + +#define TAILQ_HEAD_INITIALIZER(head) \ + { NULL, &(head).tqh_first } + +#define TAILQ_ENTRY(type) \ +struct { \ + struct type *tqe_next; /* next element */ \ + struct type **tqe_prev; /* address of previous next element */ \ +} + +/* + * Tail queue access methods. + */ +#define TAILQ_NELEM(head) ((head)->nelem) +#define TAILQ_FIRST(head) ((head)->tqh_first) +#define TAILQ_END(head) NULL +#define TAILQ_NEXT(elm, field) ((elm)->field.tqe_next) +#define TAILQ_LAST(head, headname) \ + (*(((struct headname *)((head)->tqh_last))->tqh_last)) +/* XXX */ +#define TAILQ_PREV(elm, headname, field) \ + (*(((struct headname *)((elm)->field.tqe_prev))->tqh_last)) +#define TAILQ_EMPTY(head) \ + (TAILQ_FIRST(head) == TAILQ_END(head)) + +#define TAILQ_FOREACH(var, head, field) \ + for((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_NEXT(var, field)) + +#define TAILQ_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = TAILQ_FIRST(head); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_NEXT(var, field), 1); \ + (var) = (tvar)) + + +#define TAILQ_FOREACH_REVERSE(var, head, headname, field) \ + for((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head); \ + (var) = TAILQ_PREV(var, headname, field)) + +#define TAILQ_FOREACH_REVERSE_SAFE(var, head, headname, field, tvar) \ + for ((var) = TAILQ_LAST(head, headname); \ + (var) != TAILQ_END(head) && \ + ((tvar) = TAILQ_PREV(var, headname, field), 1); \ + (var) = (tvar)) + +/* + * Tail queue functions. + */ +#define TAILQ_INIT(head) do { \ + (head)->tqh_first = NULL; \ + (head)->tqh_last = &(head)->tqh_first; \ + (head)->nelem = 0; \ +} while (0) + +#define TAILQ_INSERT_HEAD(head, elm, field) do { \ + if (((elm)->field.tqe_next = (head)->tqh_first) != NULL) \ + (head)->tqh_first->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (head)->tqh_first = (elm); \ + (elm)->field.tqe_prev = &(head)->tqh_first; \ + ++(head)->nelem; \ +} while (0) + +#define TAILQ_INSERT_TAIL(head, elm, field) do { \ + (elm)->field.tqe_next = NULL; \ + (elm)->field.tqe_prev = (head)->tqh_last; \ + *(head)->tqh_last = (elm); \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + ++(head)->nelem; \ +} while (0) + +#define TAILQ_INSERT_AFTER(head, listelm, elm, field) do { \ + if (((elm)->field.tqe_next = (listelm)->field.tqe_next) != NULL)\ + (elm)->field.tqe_next->field.tqe_prev = \ + &(elm)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm)->field.tqe_next; \ + (listelm)->field.tqe_next = (elm); \ + (elm)->field.tqe_prev = &(listelm)->field.tqe_next; \ + ++(head)->nelem; \ +} while (0) + +#define TAILQ_INSERT_BEFORE(listelm, elm, field) do { \ + (elm)->field.tqe_prev = (listelm)->field.tqe_prev; \ + (elm)->field.tqe_next = (listelm); \ + *(listelm)->field.tqe_prev = (elm); \ + (listelm)->field.tqe_prev = &(elm)->field.tqe_next; \ + ++(head)->nelem; \ +} while (0) + +#define TAILQ_REMOVE(head, elm, field) do { \ + if (((elm)->field.tqe_next) != NULL) \ + (elm)->field.tqe_next->field.tqe_prev = \ + (elm)->field.tqe_prev; \ + else \ + (head)->tqh_last = (elm)->field.tqe_prev; \ + *(elm)->field.tqe_prev = (elm)->field.tqe_next; \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ + --(head)->nelem; \ +} while (0) + +#define TAILQ_REPLACE(head, elm, elm2, field) do { \ + if (((elm2)->field.tqe_next = (elm)->field.tqe_next) != NULL) \ + (elm2)->field.tqe_next->field.tqe_prev = \ + &(elm2)->field.tqe_next; \ + else \ + (head)->tqh_last = &(elm2)->field.tqe_next; \ + (elm2)->field.tqe_prev = (elm)->field.tqe_prev; \ + *(elm2)->field.tqe_prev = (elm2); \ + _Q_INVALIDATE((elm)->field.tqe_prev); \ + _Q_INVALIDATE((elm)->field.tqe_next); \ +} while (0) + +#define TAILQ_CONCAT(head1, head2, field) do { \ + if (!TAILQ_EMPTY(head2)) { \ + *(head1)->tqh_last = (head2)->tqh_first; \ + (head2)->tqh_first->field.tqe_prev = (head1)->tqh_last; \ + (head1)->tqh_last = (head2)->tqh_last; \ + TAILQ_INIT((head2)); \ + } \ +} while (0) + +/* + * List definitions. + */ +#define LIST_HEAD(name, type) \ +struct name { \ + struct type *lh_first; /* first element */ \ +} + +#define LIST_HEAD_INITIALIZER(head) \ + { NULL } + +#define LIST_ENTRY(type) \ +struct { \ + struct type *le_next; /* next element */ \ + struct type **le_prev; /* address of previous next element */ \ +} + +/* + * List access methods. + */ +#define LIST_FIRST(head) ((head)->lh_first) +#define LIST_END(head) NULL +#define LIST_EMPTY(head) ((head)->lh_first == LIST_END(head)) +#define LIST_NEXT(elm, field) ((elm)->field.le_next) + +#define LIST_FOREACH(var, head, field) \ + for ((var) = ((head)->lh_first); \ + (var) != LIST_END(head); \ + (var) = ((var)->field.le_next)) + +#define LIST_FOREACH_SAFE(var, head, field, tvar) \ + for ((var) = LIST_FIRST((head)); \ + (var) != LIST_END(head) && \ + ((tvar) = LIST_NEXT((var), field), 1); \ + (var) = (tvar)) + +#define LIST_MOVE(head1, head2, field) do { \ + LIST_INIT((head2)); \ + if (!LIST_EMPTY((head1))) { \ + (head2)->lh_first = (head1)->lh_first; \ + (head2)->lh_first->field.le_prev = &(head2)->lh_first; \ + LIST_INIT((head1)); \ + } \ +} while (0) + +/* + * List functions. + */ +#if defined(QUEUEDEBUG) +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) \ + if ((head)->lh_first && \ + (head)->lh_first->field.le_prev != &(head)->lh_first) \ + QUEUEDEBUG_ABORT("LIST_INSERT_HEAD %p %s:%d", (head), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_OP(elm, field) \ + if ((elm)->field.le_next && \ + (elm)->field.le_next->field.le_prev != \ + &(elm)->field.le_next) \ + QUEUEDEBUG_ABORT("LIST_* forw %p %s:%d", (elm), \ + __FILE__, __LINE__); \ + if (*(elm)->field.le_prev != (elm)) \ + QUEUEDEBUG_ABORT("LIST_* back %p %s:%d", (elm), \ + __FILE__, __LINE__); +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) \ + (elm)->field.le_next = (void *)1L; \ + (elm)->field.le_prev = (void *)1L; +#else +#define QUEUEDEBUG_LIST_INSERT_HEAD(head, elm, field) +#define QUEUEDEBUG_LIST_OP(elm, field) +#define QUEUEDEBUG_LIST_POSTREMOVE(elm, field) +#endif + +#define LIST_INIT(head) do { \ + (head)->lh_first = LIST_END(head); \ +} while (0) + +#define LIST_INSERT_AFTER(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + if (((elm)->field.le_next = (listelm)->field.le_next) != \ + LIST_END(head)) \ + (listelm)->field.le_next->field.le_prev = \ + &(elm)->field.le_next; \ + (listelm)->field.le_next = (elm); \ + (elm)->field.le_prev = &(listelm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_BEFORE(listelm, elm, field) do { \ + QUEUEDEBUG_LIST_OP((listelm), field) \ + (elm)->field.le_prev = (listelm)->field.le_prev; \ + (elm)->field.le_next = (listelm); \ + *(listelm)->field.le_prev = (elm); \ + (listelm)->field.le_prev = &(elm)->field.le_next; \ +} while (0) + +#define LIST_INSERT_HEAD(head, elm, field) do { \ + QUEUEDEBUG_LIST_INSERT_HEAD((head), (elm), field) \ + if (((elm)->field.le_next = (head)->lh_first) != LIST_END(head))\ + (head)->lh_first->field.le_prev = &(elm)->field.le_next;\ + (head)->lh_first = (elm); \ + (elm)->field.le_prev = &(head)->lh_first; \ +} while (0) + +#define LIST_REMOVE(elm, field) do { \ + QUEUEDEBUG_LIST_OP((elm), field) \ + if ((elm)->field.le_next != NULL) \ + (elm)->field.le_next->field.le_prev = \ + (elm)->field.le_prev; \ + *(elm)->field.le_prev = (elm)->field.le_next; \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (0) + +#define LIST_REPLACE(elm, elm2, field) do { \ + if (((elm2)->field.le_next = (elm)->field.le_next) != NULL) \ + (elm2)->field.le_next->field.le_prev = \ + &(elm2)->field.le_next; \ + (elm2)->field.le_prev = (elm)->field.le_prev; \ + *(elm2)->field.le_prev = (elm2); \ + QUEUEDEBUG_LIST_POSTREMOVE((elm), field) \ +} while (0) + +#endif /* _QUEUE_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') 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 c43e62b89d8bcb5ccd4f3265375e09a22dab3831 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Fri, 21 Jun 2024 22:03:41 -0400 Subject: kernel: cdefs: Fixup comment Signed-off-by: Ian Moffett --- sys/include/sys/cdefs.h | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) (limited to 'sys/include') diff --git a/sys/include/sys/cdefs.h b/sys/include/sys/cdefs.h index 8ccf5cc..bec6271 100644 --- a/sys/include/sys/cdefs.h +++ b/sys/include/sys/cdefs.h @@ -43,7 +43,8 @@ /* * Align data on a cache line boundary. This is * mostly useful for certain locks to ensure they - * have their own cache line to reduce contention. + * have their own cache line to reduce cache line + * bouncing. */ #ifndef __cacheline_aligned #define __cacheline_aligned \ -- cgit v1.2.3 From 2e2dc610d2abd6c12cf6dcda290b23fb77ecd704 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 19:00:54 -0400 Subject: kernel: vm: Add g_kvas for kernel VAS Signed-off-by: Ian Moffett --- sys/include/vm/vm.h | 3 +++ sys/vm/vm_init.c | 3 +++ 2 files changed, 6 insertions(+) (limited to 'sys/include') diff --git a/sys/include/vm/vm.h b/sys/include/vm/vm.h index bf49e67..9c63901 100644 --- a/sys/include/vm/vm.h +++ b/sys/include/vm/vm.h @@ -34,6 +34,7 @@ #include #include #include +#include extern volatile struct limine_hhdm_request g_hhdm_request; @@ -50,6 +51,8 @@ struct vm_ctx { tlsf_t tlsf_ctx; }; +extern struct vas g_kvas; + struct vm_ctx *vm_get_ctx(void); void vm_init(void); diff --git a/sys/vm/vm_init.c b/sys/vm/vm_init.c index 703942b..b6bb8a1 100644 --- a/sys/vm/vm_init.c +++ b/sys/vm/vm_init.c @@ -31,11 +31,13 @@ #include #include #include +#include #include #define DYNALLOC_POOL_SZ 0x400000 /* 4 MiB */ #define DYNALLOC_POOL_PAGES (DYNALLOC_POOL_SZ / DEFAULT_PAGESIZE) +struct vas g_kvas; static struct vm_ctx vm_ctx; volatile struct limine_hhdm_request g_hhdm_request = { .id = LIMINE_HHDM_REQUEST, @@ -55,6 +57,7 @@ vm_init(void) vm_physmem_init(); + g_kvas = pmap_read_vas(); vm_ctx.dynalloc_pool_sz = DYNALLOC_POOL_SZ; vm_ctx.dynalloc_pool_pa = vm_alloc_frame(DYNALLOC_POOL_PAGES); if (vm_ctx.dynalloc_pool_pa == 0) { -- cgit v1.2.3 From 347a1a0eeb5aa84e287e443a468a47a0fafd153f Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 19:01:29 -0400 Subject: kernel/amd64: pmap: Add function to create new VAS Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/pmap.c | 33 +++++++++++++++++++++++++++++++++ sys/include/vm/pmap.h | 5 +++++ 2 files changed, 38 insertions(+) (limited to 'sys/include') diff --git a/sys/arch/amd64/amd64/pmap.c b/sys/arch/amd64/amd64/pmap.c index 6047699..108cd91 100644 --- a/sys/arch/amd64/amd64/pmap.c +++ b/sys/arch/amd64/amd64/pmap.c @@ -30,6 +30,7 @@ #include #include #include +#include #include #include #include @@ -191,6 +192,38 @@ pmap_update_tbl(struct vas vas, vaddr_t va, uint64_t val) return 0; } +int +pmap_new_vas(struct vas *res) +{ + const struct vas *kvas = &g_kvas; + struct vas new_vas; + uint64_t *src, *dest; + + new_vas.cr3_flags = kvas->cr3_flags; + new_vas.top_level = vm_alloc_frame(1); + if (new_vas.top_level == 0) + return -ENOMEM; + + src = PHYS_TO_VIRT(kvas->top_level); + dest = PHYS_TO_VIRT(new_vas.top_level); + + /* + * Keep the higher half but zero out the lower + * half for user programs. + */ + for (int i = 0; i < 512; ++i) { + if (i < 256) { + dest[i] = 0; + continue; + } + + dest[i] = src[i]; + } + + *res = new_vas; + return 0; +} + struct vas pmap_read_vas(void) { diff --git a/sys/include/vm/pmap.h b/sys/include/vm/pmap.h index ec669a8..dccfe0d 100644 --- a/sys/include/vm/pmap.h +++ b/sys/include/vm/pmap.h @@ -51,6 +51,11 @@ struct vas pmap_read_vas(void); */ void pmap_switch_vas(struct vas vas); +/* + * Create a new virtual address space. + */ +int pmap_new_vas(struct vas *res); + /* * Create a virtual memory mapping of a single page. */ -- 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') 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') 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 From 84f6abd193211b30c62a7c708edaccbe3ede8ee7 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 22:35:44 -0400 Subject: kernel/amd64: Add machdep thread init function Signed-off-by: Ian Moffett --- sys/arch/amd64/amd64/proc_machdep.c | 107 ++++++++++++++++++++++++++++++++++++ sys/include/sys/proc.h | 3 + 2 files changed, 110 insertions(+) create mode 100644 sys/arch/amd64/amd64/proc_machdep.c (limited to 'sys/include') diff --git a/sys/arch/amd64/amd64/proc_machdep.c b/sys/arch/amd64/amd64/proc_machdep.c new file mode 100644 index 0000000..eb3866a --- /dev/null +++ b/sys/arch/amd64/amd64/proc_machdep.c @@ -0,0 +1,107 @@ +/* + * 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 + +/* + * MD thread init code + * + * @p: New process. + * @parent: Parent of new process. + * @ip: Instruction pointer. + */ +int +md_td_init(struct proc *p, struct proc *parent, uintptr_t ip) +{ + uintptr_t stack_base; + struct trapframe *tfp, *parent_tfp; + struct pcb *pcbp; + uint8_t rpl; + int error; + + tfp = &p->tf; + + /* Create a new VAS for this thread */ + pcbp = &p->pcb; + if ((error = pmap_new_vas(&pcbp->addrsp)) != 0) + return error; + + /* + * If parent is NULL, assume kernel space and zero the + * trapframe. Otherwise we can just set it up normally. + */ + if (parent == NULL) { + rpl = 0; + memset(tfp, 0, sizeof(*tfp)); + } else { + parent_tfp = &parent->tf; + rpl = parent_tfp->cs & 3; + memcpy(tfp, &parent->tf, sizeof(*tfp)); + } + + /* + * RPL being 3 indicates that the parent thread is in + * userland. If this is the case, we'd want this new thread + * to also be in userland. + */ + tfp->rip = ip; + tfp->cs = (rpl == 3) ? (USER_CS | 3) : KERNEL_CS; + tfp->ss = (rpl == 3) ? (USER_DS | 3) : KERNEL_DS; + tfp->rflags = 0x202; + + /* Try to allocate a new stack */ + stack_base = vm_alloc_frame(PROC_STACK_PAGES); + if (stack_base == 0) + return -ENOMEM; + + /* + * If RPL is 0 (kernel), adjust the stack base to the + * higher half. If we have an RPL of 3 (user) then we'll + * need to identity map the stack. + */ + if (rpl == 0) { + stack_base += VM_HIGHER_HALF; + } else { + vm_map(pcbp->addrsp, stack_base, stack_base, + PROT_READ | PROT_WRITE | PROT_USER, PROC_STACK_PAGES); + } + + p->stack_base = stack_base; + tfp->rsp = ALIGN_DOWN((stack_base + PROC_STACK_SIZE) - 1, 16); + return 0; +} diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index b74cb00..db41a4b 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -39,6 +39,8 @@ #endif /* _KERNEL */ #if defined(_KERNEL) +#define PROC_STACK_PAGES 8 +#define PROC_STACK_SIZE (PROC_STACK_PAGES * DEFAULT_PAGESIZE) struct proc { pid_t pid; @@ -50,6 +52,7 @@ struct proc { }; struct proc *this_td(void); +int md_td_init(struct proc *p, struct proc *parent, uintptr_t ip); #endif /* _KERNEL */ #endif /* !_SYS_PROC_H_ */ -- cgit v1.2.3 From 9728334b0fbbcb3f13ea9a72918edf050c9d5560 Mon Sep 17 00:00:00 2001 From: Ian Moffett Date: Sun, 23 Jun 2024 22:38:25 -0400 Subject: kernel: Add fork1() Signed-off-by: Ian Moffett --- sys/include/sys/proc.h | 1 + sys/kern/kern_fork.c | 78 ++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 79 insertions(+) create mode 100644 sys/kern/kern_fork.c (limited to 'sys/include') diff --git a/sys/include/sys/proc.h b/sys/include/sys/proc.h index db41a4b..c74bca5 100644 --- a/sys/include/sys/proc.h +++ b/sys/include/sys/proc.h @@ -53,6 +53,7 @@ struct proc { struct proc *this_td(void); int md_td_init(struct proc *p, struct proc *parent, uintptr_t ip); +int fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp); #endif /* _KERNEL */ #endif /* !_SYS_PROC_H_ */ diff --git a/sys/kern/kern_fork.c b/sys/kern/kern_fork.c new file mode 100644 index 0000000..64e0caf --- /dev/null +++ b/sys/kern/kern_fork.c @@ -0,0 +1,78 @@ +/* + * 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 + +static size_t nthreads = 0; + +/* + * Fork1 - fork and direct a thread to 'ip' + * + * @cur: Current process. + * @flags: Flags to set. + * @ip: Location for new thread to start at. + * @newprocp: Will contain new thread if not NULL. + */ +int +fork1(struct proc *cur, int flags, void(*ip)(void), struct proc **newprocp) +{ + struct proc *newproc; + int status = 0; + + newproc = dynalloc(sizeof(*newproc)); + if (newproc == NULL) + return -ENOMEM; + + /* + * We want to zero the proc to ensure it is in known + * state. We then want to initialize machine dependent + * fields. + */ + memset(newproc, 0, sizeof(*newproc)); + status = md_td_init(newproc, cur, (uintptr_t)ip); + if (status != 0) + goto done; + + /* Set proc output if we can */ + if (newprocp != NULL) + *newprocp = newproc; + + newproc->pid = nthreads++; + sched_enqueue_td(newproc); +done: + if (status != 0) + dynfree(newproc); + + return status; +} -- cgit v1.2.3