From fb64157ff2ec19040e28353da2e926b706f7bade Mon Sep 17 00:00:00 2001 From: "K. Lange" Date: Sat, 22 May 2021 23:55:48 +0900 Subject: [PATCH] Add more locks, cleanup irq handlers a bit --- base/usr/include/kernel/misc.h | 2 + base/usr/include/kernel/process.h | 5 ++- kernel/arch/x86_64/acpi.c | 2 + kernel/arch/x86_64/gdt.c | 5 +-- kernel/arch/x86_64/idt.c | 73 ++++++++++++++++--------------- kernel/sys/process.c | 43 ++++++++++++------ kernel/vfs/pipe.c | 6 ++- 7 files changed, 82 insertions(+), 54 deletions(-) diff --git a/base/usr/include/kernel/misc.h b/base/usr/include/kernel/misc.h index 370882f..fb66210 100644 --- a/base/usr/include/kernel/misc.h +++ b/base/usr/include/kernel/misc.h @@ -7,6 +7,8 @@ const char * arch_get_cmdline(void); const char * arch_get_loader(void); void arch_pause(void); + +__attribute__((noreturn)) void arch_fatal(void); void arch_set_tls_base(uintptr_t tlsbase); diff --git a/base/usr/include/kernel/process.h b/base/usr/include/kernel/process.h index 581e59a..0c035a1 100644 --- a/base/usr/include/kernel/process.h +++ b/base/usr/include/kernel/process.h @@ -57,6 +57,7 @@ typedef struct file_descriptors { size_t length; size_t capacity; size_t refs; + spin_lock_t lock; } fd_table_t; #define PROC_FLAG_IS_TASKLET 0x01 @@ -73,6 +74,7 @@ typedef struct process { pid_t session; /* tty session */ int status; /* status code */ unsigned int flags; /* finished, started, running, isTasklet */ + int owner; uid_t user; uid_t real_user; @@ -146,6 +148,7 @@ struct ProcessorLocal { process_t * kernel_idle_task; union PML * current_pml; volatile int sync_depth; + int cpu_id; }; extern struct ProcessorLocal processor_local_data[32]; @@ -164,7 +167,7 @@ extern process_t * process_from_pid(pid_t pid); extern void process_delete(process_t * proc); extern void make_process_ready(volatile process_t * proc); -extern process_t * next_ready_process(void); +extern volatile process_t * next_ready_process(void); extern int wakeup_queue(list_t * queue); extern int wakeup_queue_interrupted(list_t * queue); extern int sleep_on(list_t * queue); diff --git a/kernel/arch/x86_64/acpi.c b/kernel/arch/x86_64/acpi.c index 6b0421c..4570729 100644 --- a/kernel/arch/x86_64/acpi.c +++ b/kernel/arch/x86_64/acpi.c @@ -100,6 +100,8 @@ void ap_main(void) { fpu_initialize(); pat_initialize(); + this_core->cpu_id = ebx >> 24; + /* Set our pml pointers */ this_core->current_pml = &init_page_region[0]; diff --git a/kernel/arch/x86_64/gdt.c b/kernel/arch/x86_64/gdt.c index 29da1a5..951998c 100644 --- a/kernel/arch/x86_64/gdt.c +++ b/kernel/arch/x86_64/gdt.c @@ -6,6 +6,7 @@ #include #include +#include /** * @brief 64-bit TSS @@ -98,9 +99,7 @@ void gdt_copy_to_trampoline(int ap, char * trampoline) { } void arch_set_kernel_stack(uintptr_t stack) { - uint32_t ebx; - asm volatile ("cpuid" : "=b"(ebx) : "a"(0x1)); - gdt[ebx >> 24].tss.rsp[0] = stack; + gdt[this_core->cpu_id].tss.rsp[0] = stack; } void arch_set_tls_base(uintptr_t tlsbase) { diff --git a/kernel/arch/x86_64/idt.c b/kernel/arch/x86_64/idt.c index 810841f..efda2cb 100644 --- a/kernel/arch/x86_64/idt.c +++ b/kernel/arch/x86_64/idt.c @@ -100,7 +100,10 @@ void idt_ap_install(void) { ); } +static spin_lock_t fault_lock = {0}; +static spin_lock_t dump_lock = {0}; static void dump_regs(struct regs * r) { + spin_lock(dump_lock); printf( "Registers at interrupt:\n" " $rip=0x%016lx\n" @@ -116,6 +119,7 @@ static void dump_regs(struct regs * r) { r->r12, r->r13, r->r14, r->r15, r->cs, r->ss, r->rflags, r->int_no, r->err_code ); + spin_unlock(dump_lock); } extern void syscall_handler(struct regs *); @@ -182,28 +186,16 @@ void irq_uninstall_handler(size_t irq) { } struct regs * isr_handler(struct regs * r) { - uintptr_t ebx; - asm volatile ("cpuid" : "=b"(ebx) : "a"(0x1)); - - uint32_t base_high, base_low; - asm volatile ("rdmsr" : "=d"(base_high), "=a"(base_low) : "c"(0xc0000101)); - - if (base_high || ((uintptr_t)base_low < (uintptr_t)&processor_local_data[0]) || ((uintptr_t)base_low > (uintptr_t)&processor_local_data[33])) { - printf("Bad GS segment in kernel.\n"); - dump_regs(r); - while (1) {}; - } - this_core->current_process->interrupt_registers = r; switch (r->int_no) { case 14: /* Page fault */ { uintptr_t faulting_address; asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); - if (!this_core->current_process) { - printf("Page fault in early startup at %#zx (%zd)\n", faulting_address, ebx >> 24); + if (!this_core->current_process || r->cs == 0x08) { + printf("Page fault in kernel (cpu=%d) at %#zx\n", this_core->cpu_id, faulting_address); dump_regs(r); - break; + arch_fatal(); } if (faulting_address == 0xFFFFB00F) { /* Thread exit */ @@ -214,26 +206,32 @@ struct regs * isr_handler(struct regs * r) { return_from_signal_handler(); break; } - printf("Page fault in pid=%d (%s; cpu=%zd) at %#zx\n", (int)this_core->current_process->id, this_core->current_process->name, ebx >> 24, faulting_address); +#ifdef DEBUG_FAULTS + spin_lock(fault_lock); + printf("Page fault in pid=%d (%s; cpu=%d) at %#zx\n", (int)this_core->current_process->id, this_core->current_process->name, this_core->cpu_id, faulting_address); dump_regs(r); - if (this_core->current_process->flags & PROC_FLAG_IS_TASKLET) { - printf("Segmentation fault in kernel worker thread, halting.\n"); - arch_fatal(); - } - if (r->cs == 0x08) { - printf("Fault in kernel, halting.\n"); - arch_fatal(); - } + spin_unlock(fault_lock); + arch_fatal(); +#else send_signal(this_core->current_process->id, SIGSEGV, 1); +#endif break; } case 13: /* GPF */ { - if (!this_core->current_process) { - printf("GPF in early startup\n"); + if (!this_core->current_process || r->cs == 0x08) { + printf("GPF in kernel (cpu=%d)\n", this_core->cpu_id); dump_regs(r); - break; + arch_fatal(); } +#ifdef DEBUG_FAULTS + spin_lock(fault_lock); + printf("GPF in userspace on CPU %d\n", this_core->cpu_id); + dump_regs(r); + spin_unlock(fault_lock); + arch_fatal(); +#else send_signal(this_core->current_process->id, SIGSEGV, 1); +#endif break; } case 8: /* Double fault */ { @@ -242,6 +240,7 @@ struct regs * isr_handler(struct regs * r) { asm volatile("mov %%cr2, %0" : "=r"(faulting_address)); printf("cr2: 0x%016lx\n", faulting_address); dump_regs(r); + arch_fatal(); break; } case 127: /* syscall */ { @@ -255,12 +254,20 @@ struct regs * isr_handler(struct regs * r) { } default: { if (r->int_no < 32) { - if (!this_core->current_process) { - printf("Unhandled exception: %s\n", exception_messages[r->int_no]); - break; + if (!this_core->current_process || r->cs == 0x08) { + printf("Unhandled %s in kernel (cpu=%d)\n", exception_messages[r->int_no], this_core->cpu_id); + dump_regs(r); + arch_fatal(); } - printf("Killing %d from unhandled %s\n", this_core->current_process->id, exception_messages[r->int_no]); +#ifdef DEBUG_FAULTS + spin_lock(fault_lock); + printf("Unhandled %s in userspace (cpu=%d)\n", exception_messages[r->int_no], this_core->cpu_id); + dump_regs(r); + spin_unlock(fault_lock); + arch_fatal(); +#else send_signal(this_core->current_process->id, SIGILL, 1); +#endif } else { for (size_t i = 0; i < IRQ_CHAIN_DEPTH; i++) { irq_handler_chain_t handler = irq_routines[i * IRQ_CHAIN_SIZE + (r->int_no - 32)]; @@ -270,10 +277,6 @@ struct regs * isr_handler(struct regs * r) { } } irq_ack(r->int_no - 32); - #if 0 - printf("Unhandled interrupt: %lu\n", r->int_no - 32); - dump_regs(r); - #endif break; } } diff --git a/kernel/sys/process.c b/kernel/sys/process.c index 1cf4447..3ad4600 100644 --- a/kernel/sys/process.c +++ b/kernel/sys/process.c @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -367,6 +368,7 @@ process_t * spawn_init(void) { init->fds->entries = malloc(init->fds->capacity * sizeof(fs_node_t *)); init->fds->modes = malloc(init->fds->capacity * sizeof(int)); init->fds->offsets = malloc(init->fds->capacity * sizeof(uint64_t)); + spin_init(init->fds->lock); init->wd_node = clone_fs(fs_root); init->wd_name = strdup("/"); @@ -429,11 +431,15 @@ process_t * spawn_process(volatile process_t * parent, int flags) { proc->image.shm_heap = 0x200000000; /* FIXME this should be a macro def */ if (flags & PROC_REUSE_FDS) { + spin_lock(parent->fds->lock); proc->fds = parent->fds; - proc->fds->refs++; /* FIXME lock? */ + proc->fds->refs++; + spin_unlock(parent->fds->lock); } else { proc->fds = malloc(sizeof(fd_table_t)); + spin_init(proc->fds->lock); proc->fds->refs = 1; + spin_lock(parent->fds->lock); proc->fds->length = parent->fds->length; proc->fds->capacity = parent->fds->capacity; proc->fds->entries = malloc(proc->fds->capacity * sizeof(fs_node_t *)); @@ -444,6 +450,7 @@ process_t * spawn_process(volatile process_t * parent, int flags) { proc->fds->modes[i] = parent->fds->modes[i]; proc->fds->offsets[i] = parent->fds->offsets[i]; } + spin_unlock(parent->fds->lock); } proc->wd_node = clone_fs(parent->wd_node); @@ -522,7 +529,7 @@ void make_process_ready(volatile process_t * proc) { } } else { /* This was blocked on a semaphore we can interrupt. */ - proc->flags |= PROC_FLAG_SLEEP_INT; + __sync_or_and_fetch(&proc->flags, PROC_FLAG_SLEEP_INT); list_delete((list_t*)proc->sleep_node.owner, (node_t*)&proc->sleep_node); } } @@ -538,9 +545,7 @@ void make_process_ready(volatile process_t * proc) { } spin_lock(process_queue_lock); - asm volatile ("":::"memory"); list_append(process_queue, (node_t*)&proc->sched_node); - asm volatile ("":::"memory"); spin_unlock(process_queue_lock); } @@ -552,7 +557,7 @@ void make_process_ready(volatile process_t * proc) { * * TODO This needs more locking for SMP... */ -process_t * next_ready_process(void) { +volatile process_t * next_ready_process(void) { spin_lock(process_queue_lock); if (!process_queue->head) { @@ -561,8 +566,19 @@ process_t * next_ready_process(void) { } node_t * np = list_dequeue(process_queue); - process_t * next = np->value; + if ((uintptr_t)np < 0xFFFFff0000000000UL || (uintptr_t)np > 0xFFFFff0000f00000UL) { + printf("Suspicious pointer in queue: %#zx\n", (uintptr_t)np); + arch_fatal(); + } + volatile process_t * next = np->value; + + if (next->flags & PROC_FLAG_RUNNING) { + printf("Process %d reports already running but was pulled from queue (might be owned by %d, I am %d; I'll wait a bit.)\n", next->id, next->owner, this_core->cpu_id); + while (next->flags & PROC_FLAG_RUNNING); + } + __sync_or_and_fetch(&next->flags, PROC_FLAG_RUNNING); + next->owner = this_core->cpu_id; spin_unlock(process_queue_lock); return next; @@ -650,7 +666,7 @@ int sleep_on(list_t * queue) { * @brief Indicates whether a process is ready to be run but not currently running. */ int process_is_ready(process_t * proc) { - return (proc->sched_node.owner != NULL); + return (proc->sched_node.owner != NULL && !(proc->flags & PROC_FLAG_RUNNING)); } /** @@ -674,12 +690,10 @@ void wakeup_sleepers(unsigned long seconds, unsigned long subseconds) { process_t * process = proc->process; process->sleep_node.owner = NULL; process->timed_sleep_node = NULL; - if (!process_is_ready(process) && !(process->flags & PROC_FLAG_RUNNING)) { - spin_unlock(sleep_lock); + if (!process_is_ready(process)) { spin_lock(wait_lock_tmp); make_process_ready(process); spin_unlock(wait_lock_tmp); - spin_lock(sleep_lock); } } free(proc); @@ -880,6 +894,7 @@ int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { n = nodes; + spin_lock(process->sched_lock); process->node_waits = list_create("process fswaiters",process); if (*n) { do { @@ -916,6 +931,8 @@ int process_wait_nodes(process_t * process,fs_node_t * nodes[], int timeout) { } process->awoken_index = -1; + spin_unlock(process->sched_lock); + /* Wait. */ switch_task(0); @@ -1049,9 +1066,7 @@ pid_t fork(void) { sp = new_proc->image.stack; bp = sp; - /* This is all very arch specific... */ - /* arch_setup_fork_return? */ - r.rax = 0; /* make fork return 0 */ + arch_syscall_return(&r, 0); PUSH(sp, struct regs, r); new_proc->syscall_registers = (void*)sp; new_proc->thread.context.sp = sp; @@ -1105,7 +1120,7 @@ pid_t clone(uintptr_t new_stack, uintptr_t thread_func, uintptr_t arg) { process_t * spawn_worker_thread(void (*entrypoint)(void * argp), const char * name, void * argp) { process_t * proc = calloc(1,sizeof(process_t)); - proc->flags = PROC_FLAG_IS_TASKLET | PROC_FLAG_STARTED | PROC_FLAG_RUNNING; + proc->flags = PROC_FLAG_IS_TASKLET | PROC_FLAG_STARTED; proc->id = get_next_pid(); proc->group = proc->id; diff --git a/kernel/vfs/pipe.c b/kernel/vfs/pipe.c index c3dd1a5..9fee9cb 100644 --- a/kernel/vfs/pipe.c +++ b/kernel/vfs/pipe.c @@ -98,8 +98,12 @@ static void pipe_alert_waiters(pipe_device_t * pipe) { while (pipe->alert_waiters->head) { node_t * node = list_dequeue(pipe->alert_waiters); process_t * p = node->value; - process_alert_node(p, pipe); free(node); + spin_unlock(pipe->alert_lock); + + process_alert_node(p, pipe); + + spin_lock(pipe->alert_lock); } spin_unlock(pipe->alert_lock); }