diff --git a/arch/x86_64/acpi/acpi.c b/arch/x86_64/acpi/acpi.c index c7ca9e9..cded109 100644 --- a/arch/x86_64/acpi/acpi.c +++ b/arch/x86_64/acpi/acpi.c @@ -3,5 +3,8 @@ kern_status_t acpi_init(void) { + apic_init(); + smp_init(); + return KERN_OK; } diff --git a/arch/x86_64/acpi/apic.c b/arch/x86_64/acpi/apic.c new file mode 100644 index 0000000..5ec13be --- /dev/null +++ b/arch/x86_64/acpi/apic.c @@ -0,0 +1,109 @@ +#include +#include +#include +#include +#include +#include +#include + +#define PIC1_DATA 0x21 +#define PIC2_DATA 0xA1 + +#define IA32_APIC_BASE_MSR 0x1B +#define IA32_APIC_BASE_MSR_BSP 0x100 +#define IA32_APIC_BASE_MSR_ENABLE 0x800 + +static uint32_t *lapic_base; + +extern int check_apic(void); + +static uintptr_t apic_get_base(void) +{ + return rdmsr(IA32_APIC_BASE_MSR); +} + +static void apic_set_base(uintptr_t addr) +{ + wrmsr(IA32_APIC_BASE_MSR, addr); +} + +static void disable_8259(void) +{ + /* mask all interrupts on PICs 1 and 2 */ + outportb(PIC1_DATA, 0xFF); + outportb(PIC2_DATA, 0xFF); +} + +static uint32_t local_apic_read(uint32_t reg) +{ + return READ_ONCE(lapic_base[reg >> 4]); +} + +static void local_apic_write(uint32_t reg, uint32_t val) +{ + +} + +static void *find_lapic(struct acpi_madt *madt) +{ + phys_addr_t local_apic = madt->m_lapic_ptr; + + unsigned char *p = (unsigned char *)madt + sizeof *madt; + unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length; + + while (p < madt_end) { + struct acpi_madt_record *rec = (struct acpi_madt_record *)p; + struct lapic_override_record *lapic; + + switch (rec->r_type) { + case ACPI_MADT_LAPIC_OVERRIDE: + lapic = (struct lapic_override_record *)(rec + 1); + return vm_phys_to_virt(lapic->l_lapic_ptr); + default: + break; + } + + p += rec->r_length; + } + + return vm_phys_to_virt(local_apic); +} + + +kern_status_t local_apic_enable(void) +{ + struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT); + if (!madt) { + return KERN_UNSUPPORTED; + } + + apic_set_base(apic_get_base()); + lapic_base = find_lapic(madt); + + local_apic_write(0xF0, local_apic_read(0xF0) | 0x100); + + printk("acpi: enabled local APIC on core %u", this_cpu()); + return KERN_OK; +} + +static void configure_legacy_pic(void) +{ + printk("acpi: APIC unavailable, using 8259 PIC"); + pit_init(1000); +} + +kern_status_t apic_init(void) +{ + if (check_apic() == 0) { + configure_legacy_pic(); + return KERN_UNSUPPORTED; + } + + if (local_apic_enable() != KERN_OK) { + configure_legacy_pic(); + return KERN_UNSUPPORTED; + } + + disable_8259(); + return KERN_OK; +} diff --git a/arch/x86_64/acpi/apic_ctrl.S b/arch/x86_64/acpi/apic_ctrl.S new file mode 100644 index 0000000..910919c --- /dev/null +++ b/arch/x86_64/acpi/apic_ctrl.S @@ -0,0 +1,18 @@ + .global check_apic + .type check_apic, @function +check_apic: + push %rbp + mov %rsp, %rbp + + push %rbx + mov $1, %rax + cpuid + + andl $0x200, %edx + shr $9, %edx + + mov %rdx, %rax + + pop %rbx + pop %rbp + ret diff --git a/arch/x86_64/acpi/rsdp.c b/arch/x86_64/acpi/rsdp.c index 9c554fc..c681275 100644 --- a/arch/x86_64/acpi/rsdp.c +++ b/arch/x86_64/acpi/rsdp.c @@ -9,7 +9,7 @@ static struct acpi_rsdp_10 *search_for_rsdp(void) { uint64_t *start = vm_phys_to_virt(0x80000); uint64_t *end = vm_phys_to_virt(0xFFFFF); - + for (uint64_t *i = start; i < end; i++) { if (*i == ACPI_SIG_RSDP) { return (struct acpi_rsdp_10 *)i; @@ -24,7 +24,6 @@ static int init_rsdt(void) struct acpi_rsdp_10 *x = search_for_rsdp(); if (!x) { - printk("acpi: not available"); return -1; } @@ -33,25 +32,23 @@ static int init_rsdt(void) for (unsigned int i = 0; i < sizeof *x; i++) { chksum += b[i]; } - + if (chksum & 0xFF) { - printk("acpi: not available"); return -1; } if (x->r_revision == 2) { chksum = 0; - + for (unsigned int i = sizeof *x; i < sizeof(struct acpi_rsdp_20); i++) { chksum += b[i]; } if (chksum & 0xFF) { - printk("acpi: not available"); return -1; } } - + memcpy(&rsdp.rsdp_20, x, sizeof rsdp.rsdp_20); return 0; } diff --git a/arch/x86_64/acpi/smp.c b/arch/x86_64/acpi/smp.c index 11cdb1d..1be5c88 100644 --- a/arch/x86_64/acpi/smp.c +++ b/arch/x86_64/acpi/smp.c @@ -3,27 +3,6 @@ #include #include -#define AP_TRAMPOLINE_PADDR 0x8000 -#define LAPIC_IPI_STATUS_REG 0x0280 -#define LAPIC_IPI_DEST_REG 0x0310 -#define LAPIC_IPI_ICR_REG 0x0300 - -struct acpi_madt_record { - uint8_t r_type; - uint8_t r_length; -} __packed; - -struct lapic_record { - uint8_t l_cpu_id; - uint8_t l_apic_id; - uint32_t l_flags; -} __packed; - -struct lapic_override_record { - uint16_t l_reserved; - uint64_t l_lapic_ptr; -} __packed; - extern uint8_t acpi_bsp_lapic_id(void); extern char ap_trampoline[]; @@ -61,31 +40,6 @@ static int __used init_ap(struct acpi_madt_record *rec, void *bsp_lapic, uint8_t return 0; } -static void *__used find_lapic(struct acpi_madt *madt) -{ - phys_addr_t local_apic = madt->m_lapic_ptr; - - unsigned char *p = (unsigned char *)madt + sizeof *madt; - unsigned char *madt_end = (unsigned char *)madt + madt->m_base.s_length; - - while (p < madt_end) { - struct acpi_madt_record *rec = (struct acpi_madt_record *)p; - struct lapic_override_record *lapic; - - switch (rec->r_type) { - case ACPI_MADT_LAPIC_OVERRIDE: - lapic = (struct lapic_override_record *)(rec + 1); - return vm_phys_to_virt(lapic->l_lapic_ptr); - default: - break; - } - - p += rec->r_length; - } - - return vm_phys_to_virt(local_apic); -} - /* kern_status_t acpi_smp_init(void) { @@ -125,10 +79,20 @@ kern_status_t acpi_smp_init(void) } */ +static void no_smp_config(void) +{ + cpu_set_available(0); + cpu_set_online(0); + + ml_cpu_block *self = ml_this_cpu(); + self->c_cpu_id = 0; +} + kern_status_t acpi_scan_cpu_topology(void) { struct acpi_madt *madt = (struct acpi_madt *)acpi_find_sdt(ACPI_SIG_MADT); if (!madt) { + no_smp_config(); return KERN_UNSUPPORTED; } @@ -171,3 +135,8 @@ kern_status_t acpi_scan_cpu_topology(void) printk("acpi: found %u logical cores", nr_processors); return KERN_OK; } + +kern_status_t smp_init(void) +{ + return KERN_OK; +} diff --git a/arch/x86_64/include/arch/acpi.h b/arch/x86_64/include/arch/acpi.h index 6532ce3..6535e49 100644 --- a/arch/x86_64/include/arch/acpi.h +++ b/arch/x86_64/include/arch/acpi.h @@ -13,6 +13,11 @@ #define ACPI_SIG_FADT 0x50434146 #define ACPI_SIG_MADT 0x43495041 +#define AP_TRAMPOLINE_PADDR 0x8000 +#define LAPIC_IPI_STATUS_REG 0x0280 +#define LAPIC_IPI_DEST_REG 0x0310 +#define LAPIC_IPI_ICR_REG 0x0300 + struct acpi_rsdp_10 { char r_sig[8]; uint8_t r_chksum; @@ -65,9 +70,29 @@ struct acpi_madt { uint32_t m_flags; } __packed; +struct acpi_madt_record { + uint8_t r_type; + uint8_t r_length; +} __packed; + +struct lapic_record { + uint8_t l_cpu_id; + uint8_t l_apic_id; + uint32_t l_flags; +} __packed; + +struct lapic_override_record { + uint16_t l_reserved; + uint64_t l_lapic_ptr; +} __packed; + + extern kern_status_t acpi_init(void); extern kern_status_t acpi_scan_cpu_topology(void); +extern kern_status_t apic_init(void); +extern kern_status_t smp_init(void); + extern struct acpi_sdt *acpi_find_sdt(uint32_t sig); #endif diff --git a/arch/x86_64/include/arch/irq.h b/arch/x86_64/include/arch/irq.h index 54d1a17..4aa95e5 100644 --- a/arch/x86_64/include/arch/irq.h +++ b/arch/x86_64/include/arch/irq.h @@ -2,10 +2,35 @@ #define ARCH_IRQ_H_ #include +#include #include #define NR_IDT_ENTRIES 48 +typedef enum irq_vector { + IRQ0 = 32, + IRQ1, + IRQ2, + IRQ3, + IRQ4, + IRQ5, + IRQ6, + IRQ7, + IRQ8, + IRQ9, + IRQ10, + IRQ11, + IRQ12, + IRQ13, + IRQ14, + IRQ15, +} irq_vector_t; + +typedef struct irq_hook { + queue_entry_t irq_entry; + int (*irq_callback)(void); +} irq_hook_t; + struct cpu_context { uint64_t r15, r14, r13, r12, r11, r10, r9, r8; uint64_t rdi, rsi, rbp, unused_rsp, rbx, rdx, rcx, rax; @@ -40,4 +65,6 @@ typedef void (*int_hook)(struct cpu_context *); extern int idt_init(struct idt_ptr *idtp); extern int idt_load(struct idt_ptr *idtp); +extern void hook_irq(irq_vector_t vec, irq_hook_t *hook); + #endif diff --git a/arch/x86_64/include/arch/pit.h b/arch/x86_64/include/arch/pit.h new file mode 100644 index 0000000..4d46017 --- /dev/null +++ b/arch/x86_64/include/arch/pit.h @@ -0,0 +1,6 @@ +#ifndef ARCH_PIT_H_ +#define ARCH_PIT_H_ + +extern void pit_init(unsigned int hz); + +#endif diff --git a/arch/x86_64/include/socks/machine/cpu.h b/arch/x86_64/include/socks/machine/cpu.h index 0a721c2..b082f8b 100644 --- a/arch/x86_64/include/socks/machine/cpu.h +++ b/arch/x86_64/include/socks/machine/cpu.h @@ -16,6 +16,9 @@ typedef struct ml_cpu_block { unsigned int c_cpu_id; } ml_cpu_block; +#define ml_cpu_pause() asm volatile("hlt") +#define ml_cpu_relax() asm volatile("pause") + extern int ml_init_bootcpu(void); extern int ml_cpu_block_init(ml_cpu_block *p); diff --git a/arch/x86_64/init.c b/arch/x86_64/init.c index 76f11b7..e95277c 100644 --- a/arch/x86_64/init.c +++ b/arch/x86_64/init.c @@ -70,5 +70,12 @@ int ml_init(uintptr_t arg) vm_bootstrap(vm_zones, sizeof vm_zones / sizeof vm_zones[0]); + object_bootstrap(); + sched_init(); + + acpi_init(); + + asm volatile("sti"); + return 0; } diff --git a/arch/x86_64/irq.c b/arch/x86_64/irq.c index 170f24a..6ff5123 100644 --- a/arch/x86_64/irq.c +++ b/arch/x86_64/irq.c @@ -63,6 +63,7 @@ extern void syscall_gate(); extern uintptr_t pf_faultptr(void); static int_hook isr_handlers[NR_IDT_ENTRIES]; +static queue_t irq_hooks[32]; static struct idt idt; static int idt_initialised = 0; @@ -86,7 +87,7 @@ static void gpf_handler(struct cpu_context *regs) int ext = regs->err_no & 1; int table = (regs->err_no >> 1) & 2; int index = (regs->err_no >> 3) & 13; - + printk("general protection fault (%08x %08x %08x %016llx)", ext, table, index, regs->rip); ml_halt_cpu(); } @@ -103,23 +104,21 @@ static void set_syscall_gate(uintptr_t rip) /* sysret adds 0x10 to this to get cs, and 0x8 to get ss * note that the CPU should force the RPL to 3 when loading * the selector by using user_cs | 3. However, this doesn't happen - * in certain scenarios (specifically, QEMU + KVM on a Ryzen 5 1600X). - * It's probably a Magenta bug, but just in case it's not, - * we perform the RPL OR ourselves */ + * in certain scenarios (specifically, QEMU + KVM on a Ryzen 5 1600X). */ uint64_t user_cs = 0x13; uint64_t kernel_cs = 0x8; - + uintptr_t star_reg = 0xC0000081; uintptr_t lstar_reg = 0xC0000082; uintptr_t sfmask_reg = 0xC0000084; - + uint64_t selectors = 0; selectors |= (user_cs) << 48; selectors |= (kernel_cs) << 32; - + /* disable interrupts */ uint64_t flag_mask = 0x200; - + write_msr(star_reg, selectors); write_msr(lstar_reg, rip); write_msr(sfmask_reg, flag_mask); @@ -139,7 +138,7 @@ static void init_pic() outportb(0xA1, 0x01); outportb(0x21, 0x0); outportb(0xA1, 0x0); - + isr_handlers[13] = gpf_handler; isr_handlers[14] = pf_handler; } @@ -147,7 +146,7 @@ static void init_pic() static void init_global_idt(void) { memset((void *)&idt.i_entries, 0, sizeof idt.i_entries); - + set_idt_gate(&idt, 0, (uintptr_t)_isr0, 0x08, 0x8E); set_idt_gate(&idt, 1, (uintptr_t)_isr1, 0x08, 0x8E); set_idt_gate(&idt, 2, (uintptr_t)_isr2, 0x08, 0x8E); @@ -180,9 +179,9 @@ static void init_global_idt(void) set_idt_gate(&idt, 29, (uintptr_t)_isr29, 0x08, 0x8E); set_idt_gate(&idt, 30, (uintptr_t)_isr30, 0x08, 0x8E); set_idt_gate(&idt, 31, (uintptr_t)_isr31, 0x08, 0x8E); - + init_pic(); - + // Install the IRQs set_idt_gate(&idt, 32, (uintptr_t)_irq0, 0x08, 0x8E); set_idt_gate(&idt, 33, (uintptr_t)_irq1, 0x08, 0x8E); @@ -209,10 +208,10 @@ int idt_init(struct idt_ptr *ptr) if (idt_initialised == 0) { init_global_idt(); } - + ptr->i_limit = sizeof(idt) - 1; ptr->i_base = (uintptr_t)&idt; - + return 0; } @@ -235,8 +234,13 @@ void irq_dispatch(struct cpu_context *regs) if (regs->int_no >= 40) { outportb(0xA0, 0x20); } - + outportb(0x20, 0x20); + + queue_t *hooks = &irq_hooks[regs->int_no - IRQ0]; + queue_foreach(irq_hook_t, hook, hooks, irq_entry) { + hook->irq_callback(); + } } void syscall_dispatch(struct cpu_context *regs) @@ -253,3 +257,9 @@ void ml_int_disable() { asm volatile("cli"); } + +void hook_irq(irq_vector_t vec, irq_hook_t *hook) +{ + queue_t *hook_queue = &irq_hooks[vec - IRQ0]; + queue_push_back(hook_queue, &hook->irq_entry); +} diff --git a/arch/x86_64/pit.c b/arch/x86_64/pit.c new file mode 100644 index 0000000..b2a35dd --- /dev/null +++ b/arch/x86_64/pit.c @@ -0,0 +1,29 @@ +#include +#include +#include + +static int pit_callback(void) +{ + printk("tick"); + return 0; +} + +static irq_hook_t pit_irq_hook = { + .irq_callback = pit_callback +}; + +void pit_init(unsigned int hz) +{ + unsigned int divisor = 1193180 / hz; + + outportb(0x43, 0x36); + uint8_t lo = (uint8_t)(divisor & 0xFF); + uint8_t hi = (uint8_t)((divisor >> 8) & 0xFF); + + outportb(0x40, lo); + outportb(0x40, hi); + + hook_irq(IRQ0, &pit_irq_hook); + + printk("clock: 8253 PIT initialised at %uHz", hz); +} diff --git a/init/main.c b/init/main.c index 8100da0..e4810aa 100644 --- a/init/main.c +++ b/init/main.c @@ -20,12 +20,11 @@ void kernel_init(uintptr_t arg) { ml_init(arg); - object_bootstrap(); - sched_init(); - printk("kernel_init() running on processor %u", this_cpu()); run_all_tests(); - ml_halt_cpu(); + while (1) { + ml_cpu_pause(); + } }