From c63f340d90800895f007de64b7d2d14624263331 Mon Sep 17 00:00:00 2001 From: nthnluu Date: Sun, 28 Jan 2024 21:20:27 -0500 Subject: Created student weenix repository --- kernel/util/debug.c | 237 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100644 kernel/util/debug.c (limited to 'kernel/util/debug.c') diff --git a/kernel/util/debug.c b/kernel/util/debug.c new file mode 100644 index 0000000..47c8345 --- /dev/null +++ b/kernel/util/debug.c @@ -0,0 +1,237 @@ +#include "main/apic.h" +#include "main/io.h" +#include "util/printf.h" +#include "util/string.h" + +/* + * Debug message behavior. + * + * To disable a dbg mode add ',-name' to this variable. To enable one add + * ',name'. For example to have everything except 'mm' and 'pagealloc' you would + * set DBG to 'all,-mm,-pagealloc'. To have only 'test', 'testpass', 'testfail' + * you would set DBG to '-all,test,testpass,testfail'. + * + * We generally recommend that you leave this set to 'all' with some of the + * less useful message types disabled. To see all available message types, and + * to potentially add to them see 'kernel/include/util/debug.h' + * + * Note that due to the way this is interpreted either 'all' or '-all' should + * always be the first thing in this variable. Note that this setting can be + * changed at runtime by modifying the dbg_modes global variable. + */ +#define INIT_DBG_MODES "-all" + +/* Below is a truly terrible poll-driven serial driver that we use for debugging + * purposes - it outputs to COM1, but + * this can be easily changed. It does not use interrupts, and cannot read input + * */ +/* This port is COM1 */ +#define PORT 0x3f8 +/* Corresponding interrupt vector */ +#define PORT_INTR 0x0d + +uint64_t dbg_modes; + +typedef struct dbg_mode +{ + const char *d_name; + uint64_t d_mode; + const char *d_color; +} dbg_mode_t; + +void dbg_init() +{ + outb(PORT + 3, 0x80); /* Enable DLAB (set baud rate divisor) */ + outb(PORT + 0, 0x03); /* Set divisor to 3 (lo byte) 38400 baud */ + outb(PORT + 1, 0x00); /* (hi byte) */ + outb(PORT + 3, 0x03); /* 8 bits, no parity, one stop bit */ + outb(PORT + 2, 0xC7); /* Enable FIFO, clear them, with 14-byte threshold */ + + dbg_add_modes(INIT_DBG_MODES); +} + +static dbg_mode_t dbg_tab[] = {DBG_TAB}; + +const char *dbg_color(uint64_t d_mode) +{ + dbg_mode_t *mode; + for (mode = dbg_tab; mode->d_mode != 0UL; mode++) + { + if (mode->d_mode & d_mode) + { + return mode->d_color; + } + } + /* If we get here, something went seriously wrong */ + panic("Unknown debug mode 0x%lx\n", d_mode); +} + +static void dbg_puts(char *c) +{ + while (*c != '\0') + { + /* Wait until the port is free */ + while (!(inb(PORT + 5) & 0x20)) + ; + outb(PORT, (uint8_t)*c++); + } +} + +#define BUFFER_SIZE 1024 + +void dbg_print(char *fmt, ...) +{ + va_list args; + char buf[BUFFER_SIZE]; + size_t count; + + va_start(args, fmt); + count = (size_t)vsnprintf(buf, sizeof(buf), fmt, args); + va_end(args); + + if (count >= sizeof(buf)) + { + dbg_puts( + "WARNING: The following message has been truncated due to " + "buffer size limitations.\n"); + } + dbg_puts(buf); +} + +void dbg_printinfo(dbg_infofunc_t func, const void *data) +{ + char buf[BUFFER_SIZE]; + func(data, buf, BUFFER_SIZE); + dbg_puts(buf); +} + +#ifndef NDEBUG +/** + * searches for name in the list of known + * debugging modes specified above and, if it + * finds name, adds the corresponding + * debugging mode to a list + */ +void dbg_add_mode(const char *name) +{ + long cancel; + dbg_mode_t *mode; + + if (*name == '-') + { + cancel = 1; + name++; + } + else + { + cancel = 0; + } + + for (mode = dbg_tab; mode->d_name != NULL; mode++) + { + if (strcmp(name, mode->d_name) == 0) + { + break; + } + } + if (mode->d_name == NULL) + { + dbg_print("Warning: Unknown debug option: \"%s\"\n", name); + return; + } + + if (cancel) + { + dbg_modes &= ~mode->d_mode; + } + else + { + dbg_modes |= mode->d_mode; + } +} + +/** + * Cycles through each comma-delimited debugging option and + * adds it to the debugging modes by calling dbg_add_mode + */ +void dbg_add_modes(const char *modes) +{ + char env[256]; + char *name; + + strncpy(env, modes, sizeof(env)); + /* Maybe it would be good if we did this without strtok, but I'm too lazy */ + for (name = strtok(env, ","); name; name = strtok(NULL, ",")) + { + dbg_add_mode(name); + } +} + +size_t dbg_modes_info(const void *data, char *buf, size_t size) +{ + KASSERT(NULL == data); + KASSERT(0 < size); + + size_t osize = size; + + dbg_mode_t *mode; + for (mode = dbg_tab; mode->d_name != NULL; ++mode) + { + if (dbg_modes & mode->d_mode && mode->d_mode != DBG_ALL) + { + int len; + if ((len = snprintf(buf, size, "%s,", mode->d_name)) >= (int)size) + { + break; + } + else + { + buf += len; + size -= len; + } + } + } + + if (size == osize) + { + buf[0] = '\0'; + return 0; + } + else + { + /* remove trailing comma */ + buf[-1] = '\0'; + return osize - size + 1; + } +} +#endif + +/* This is meant as a good point to automatically set a breakpoint which will + * stop just after a panic has occured and printed its message. */ +noreturn static void dbg_panic_halt() +{ + __asm__ volatile("cli; hlt"); + __builtin_unreachable(); +} + +#define PANIC_BUFSIZE 2048 + +noreturn void dbg_panic(const char *file, int line, const char *func, + const char *fmt, ...) +{ + char buf[PANIC_BUFSIZE]; + va_list args; + va_start(args, fmt); + + DEBUG_ENTER + dbg_print("C%ld P%ld panic in %s:%u %s(): ", curcore.kc_id, + curproc ? curproc->p_pid : -1L, file, line, func); + vsnprintf(buf, PANIC_BUFSIZE, fmt, args); + dbg_print("%s", buf); + dbg_print("\nC%ld Halting.\n\n", apic_current_id()); + DEBUG_EXIT + + va_end(args); + + dbg_panic_halt(); +} -- cgit v1.2.3-70-g09d2