Fix scheduler lock not being released when handling signals
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
+3
-7
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+19
-1
@@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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:
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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) {
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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]);
|
||||
}
|
||||
|
||||
|
||||
@@ -14,7 +14,7 @@ spin_lock_irqsave:
|
||||
|
||||
spin_lock:
|
||||
// %rdi - spinlock
|
||||
lock bts $1, (%rdi)
|
||||
lock bts $0, (%rdi)
|
||||
jc 1f
|
||||
retq
|
||||
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
+16
-14
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
+14
-4
@@ -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) {
|
||||
|
||||
Reference in New Issue
Block a user