Skip to content
This repository has been archived by the owner on May 31, 2021. It is now read-only.

Commit

Permalink
Add more locks, cleanup irq handlers a bit
Browse files Browse the repository at this point in the history
  • Loading branch information
klange committed May 22, 2021
1 parent 16f857f commit fb64157
Show file tree
Hide file tree
Showing 7 changed files with 82 additions and 54 deletions.
2 changes: 2 additions & 0 deletions base/usr/include/kernel/misc.h
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
5 changes: 4 additions & 1 deletion base/usr/include/kernel/process.h
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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;
Expand Down Expand Up @@ -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];
Expand All @@ -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);
Expand Down
2 changes: 2 additions & 0 deletions kernel/arch/x86_64/acpi.c
Original file line number Diff line number Diff line change
Expand Up @@ -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];

Expand Down
5 changes: 2 additions & 3 deletions kernel/arch/x86_64/gdt.c
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

#include <kernel/printf.h>
#include <kernel/string.h>
#include <kernel/process.h>

/**
* @brief 64-bit TSS
Expand Down Expand Up @@ -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) {
Expand Down
73 changes: 38 additions & 35 deletions kernel/arch/x86_64/idt.c
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand All @@ -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 *);
Expand Down Expand Up @@ -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 */
Expand All @@ -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 */ {
Expand All @@ -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 */ {
Expand All @@ -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)];
Expand All @@ -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;
}
}
Expand Down
43 changes: 29 additions & 14 deletions kernel/sys/process.c
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@
#include <kernel/signal.h>
#include <kernel/time.h>
#include <kernel/misc.h>
#include <kernel/syscall.h>
#include <sys/wait.h>
#include <sys/signal_defs.h>

Expand Down Expand Up @@ -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("/");
Expand Down Expand Up @@ -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 *));
Expand All @@ -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);
Expand Down Expand Up @@ -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);
}
}
Expand All @@ -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);
}

Expand All @@ -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) {
Expand All @@ -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;
Expand Down Expand Up @@ -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));
}

/**
Expand All @@ -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);
Expand Down Expand Up @@ -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 {
Expand Down Expand Up @@ -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);

Expand Down Expand Up @@ -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;
Expand Down Expand Up @@ -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;
Expand Down
6 changes: 5 additions & 1 deletion kernel/vfs/pipe.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
Expand Down

0 comments on commit fb64157

Please sign in to comment.