Fix scheduler lock not being released when handling signals

This commit is contained in:
Mark
2020-02-04 23:37:57 +02:00
parent 3542b73f1a
commit 33ad8e3ee3
15 changed files with 128 additions and 36 deletions
+9 -9
View File
@@ -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
View File
@@ -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
View File
@@ -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");
}
}
+6
View File
@@ -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
+5
View File
@@ -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:
+21
View File
@@ -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;
}
+16
View File
@@ -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) {
+3
View File
@@ -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
+1
View File
@@ -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]);
}
+1 -1
View File
@@ -14,7 +14,7 @@ spin_lock_irqsave:
spin_lock:
// %rdi - spinlock
lock bts $1, (%rdi)
lock bts $0, (%rdi)
jc 1f
retq
+3
View File
@@ -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
+4
View File
@@ -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
View File
@@ -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
+7
View File
@@ -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
View File
@@ -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) {