diff --git a/arch/amd64/hw/acpi.c b/arch/amd64/hw/acpi.c index 1db4634..1adb0bb 100644 --- a/arch/amd64/hw/acpi.c +++ b/arch/amd64/hw/acpi.c @@ -18,10 +18,10 @@ static uint8_t checksum(const void *ptr, size_t size) { return v; } -static uint32_t acpi_power_button_handler(void *ctx) { - kinfo("Power button was pressed\n"); - return 0; -} +//static uint32_t acpi_power_button_handler(void *ctx) { +// kinfo("Power button was pressed\n"); +// return 0; +//} static ACPI_STATUS acpica_init(void) { ACPI_STATUS ret; @@ -72,11 +72,11 @@ static ACPI_STATUS acpica_init(void) { return ret; } - if (ACPI_FAILURE(ret = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, - acpi_power_button_handler, - NULL))) { - kwarn("Failed to install ACPI power button handler: %s\n", AcpiFormatException(ret)); - } + //if (ACPI_FAILURE(ret = AcpiInstallFixedEventHandler(ACPI_EVENT_POWER_BUTTON, + // acpi_power_button_handler, + // NULL))) { + // kwarn("Failed to install ACPI power button handler: %s\n", AcpiFormatException(ret)); + //} return AE_OK; } diff --git a/arch/amd64/hw/con.c b/arch/amd64/hw/con.c index 1b343d0..96aa862 100644 --- a/arch/amd64/hw/con.c +++ b/arch/amd64/hw/con.c @@ -309,9 +309,6 @@ void amd64_con_putc(int c) { return; } - uintptr_t irq; - spin_lock_irqsave(&display_lock, &irq); - c = (uint8_t) (c & 0xFF); switch (esc_mode) { @@ -342,7 +339,6 @@ void amd64_con_putc(int c) { esc_argv[0] = 0; esc_argc = 0; - spin_release_irqrestore(&display_lock, &irq); return; } if (c >= ' ') { @@ -366,18 +362,18 @@ void amd64_con_putc(int c) { break; default: amd64_con_putc('?'); - spin_release_irqrestore(&display_lock, &irq); return; } } break; } - - spin_release_irqrestore(&display_lock, &irq); } int pc_con_putc(void *dev, char c) { + uintptr_t irq; + spin_lock_irqsave(&display_lock, &irq); amd64_con_putc(c); + spin_release_irqrestore(&display_lock, &irq); return 0; } diff --git a/arch/amd64/hw/exc.c b/arch/amd64/hw/exc.c index 34ab884..59a6ed5 100644 --- a/arch/amd64/hw/exc.c +++ b/arch/amd64/hw/exc.c @@ -1,3 +1,8 @@ +#if defined(AMD64_SMP) +#include "arch/amd64/smp/ipi.h" +#include "arch/amd64/smp/smp.h" +#endif +#include "arch/amd64/cpu.h" #include "sys/types.h" #include "sys/debug.h" #include "sys/panic.h" @@ -36,6 +41,17 @@ struct amd64_exception_frame { }; void amd64_exception(struct amd64_exception_frame *frame) { + kfatal("Error\n"); +#if defined(AMD64_SMP) + // Send PANIC IPIs to all other CPUs + size_t cpu = get_cpu()->processor_id; + kfatal("cpu%u initiates panic sequence\n", cpu); + for (size_t i = 0; i < smp_ncpus; ++i) { + if (i != cpu) { + amd64_ipi_send(i, IPI_VECTOR_PANIC); + } + } +#endif // Dump frame kfatal("CPU raised exception #%u\n", frame->exc_no); @@ -107,5 +123,7 @@ void amd64_exception(struct amd64_exception_frame *frame) { kfatal("%rip is in unknown location\n"); } - panic("Exception without resolution\n"); + while (1) { + asm volatile ("cli; hlt"); + } } diff --git a/arch/amd64/hw/exc_s.S b/arch/amd64/hw/exc_s.S index 1d5a0e1..de22394 100644 --- a/arch/amd64/hw/exc_s.S +++ b/arch/amd64/hw/exc_s.S @@ -37,6 +37,9 @@ amd64_exc_generic: pushq %r14 pushq %r15 + pushq %fs + pushq %gs + movq $AMD64_STACK_CTX_CANARY, %rax pushq %rax @@ -50,6 +53,9 @@ amd64_exc_generic: 1: addq $8, %rsp + popq %gs + popq %fs + popq %r15 popq %r14 popq %r13 diff --git a/arch/amd64/hw/irq0.S b/arch/amd64/hw/irq0.S index 4349bd3..d2b6f20 100644 --- a/arch/amd64/hw/irq0.S +++ b/arch/amd64/hw/irq0.S @@ -7,13 +7,16 @@ amd64_irq0_early: cli + swapgs_if_needed pushq %rax irq_eoi_lapic 0 popq %rax + swapgs_if_needed iretq amd64_irq0: cli + swapgs_if_needed // Push caller-saved registers so it appears as if a thread just called yield() pushq %r11 @@ -38,6 +41,8 @@ amd64_irq0: popq %r9 popq %r10 popq %r11 + + swapgs_if_needed iretq amd64_irq2_counting: diff --git a/arch/amd64/mm/phys.c b/arch/amd64/mm/phys.c index e1de408..da0ecea 100644 --- a/arch/amd64/mm/phys.c +++ b/arch/amd64/mm/phys.c @@ -4,6 +4,7 @@ #include "sys/panic.h" #include "sys/debug.h" #include "sys/string.h" +#include "sys/spin.h" #include "sys/mm.h" extern int _kernel_end_phys; @@ -24,8 +25,12 @@ extern int _kernel_end_phys; static uint64_t amd64_phys_memory_track[PHYS_MAX_INDEX]; static uint64_t amd64_phys_last_index = 0; static uint64_t amd64_phys_ceiling = 0xFFFFFFFF; +static spin_t alloc_spin = 0; void amd64_phys_stat(struct amd64_phys_stat *st) { + uintptr_t irq; + spin_lock_irqsave(&alloc_spin, &irq); + st->pages_free = 0; st->pages_used = 0; st->limit = amd64_phys_ceiling; @@ -47,15 +52,20 @@ void amd64_phys_stat(struct amd64_phys_stat *st) { } } } + + spin_release_irqrestore(&alloc_spin, &irq); } // Allocate a single 4K page uintptr_t amd64_phys_alloc_page(void) { + uintptr_t irq; + spin_lock_irqsave(&alloc_spin, &irq); for (uint64_t i = amd64_phys_last_index; i < PHYS_MAX_INDEX; ++i) { for (uint64_t j = 0; j < 64; ++j) { if (!(amd64_phys_memory_track[i] & (1ULL << j))) { amd64_phys_memory_track[i] |= (1ULL << j); amd64_phys_last_index = i; + spin_release_irqrestore(&alloc_spin, &irq); return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12)); } } @@ -65,14 +75,20 @@ uintptr_t amd64_phys_alloc_page(void) { if (!(amd64_phys_memory_track[i] & (1ULL << j))) { amd64_phys_memory_track[i] |= (1ULL << j); amd64_phys_last_index = i; + spin_release_irqrestore(&alloc_spin, &irq); return PHYS_ALLOWED_BEGIN + ((i << 18) | (j << 12)); } } } + + spin_release_irqrestore(&alloc_spin, &irq); return MM_NADDR; } void amd64_phys_free(uintptr_t page) { + uintptr_t irq; + spin_lock_irqsave(&alloc_spin, &irq); + // Address is too low assert(page >= PHYS_ALLOWED_BEGIN, "The page is outside the physical range: %p\n", page); page -= PHYS_ALLOWED_BEGIN; @@ -86,6 +102,7 @@ void amd64_phys_free(uintptr_t page) { assert(amd64_phys_memory_track[index] & bit, "Double free error (phys): %p\n", page + PHYS_ALLOWED_BEGIN); amd64_phys_memory_track[index] &= ~bit; + spin_release_irqrestore(&alloc_spin, &irq); } // XXX: very slow impl. @@ -97,6 +114,8 @@ uintptr_t amd64_phys_alloc_contiguous(size_t count) { // The requested range is too large return MM_NADDR; } + uintptr_t irq; + spin_lock_irqsave(&alloc_spin, &irq); while (addr < (((uint64_t) (PHYS_MAX_INDEX - (count >> 6) - 1)) << 18)) { // Check if we can allocate these pages @@ -115,6 +134,7 @@ uintptr_t amd64_phys_alloc_contiguous(size_t count) { } kdebug("== %p\n", addr + PHYS_ALLOWED_BEGIN); + spin_release_irqrestore(&alloc_spin, &irq); return PHYS_ALLOWED_BEGIN + addr; // Found unavailable page in the range, continue searching @@ -122,6 +142,7 @@ no_match: continue; } + spin_release_irqrestore(&alloc_spin, &irq); return MM_NADDR; } diff --git a/arch/amd64/mm/pool.c b/arch/amd64/mm/pool.c index 3d5e48c..f420b94 100644 --- a/arch/amd64/mm/pool.c +++ b/arch/amd64/mm/pool.c @@ -4,6 +4,7 @@ #include "sys/debug.h" #include "sys/panic.h" #include "sys/string.h" +#include "sys/spin.h" static struct { uint64_t track[512]; @@ -12,7 +13,12 @@ static struct { size_t size; } amd64_mm_pool; +static spin_t pool_lock = 0; + void amd64_mm_pool_stat(struct amd64_pool_stat *st) { + uintptr_t irq; + spin_lock_irqsave(&pool_lock, &irq); + st->pages_free = 0; st->pages_used = 0; @@ -25,9 +31,13 @@ void amd64_mm_pool_stat(struct amd64_pool_stat *st) { } } } + + spin_release_irqrestore(&pool_lock, &irq); } uint64_t *amd64_mm_pool_alloc(void) { + uintptr_t irq; + spin_lock_irqsave(&pool_lock, &irq); uint64_t *r = NULL; for (size_t i = amd64_mm_pool.index_last; i < amd64_mm_pool.size >> 18; ++i) { @@ -37,6 +47,7 @@ uint64_t *amd64_mm_pool_alloc(void) { amd64_mm_pool.track[i] |= (1ULL << j); amd64_mm_pool.index_last = i; memset(r, 0, 4096); + spin_release_irqrestore(&pool_lock, &irq); return r; } } @@ -49,15 +60,19 @@ uint64_t *amd64_mm_pool_alloc(void) { amd64_mm_pool.track[i] |= (1ULL << j); amd64_mm_pool.index_last = i; memset(r, 0, 4096); + spin_release_irqrestore(&pool_lock, &irq); return r; } } } + spin_release_irqrestore(&pool_lock, &irq); return NULL; } void amd64_mm_pool_free(uint64_t *page) { + uintptr_t irq; + spin_lock_irqsave(&pool_lock, &irq); uintptr_t a = (uintptr_t) page; if (a < amd64_mm_pool.start || a >= (amd64_mm_pool.start + amd64_mm_pool.size)) { @@ -72,6 +87,7 @@ void amd64_mm_pool_free(uint64_t *page) { assert(amd64_mm_pool.track[i] & (1ULL << j), "Double free error (pool): %p\n", page); amd64_mm_pool.track[i] &= ~(1ULL << j); + spin_release_irqrestore(&pool_lock, &irq); } void amd64_mm_pool_init(uintptr_t begin, size_t size) { diff --git a/arch/amd64/sched_s.S b/arch/amd64/sched_s.S index a2f8fe6..face07a 100644 --- a/arch/amd64/sched_s.S +++ b/arch/amd64/sched_s.S @@ -14,6 +14,7 @@ context_enter: popq %r10 popq %r11 + swapgs_if_needed iretq .global context_exec_enter @@ -52,6 +53,7 @@ context_exec_enter: xorq %r14, %r14 xorq %r15, %r15 + swapgs_if_needed iretq .global context_switch_first @@ -151,4 +153,5 @@ context_sigenter: // Move argument movq %rdx, %rdi + swapgs iretq diff --git a/arch/amd64/smp/smp.c b/arch/amd64/smp/smp.c index 98fcec8..b3b10a7 100644 --- a/arch/amd64/smp/smp.c +++ b/arch/amd64/smp/smp.c @@ -160,6 +160,7 @@ void amd64_smp_bsp_configure(void) { cpus[0].processor_id = 0; cpus[0].apic_id = 0 /* TODO: apic_id may be different from 0 for BSP */; cpus[0].tss = amd64_tss_get(0); + cpus[0].thread = NULL; set_cpu((uintptr_t) &cpus[0]); } diff --git a/arch/amd64/sys/spin_s.S b/arch/amd64/sys/spin_s.S index 517a490..bcbd2fe 100644 --- a/arch/amd64/sys/spin_s.S +++ b/arch/amd64/sys/spin_s.S @@ -14,7 +14,7 @@ spin_lock_irqsave: spin_lock: // %rdi - spinlock - lock bts $1, (%rdi) + lock bts $0, (%rdi) jc 1f retq diff --git a/arch/amd64/syscall_s.S b/arch/amd64/syscall_s.S index 8e350e5..2643846 100644 --- a/arch/amd64/syscall_s.S +++ b/arch/amd64/syscall_s.S @@ -3,6 +3,7 @@ .section .text .global syscall_entry syscall_entry: + swapgs // %rcx - user rip // %rsp - user stack // %r11 - user rflags @@ -48,6 +49,7 @@ syscall_entry: movq %rdi, %rsp + swapgs sysretq _syscall_fork: @@ -98,4 +100,5 @@ _syscall_fork: movq %rdi, %rsp + swapgs sysretq diff --git a/include/arch/amd64/asm/asm_irq.h b/include/arch/amd64/asm/asm_irq.h index 49cfe25..7773d64 100644 --- a/include/arch/amd64/asm/asm_irq.h +++ b/include/arch/amd64/asm/asm_irq.h @@ -5,6 +5,7 @@ // TODO: use base + off instead of an absolute address #if defined(__ASM__) +#include "arch/amd64/asm/asm_cpu.h" .extern local_apic .extern irq_handle @@ -12,6 +13,7 @@ .global amd64_irq\n amd64_irq\n: cli + swapgs_if_needed pushq %r11 pushq %r10 @@ -36,6 +38,8 @@ amd64_irq\n: popq %r9 popq %r10 popq %r11 + + swapgs_if_needed iretq .endm diff --git a/include/arch/amd64/cpu.h b/include/arch/amd64/cpu.h index 59abe19..4a35f2f 100644 --- a/include/arch/amd64/cpu.h +++ b/include/arch/amd64/cpu.h @@ -1,6 +1,7 @@ #pragma once #include "arch/amd64/asm/asm_irq.h" #include "arch/amd64/hw/gdt.h" +#include "sys/assert.h" #include "sys/types.h" #define FXSAVE_REGION 512 @@ -8,20 +9,6 @@ #include "arch/amd64/asm/asm_cpu.h" #define thread_self get_cpu()->thread -#if defined(AMD64_SMP) -extern struct cpu cpus[AMD64_MAX_SMP]; - -static inline struct cpu *get_cpu(void) { - struct cpu *cpu; - asm volatile ("movq %%gs:0, %0":"=r"(cpu)); - return cpu; -} -#else -extern struct cpu __amd64_cpu; - -#define get_cpu() ((struct cpu *) &__amd64_cpu) -#endif - #define MSR_IA32_APIC_BASE 0x1B #define IA32_APIC_BASE_BSP 0x100 #define IA32_APIC_BASE_ENABLE 0x800 @@ -41,3 +28,18 @@ static inline void wrmsr(uint32_t addr, uint64_t v) { uint32_t low = (v & 0xFFFFFFFF), high = v >> 32; asm volatile ("wrmsr"::"c"(addr),"a"(low),"d"(high)); } + +#if defined(AMD64_SMP) +extern struct cpu cpus[AMD64_MAX_SMP]; + +static inline struct cpu *get_cpu(void) { + struct cpu *cpu; + _assert(rdmsr(MSR_IA32_KERNEL_GS_BASE)); + asm volatile ("movq %%gs:0, %0":"=r"(cpu)); + return cpu; +} +#else +extern struct cpu __amd64_cpu; + +#define get_cpu() ((struct cpu *) &__amd64_cpu) +#endif diff --git a/sys/sched.c b/sys/sched.c index 15ba456..9e46ad8 100644 --- a/sys/sched.c +++ b/sys/sched.c @@ -108,13 +108,16 @@ void sched_unqueue(struct thread *thr, enum thread_state new_state) { --queue_sizes[cpu_no]; thr->state = new_state; + spin_release_irqrestore(&sched_lock, &irq); thread_check_signal(thr, 0); + spin_lock_irqsave(&sched_lock, &irq); if (next == thr) { thr->next = NULL; thr->prev = NULL; queue_heads[cpu_no] = NULL; + spin_release_irqrestore(&sched_lock, &irq); cpu->thread = &threads_idle[cpu_no]; @@ -263,6 +266,8 @@ void sched_debug_cycle(uint64_t delta_ms) { } void yield(void) { + uintptr_t irq; + spin_lock_irqsave(&sched_lock, &irq); struct cpu *cpu = get_cpu(); struct thread *from = cpu->thread; struct thread *to; @@ -275,6 +280,8 @@ void yield(void) { to = &threads_idle[cpu->processor_id]; } + spin_release_irqrestore(&sched_lock, &irq); + // Check if instead of switching to a proper thread context we // have to use signal handling thread_check_signal(from, 0); diff --git a/sys/thread.c b/sys/thread.c index 2391a86..300861b 100644 --- a/sys/thread.c +++ b/sys/thread.c @@ -648,11 +648,21 @@ void sys_sigreturn(void) { void thread_signal(struct thread *thr, int signum) { if (thr->cpu == (int) get_cpu()->processor_id) { - _assert(thr == thread_self); - kdebug("Signal will be handled now\n"); - thread_sigenter(signum); + if (thr == thread_self) { + kdebug("Signal will be handled now\n"); + thread_sigenter(signum); + } else { + kdebug("Signal will be handled later\n"); + thread_signal_set(thr, signum); + + if (thr->state == THREAD_WAITING) { + timer_remove_sleep(thr); + } + + sched_queue(thr); + } } else if (thr->cpu >= 0) { - kdebug("Signal will be handled later (other CPU)\n"); + kdebug("Signal will be handled later (other cpu%d)\n", thr->cpu); thread_signal_set(thr, signum); if (thr->state == THREAD_WAITING) {