diff options
Diffstat (limited to 'kernel/include/main')
| -rw-r--r-- | kernel/include/main/acpi.h | 20 | ||||
| -rw-r--r-- | kernel/include/main/apic.h | 73 | ||||
| -rw-r--r-- | kernel/include/main/cpuid.h | 118 | ||||
| -rw-r--r-- | kernel/include/main/entry.h | 3 | ||||
| -rw-r--r-- | kernel/include/main/gdt.h | 21 | ||||
| -rw-r--r-- | kernel/include/main/inits.h | 15 | ||||
| -rw-r--r-- | kernel/include/main/interrupt.h | 117 | ||||
| -rw-r--r-- | kernel/include/main/io.h | 46 | ||||
| -rw-r--r-- | kernel/include/main/smp.h | 22 |
9 files changed, 435 insertions, 0 deletions
diff --git a/kernel/include/main/acpi.h b/kernel/include/main/acpi.h new file mode 100644 index 0000000..dc49805 --- /dev/null +++ b/kernel/include/main/acpi.h @@ -0,0 +1,20 @@ +#pragma once + +#include <types.h> + +typedef struct acpi_header +{ + uint32_t ah_sign; + uint32_t ah_size; + uint8_t ah_rev; + uint8_t ah_checksum; + uint8_t ah_oemid[6]; + uint8_t ah_tableid[8]; + uint32_t ah_oemrev; + uint32_t ah_creatorid; + uint32_t ah_creatorrev; +} packed acpi_header_t; + +void acpi_init(); + +void *acpi_table(uint32_t signature, int index); diff --git a/kernel/include/main/apic.h b/kernel/include/main/apic.h new file mode 100644 index 0000000..ca9c8f5 --- /dev/null +++ b/kernel/include/main/apic.h @@ -0,0 +1,73 @@ +#pragma once + +#include "main/interrupt.h" +#include "types.h" + +typedef enum +{ + DESTINATION_MODE_FIXED = 0, + DESTINATION_MODE_LOWEST_PRIORITY = 1, + DESTINATION_MODE_SMI = 2, + DESTINATION_MODE_NMI = 4, + DESTINATION_MODE_INIT = 5, + DESTINATION_MODE_SIPI = 6 +} ipi_destination_mode; + +#define MAX_LAPICS 8 + +/* Initializes the APIC using data from the ACPI tables. + * ACPI handlers must be initialized before calling this + * function. */ +void apic_init(); + +/* Returns the APIC ID of the current processor */ +long apic_current_id(); + +/* Returns the largest known APIC ID */ +long apic_max_id(); + +/* Maps the given IRQ to the given interrupt number. */ +void apic_setredir(uint32_t irq, uint8_t intr); + +void apic_enable(); + +// timer interrupts arrive at a rate of (freq / 16) interrupts per millisecond +// (with an ) +/* Starts the APIC timer */ +void apic_enable_periodic_timer(uint32_t freq); + +/* Stops the APIC timer */ +void apic_disable_periodic_timer(); + +/* Sets the interrupt to raise when a spurious + * interrupt occurs. */ +void apic_setspur(uint8_t intr); + +/* Sets the interrupt priority level. This function should + * be accessed via wrappers in the interrupt subsystem. */ +void apic_setipl(uint8_t ipl); + +/* Gets the interrupt priority level. This function should + * be accessed via wrappers in the interrupt subsystem. */ +uint8_t apic_getipl(); + +long apic_initialized(); + +/* Writes to the APIC's memory mapped end-of-interrupt + * register to indicate that the handling of an interrupt + * originating from the APIC has been finished. This function + * should only be called from the interrupt subsystem. */ +void apic_eoi(); + +void apic_start_processor(uint8_t target, uint8_t execution_page); + +void apic_send_ipi(uint8_t target, ipi_destination_mode destination_mode, + uint8_t vector); + +void apic_broadcast_ipi(ipi_destination_mode mode, uint8_t vector, + long include_self); + +/** + * Wait for the last IPI sent to be acknowledged by the target processor. + */ +void apic_wait_ipi();
\ No newline at end of file diff --git a/kernel/include/main/cpuid.h b/kernel/include/main/cpuid.h new file mode 100644 index 0000000..5d4b5fa --- /dev/null +++ b/kernel/include/main/cpuid.h @@ -0,0 +1,118 @@ +#pragma once + +#include <types.h> + +/* Vendor-strings. */ +#define CPUID_VENDOR_AMD "AuthenticAMD" +#define CPUID_VENDOR_INTEL "GenuineIntel" +#define CPUID_VENDOR_VIA "CentaurHauls" +#define CPUID_VENDOR_OLDTRANSMETA "TransmetaCPU" +#define CPUID_VENDOR_TRANSMETA "GenuineTMx86" +#define CPUID_VENDOR_CYRIX "CyrixInstead" +#define CPUID_VENDOR_CENTAUR "CentaurHauls" +#define CPUID_VENDOR_NEXGEN "NexGenDriven" +#define CPUID_VENDOR_UMC "UMC UMC UMC " +#define CPUID_VENDOR_SIS "SiS SiS SiS " +#define CPUID_VENDOR_NSC "Geode by NSC" +#define CPUID_VENDOR_RISE "RiseRiseRise" + +enum +{ + CPUID_FEAT_ECX_SSE3 = 1 << 0, + CPUID_FEAT_ECX_PCLMUL = 1 << 1, + CPUID_FEAT_ECX_DTES64 = 1 << 2, + CPUID_FEAT_ECX_MONITOR = 1 << 3, + CPUID_FEAT_ECX_DS_CPL = 1 << 4, + CPUID_FEAT_ECX_VMX = 1 << 5, + CPUID_FEAT_ECX_SMX = 1 << 6, + CPUID_FEAT_ECX_EST = 1 << 7, + CPUID_FEAT_ECX_TM2 = 1 << 8, + CPUID_FEAT_ECX_SSSE3 = 1 << 9, + CPUID_FEAT_ECX_CID = 1 << 10, + CPUID_FEAT_ECX_FMA = 1 << 12, + CPUID_FEAT_ECX_CX16 = 1 << 13, + CPUID_FEAT_ECX_ETPRD = 1 << 14, + CPUID_FEAT_ECX_PDCM = 1 << 15, + CPUID_FEAT_ECX_DCA = 1 << 18, + CPUID_FEAT_ECX_SSE4_1 = 1 << 19, + CPUID_FEAT_ECX_SSE4_2 = 1 << 20, + CPUID_FEAT_ECX_x2APIC = 1 << 21, + CPUID_FEAT_ECX_MOVBE = 1 << 22, + CPUID_FEAT_ECX_POPCNT = 1 << 23, + CPUID_FEAT_ECX_XSAVE = 1 << 26, + CPUID_FEAT_ECX_OSXSAVE = 1 << 27, + CPUID_FEAT_ECX_AVX = 1 << 28, + + CPUID_FEAT_EDX_FPU = 1 << 0, + CPUID_FEAT_EDX_VME = 1 << 1, + CPUID_FEAT_EDX_DE = 1 << 2, + CPUID_FEAT_EDX_PSE = 1 << 3, + CPUID_FEAT_EDX_TSC = 1 << 4, + CPUID_FEAT_EDX_MSR = 1 << 5, + CPUID_FEAT_EDX_PAE = 1 << 6, + CPUID_FEAT_EDX_MCE = 1 << 7, + CPUID_FEAT_EDX_CX8 = 1 << 8, + CPUID_FEAT_EDX_APIC = 1 << 9, + CPUID_FEAT_EDX_SEP = 1 << 11, + CPUID_FEAT_EDX_MTRR = 1 << 12, + CPUID_FEAT_EDX_PGE = 1 << 13, + CPUID_FEAT_EDX_MCA = 1 << 14, + CPUID_FEAT_EDX_CMOV = 1 << 15, + CPUID_FEAT_EDX_PAT = 1 << 16, + CPUID_FEAT_EDX_PSE36 = 1 << 17, + CPUID_FEAT_EDX_PSN = 1 << 18, + CPUID_FEAT_EDX_CLF = 1 << 19, + CPUID_FEAT_EDX_DTES = 1 << 21, + CPUID_FEAT_EDX_ACPI = 1 << 22, + CPUID_FEAT_EDX_MMX = 1 << 23, + CPUID_FEAT_EDX_FXSR = 1 << 24, + CPUID_FEAT_EDX_SSE = 1 << 25, + CPUID_FEAT_EDX_SSE2 = 1 << 26, + CPUID_FEAT_EDX_SS = 1 << 27, + CPUID_FEAT_EDX_HTT = 1 << 28, + CPUID_FEAT_EDX_TM1 = 1 << 29, + CPUID_FEAT_EDX_IA64 = 1 << 30, + CPUID_FEAT_EDX_PBE = 1 << 31 +}; + +enum cpuid_requests +{ + CPUID_GETVENDORSTRING, + CPUID_GETFEATURES, + CPUID_GETTLB, + CPUID_GETSERIAL, + + CPUID_INTELEXTENDED = 0x80000000, + CPUID_INTELFEATURES, + CPUID_INTELBRANDSTRING, + CPUID_INTELBRANDSTRINGMORE, + CPUID_INTELBRANDSTRINGEND, +}; + +static inline void cpuid(int request, uint32_t *a, uint32_t *b, uint32_t *c, + uint32_t *d) +{ + __asm__ volatile("cpuid" + : "=a"(*a), "=b"(*b), "=c"(*c), "=d"(*d) + : "0"(request)); +} + +static inline void cpuid_get_msr(uint32_t msr, uint32_t *lo, uint32_t *hi) +{ + __asm__ volatile("rdmsr" + : "=a"(*lo), "=d"(*hi) + : "c"(msr)); +} + +static inline void cpuid_set_msr(uint32_t msr, uint32_t lo, uint32_t hi) +{ + __asm__ volatile("wrmsr" ::"a"(lo), "d"(hi), "c"(msr)); +} + +static inline void io_wait(void) +{ + __asm__ volatile( + "jmp 1f\n\t" + "1:jmp 2f\n\t" + "2:"); +} diff --git a/kernel/include/main/entry.h b/kernel/include/main/entry.h new file mode 100644 index 0000000..64c0e96 --- /dev/null +++ b/kernel/include/main/entry.h @@ -0,0 +1,3 @@ +/* entry.h */ + +void kmain(void); diff --git a/kernel/include/main/gdt.h b/kernel/include/main/gdt.h new file mode 100644 index 0000000..a991cbf --- /dev/null +++ b/kernel/include/main/gdt.h @@ -0,0 +1,21 @@ +#pragma once + +#include "types.h" + +#define GDT_COUNT 16 + +#define GDT_ZERO 0x00 +#define GDT_KERNEL_TEXT 0x08 +#define GDT_KERNEL_DATA 0x10 +#define GDT_USER_TEXT 0x18 +#define GDT_USER_DATA 0x20 +#define GDT_TSS 0x28 + +void gdt_init(void); + +void gdt_set_kernel_stack(void *addr); + +void gdt_set_entry(uint32_t segment, uint32_t base, uint32_t limit, + uint8_t ring, int exec, int dir, int rw); + +void gdt_clear(uint32_t segment);
\ No newline at end of file diff --git a/kernel/include/main/inits.h b/kernel/include/main/inits.h new file mode 100644 index 0000000..5013b07 --- /dev/null +++ b/kernel/include/main/inits.h @@ -0,0 +1,15 @@ +#pragma once + +extern void sched_init(); + +extern void kshell_init(); + +extern void file_init(); + +extern void pipe_init(); + +extern void vfs_init(); + +extern void syscall_init(); + +extern void elf64_init(void); diff --git a/kernel/include/main/interrupt.h b/kernel/include/main/interrupt.h new file mode 100644 index 0000000..6a9ae00 --- /dev/null +++ b/kernel/include/main/interrupt.h @@ -0,0 +1,117 @@ +#pragma once + +#include "kernel.h" +#include "types.h" +#include "util/debug.h" + +// intr_disk_priamry/seconday so that they are different task priority classes +#define INTR_DIVIDE_BY_ZERO 0x00 +#define INTR_INVALID_OPCODE 0x06 +#define INTR_GPF 0x0d +#define INTR_PAGE_FAULT 0x0e + +#define INTR_APICTIMER 0xf0 +#define INTR_KEYBOARD 0xe0 + +#define INTR_DISK_PRIMARY 0xd0 +#define INTR_SPURIOUS 0xfe +#define INTR_APICERR 0xff +#define INTR_SHUTDOWN 0xfd + +/* NOTE: INTR_SYSCALL is not defined here, but is in syscall.h (it must be + * in a userland-accessible header) */ + +// Intel Volume 3-A, 10.8.3.1 (10-29) +#define IPL_LOW 0 +// we want to keep timer interrupts happening all the time to keep track of time +// :) +#define IPL_HIGH 0xe0 +#define IPL_HIGHEST 0xff + +typedef struct regs +{ + // all the regs + uint64_t r_r15; + uint64_t r_r14; + uint64_t r_r13; + uint64_t r_r12; + uint64_t r_rbp; + uint64_t r_rbx; + uint64_t r_r11; + uint64_t r_r10; + uint64_t r_r9; + uint64_t r_r8; + uint64_t r_rax; + uint64_t r_rcx; + uint64_t r_rdx; + uint64_t r_rsi; + uint64_t r_rdi; + + // interrupt number + uint64_t r_intr; + + // pushed by processor + uint64_t r_err; + uint64_t r_rip; + uint64_t r_cs; + uint64_t r_rflags; + uint64_t r_rsp; + uint64_t r_ss; +} packed regs_t; + +void intr_init(); + +/* The function pointer which should be implemented by functions + * which will handle interrupts. These handlers should be registered + * with the interrupt subsystem via the intr_register function. + * The regs structure contains the state of the registers saved when + * the interrupt occured. Return whether or not the handler has itself + * acknowledged the interrupt with a call to apic_eoi(). */ +typedef long (*intr_handler_t)(regs_t *regs); + +/* Registers an interrupt handler for the given interrupt handler. + * If another handler had been previously registered for this interrupt + * number it is returned, otherwise this function returns NULL. It + * is good practice to assert that this function returns NULL unless + * it is known that this will not be the case. */ +intr_handler_t intr_register(uint8_t intr, intr_handler_t handler); + +int32_t intr_map(uint16_t irq, uint8_t intr); + +static inline uint64_t intr_enabled() +{ + uint64_t flags; + __asm__ volatile("pushf; pop %0; and $0x200, %0;" + : "=r"(flags)::); + return flags; +} + +static inline void intr_enable() { __asm__ volatile("sti"); } + +static inline void intr_disable() { __asm__ volatile("cli"); } + +/* Atomically enables interrupts using the sti + * instruction and puts the processor into a halted + * state, this function returns once an interrupt + * occurs. */ +static inline void intr_wait() +{ + /* the sti instruction enables interrupts, however + * interrupts are not checked for until the next + * instruction is executed, this means that the following + * code will not be succeptible to a bug where an + * interrupt occurs between the sti and hlt commands + * and does not wake us up from the hlt. */ + __asm__ volatile("sti; hlt"); +} + +/* Sets the interrupt priority level for hardware interrupts. + * At initialization time devices should detect their individual + * IPLs and save them for use with this function. IPL_LOW allows + * all hardware interrupts. IPL_HIGH blocks all hardware interrupts */ +uint8_t intr_setipl(uint8_t ipl); + +/* Retreives the current interrupt priority level. */ +uint8_t intr_getipl(); + +void dump_registers(regs_t *regs); diff --git a/kernel/include/main/io.h b/kernel/include/main/io.h new file mode 100644 index 0000000..19c6f86 --- /dev/null +++ b/kernel/include/main/io.h @@ -0,0 +1,46 @@ +#pragma once + +#include "kernel.h" +#include "types.h" + +static inline void outb(uint16_t port, uint8_t val) +{ + __asm__ volatile("outb %0,%1" ::"a"(val), "Nd"(port)); +} + +static inline uint8_t inb(uint16_t port) +{ + uint8_t ret; + __asm__ volatile("inb %1,%0" + : "=a"(ret) + : "Nd"(port)); + return ret; +} + +static inline void outw(uint16_t port, uint16_t val) +{ + __asm__ volatile("outw %0,%1" ::"a"(val), "Nd"(port)); +} + +static inline uint16_t inw(uint16_t port) +{ + uint16_t ret; + __asm__ volatile("inw %1,%0" + : "=a"(ret) + : "Nd"(port)); + return ret; +} + +static inline void outl(uint16_t port, uint32_t val) +{ + __asm__ volatile("outl %0,%1" ::"a"(val), "Nd"(port)); +} + +static inline uint32_t inl(uint16_t port) +{ + uint32_t ret; + __asm__ volatile("inl %1,%0" + : "=a"(ret) + : "Nd"(port)); + return ret; +} diff --git a/kernel/include/main/smp.h b/kernel/include/main/smp.h new file mode 100644 index 0000000..bf05fff --- /dev/null +++ b/kernel/include/main/smp.h @@ -0,0 +1,22 @@ +#include "boot/config.h" +#include "mm/page.h" +#include "proc/core.h" + +// For any given piece of global data, there are 4 cases we must protect +// against: (SMP.1) our core's other threads, (mutex or mask interrupts) (SMP.2) +// our core's interrupt handlers, and (mask interrupts) (SMP.3) other cores' +// threads, (mutex or spinlock) (SMP.4) other cores' interrupt handlers +// (spinlock) mask interrupts + spinlock covers all 4 cases! + +#define GET_CSD(core, type, name) \ + ((type *)(csd_vaddr_table[(core)] + PAGE_OFFSET(&(name)))) + +extern uintptr_t csd_vaddr_table[]; + +void map_in_core_specific_data(pml4_t *pml4); + +void smp_init(); + +void core_init(); + +long is_core_specific_data(void *addr); |
