initial razzle

This commit is contained in:
Nicholas Orlowsky 2024-10-03 02:55:54 -05:00
commit cd3d8871df
29 changed files with 1986 additions and 0 deletions

74
kernel/kernel.c Normal file
View file

@ -0,0 +1,74 @@
#include "./scheduler.c"
#include "./vga.c"
#include <stdint.h>
#include "./test_processes.c"
#ifdef ARCH_I386
#include "../arch/i386/init.c"
#endif
int kernel_main() {
lock = 0;
outb(0x3D4, 0x0A);
outb(0x3D5, 0x20);
clear_screen();
interrupt_disable();
arch_init();
init_process_table();
start_process("razzle", (char *) &test_razzle);
start_process("dazzle", (char *) &test_dazzle);
interrupt_enable();
for (;;) {
}
}
void fault_handler(struct regs *r) {
clear_screen();
printf("!!! Kernel Panic !!!\n");
switch (r->int_no) {
case 0: {
printf("Error: Divide by Zero\n");
break;
};
case 6: {
printf("Error: Illegal instruction\n");
break;
};
case 8: {
printf("Error: Double Fault (Ignoring)\n");
break;
};
case 13: {
printf("Error: General Protection Fault at\n");
break;
};
default: {
printf("Error: Unknown (no: %d)\n", r->int_no);
break;
};
}
printf("EIP: %x\n", r->eip);
printf("ESPv: %x\n", *(((unsigned int *)r->esp) + 2));
printf("ESP : %x\n", r->esp);
printf("\n");
process_debug();
for (;;) {
}
}

24
kernel/memory.c Normal file
View file

@ -0,0 +1,24 @@
#pragma once
#include <stdint.h>
void memset(char *ptr, char data, uint32_t len) {
for (uint32_t i = 0; i < len; i++) {
ptr[i] = data;
}
}
void memcpy(char *src, char *dst, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
dst[i] = src[i];
}
}
void strncpy(char *src, char *dst, uint32_t size) {
for (uint32_t i = 0; i < size; i++) {
dst[i] = src[i];
if (src[i] == '\0') {
return;
}
}
}

302
kernel/ps2.c Normal file
View file

@ -0,0 +1,302 @@
#pragma once
#include "./scheduler.c"
#include "./vga.c"
#include <stdint.h>
enum key_code_t {
backtick_tilde = 1,
one_bang = 2,
two_at = 3,
three_crunch = 4,
four_dollar = 5,
five_percent = 6,
six_carat = 7,
seven_amp = 8,
eight_star = 9,
nine_lparen = 10,
zero_rparen = 11,
minus_underscore = 12,
equal_plus = 13,
backspace = 14,
tab = 15,
lbracket_lbrace = 26,
rbracket_rbrace = 27,
backslash_pipe = 43,
caps_lock = 58,
semicolon_colon = 39,
quote_dquote = 40,
a = 30,
b = 48,
c = 46,
d = 32,
e = 18,
f = 33,
g = 34,
h = 35,
i = 23,
j = 36,
k = 37,
l = 38,
m = 50,
n = 49,
o = 24,
p = 25,
q = 16,
r = 19,
s = 31,
t = 20,
u = 22,
v = 47,
w = 17,
x = 45,
y = 21,
z = 44,
space = 57,
l_shift = 42,
r_shift = 54,
period_rarr = 52,
enter = 28,
comma_larr = 51,
slash_question = 53
};
struct key_event_t {
enum key_code_t key;
uint8_t is_down;
};
struct kb_state {
uint8_t l_shift;
uint8_t r_shift;
uint8_t l_ctrl;
uint8_t r_ctrl;
uint8_t caps;
};
static struct kb_state kstate;
uint8_t is_shifted() { return kstate.caps | kstate.r_shift | kstate.l_shift; }
char keycode_to_char(enum key_code_t key_code) {
switch (key_code) {
case a:
return is_shifted() ? 'A' : 'a';
break;
case b:
return is_shifted() ? 'B' : 'b';
break;
case c:
return is_shifted() ? 'C' : 'c';
break;
case d:
return is_shifted() ? 'D' : 'd';
break;
case e:
return is_shifted() ? 'E' : 'e';
break;
case f:
return is_shifted() ? 'F' : 'f';
break;
case g:
return is_shifted() ? 'G' : 'g';
break;
case h:
return is_shifted() ? 'H' : 'h';
break;
case i:
return is_shifted() ? 'I' : 'i';
break;
case j:
return is_shifted() ? 'J' : 'j';
break;
case k:
return is_shifted() ? 'K' : 'k';
break;
case l:
return is_shifted() ? 'L' : 'l';
break;
case m:
return is_shifted() ? 'M' : 'm';
break;
case n:
return is_shifted() ? 'N' : 'n';
break;
case o:
return is_shifted() ? 'O' : 'o';
break;
case p:
return is_shifted() ? 'P' : 'p';
break;
case q:
return is_shifted() ? 'Q' : 'q';
break;
case r:
return is_shifted() ? 'R' : 'r';
break;
case s:
return is_shifted() ? 'S' : 's';
break;
case t:
return is_shifted() ? 'T' : 't';
break;
case u:
return is_shifted() ? 'U' : 'u';
break;
case v:
return is_shifted() ? 'V' : 'v';
break;
case w:
return is_shifted() ? 'W' : 'w';
break;
case x:
return is_shifted() ? 'X' : 'x';
break;
case y:
return is_shifted() ? 'Y' : 'y';
break;
case z:
return is_shifted() ? 'Z' : 'z';
break;
case space:
return ' ';
break;
case comma_larr:
return is_shifted() ? '<' : ',';
break;
case period_rarr:
return is_shifted() ? '>' : '.';
break;
case enter:
return '\n';
break;
case backspace:
return '\b';
break;
case backtick_tilde:
return is_shifted() ? '~' : '`';
break;
case one_bang:
return is_shifted() ? '!' : '1';
break;
case two_at:
return is_shifted() ? '@' : '2';
break;
case three_crunch:
return is_shifted() ? '#' : '3';
break;
case four_dollar:
return is_shifted() ? '$' : '4';
break;
case five_percent:
return is_shifted() ? '%' : '5';
break;
case six_carat:
return is_shifted() ? '^' : '6';
break;
case seven_amp:
return is_shifted() ? '&' : '7';
break;
case eight_star:
return is_shifted() ? '*' : '8';
break;
case nine_lparen:
return is_shifted() ? '(' : '9';
break;
case zero_rparen:
return is_shifted() ? ')' : '0';
break;
case minus_underscore:
return is_shifted() ? '_' : '-';
break;
case equal_plus:
return is_shifted() ? '+' : '=';
break;
case tab:
return '\t';
break;
case lbracket_lbrace:
return is_shifted() ? '{' : '[';
break;
case rbracket_rbrace:
return is_shifted() ? '}' : ']';
break;
case semicolon_colon:
return is_shifted() ? ':' : ';';
break;
case quote_dquote:
return is_shifted() ? '"' : '\'';
break;
case backslash_pipe:
return is_shifted() ? '|' : '\\';
break;
case slash_question:
return is_shifted() ? '?' : '/';
break;
case caps_lock:
case r_shift:
case l_shift:
break;
// default:
// printf("%d", key_code);
// break;
}
return '\0';
}
struct ps2_waiter_t {
uint8_t alloc;
uint32_t pid;
};
struct ps2_waiter_t ps2_waiters[MAX_PROCESSES];
void init_ps2() {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
ps2_waiters[i].alloc = 0;
}
}
void handle_keypress(uint8_t char_code) {
struct key_event_t event;
if ((char_code & 0b11000000) == 0b10000000) {
event.is_down = 0;
event.key = char_code & 0b00111111;
} else {
event.is_down = 1;
event.key = char_code;
}
switch (event.key) {
case l_shift:
kstate.l_shift = event.is_down;
break;
case r_shift:
kstate.r_shift = event.is_down;
break;
case caps_lock:
if (event.is_down) {
kstate.caps = !kstate.caps;
}
break;
default: {
if (event.is_down) {
char c = keycode_to_char(event.key);
if (c != '\0') {
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(ps2_waiters[i].alloc) {
process_table[ps2_waiters[i].pid].registers.eax = c;
ps2_waiters[i].alloc = 0;
process_table[ps2_waiters[i].pid].state = TASKSTATE_ready;
}
}
}
}
break;
}
}
}

95
kernel/scheduler.c Normal file
View file

@ -0,0 +1,95 @@
#pragma once
#ifdef ARCH_I386
#include "../arch/i386/scheduler.c"
#endif
#include "./memory.c"
#include "./vga.c"
#include <stdint.h>
#define ADDRESS_SPACE_SIZE 1000000
#define MAX_PROCESSES 128
enum task_state_t { TASKSTATE_unused, TASKSTATE_ready, TASKSTATE_blocked };
struct task_struct {
enum task_state_t state;
struct regs registers;
unsigned int address_base;
char *allocd_addr;
char *process_name;
};
static struct task_struct process_table[MAX_PROCESSES];
static uint32_t current_pid;
void init_process_table() {
for (uint32_t i = 0; i < MAX_PROCESSES; i++) {
process_table[i].state = TASKSTATE_unused;
}
current_pid = 129;
}
uint32_t get_next_pid(uint32_t start, enum task_state_t state) {
uint32_t i = start % MAX_PROCESSES;
for (; process_table[i].state != state; i = (i + 1) % MAX_PROCESSES) {
}
return i;
}
char *balloc_pid(uint32_t size, uint32_t pid) {
char *addr = process_table[pid].allocd_addr;
process_table[pid].allocd_addr += size;
return addr;
}
char *balloc(uint32_t size) { return balloc_pid(size, current_pid); }
void start_process(char *name, char *entrypoint) {
uint32_t pid = get_next_pid(0, TASKSTATE_unused);
process_table[pid].address_base =
(unsigned int)(ADDRESS_SPACE_SIZE * (pid + 6));
// TODO: Copy code into process' address space
// memcpy(entrypoint, (char*) process_table[pid].address_base, 500000);
// entrypoint = (char*) process_table[pid].address_base;
process_table[pid].allocd_addr = (char *)process_table[pid].address_base;
process_table[pid].state = TASKSTATE_ready;
process_table[pid].process_name = balloc_pid(16, pid);
strncpy(name, process_table[pid].process_name, 16);
initialize_registers(&process_table[pid].registers, entrypoint,
process_table[pid].address_base, ADDRESS_SPACE_SIZE);
}
void single_process_debug(uint32_t pid) {
struct task_struct proc = process_table[pid];
printf_nolock("pid: %u (%s)\n", pid, proc.process_name);
printf_nolock("eip: %x esp: %x (%d)\n", proc.registers.eip,
proc.registers.useresp, proc.registers.useresp);
printf_nolock("ass: %d ase: %d\n\n", proc.address_base, proc.registers.ebp);
}
void process_debug() {
printf_nolock("RAZZLE Debugger: Process Table | current pid: %u\n",
current_pid);
for (int i = 0; i < MAX_PROCESSES; i++) {
if (process_table[i].state != TASKSTATE_unused)
single_process_debug(i);
}
}
void schedule(struct regs *r) {
if (current_pid < MAX_PROCESSES) {
store_registers(r, &process_table[current_pid].registers);
}
current_pid =
get_next_pid((current_pid + 1) % MAX_PROCESSES, TASKSTATE_ready);
switch_context(r, &process_table[current_pid].registers);
}

9
kernel/spin_lock.c Normal file
View file

@ -0,0 +1,9 @@
#pragma once
#ifdef ARCH_I386
#include "../arch/i386/asm.c"
#endif
void sl_acquire(uint32_t *lock) { __sl_acquire(lock); }
void sl_release(uint32_t *lock) { __sl_release(lock); }

64
kernel/syscall.c Normal file
View file

@ -0,0 +1,64 @@
#pragma once
#include "scheduler.c"
#include "ps2.c"
#ifdef ARCH_I386
#include "../arch/i386/syscall.c"
#endif
enum syscall_type_d { SYSCALL_yield, SYSCALL_getc, SYSCALL_exit };
void yield() { INVOKE_SYSCALL(SYSCALL_yield); }
char getc() {
INVOKE_SYSCALL(SYSCALL_getc);
char result;
__asm__ volatile (
"movb %%al, %0"
: "=r"(result)
);
return result;
}
void __syscall_yield(struct regs *r) {
// for now, just reschedule
// TODO: reset PIT timer so
// next process doesn't get an
// unreasonably small quantum
schedule(r);
}
void syscall(struct regs *r) {
int syscall_no = r->eax;
switch (syscall_no) {
case SYSCALL_yield: {
__syscall_yield(r);
break;
};
case SYSCALL_getc: {
process_table[current_pid].state = TASKSTATE_blocked;
for(uint32_t i = 0; i < MAX_PROCESSES; i++) {
if(!ps2_waiters[i].alloc) {
ps2_waiters[i].alloc = 1;
ps2_waiters[i].pid = current_pid;
break;
}
}
__syscall_yield(r);
break;
};
case SYSCALL_exit: {
process_table[current_pid].state = TASKSTATE_unused;
__syscall_yield(r);
break;
};
}
}

96
kernel/test_processes.c Normal file
View file

@ -0,0 +1,96 @@
/*
* Since RAZZLE doesn't have disk support yet, all code for test processes are
* included in this file.
*/
#pragma once
#include "./scheduler.c"
#include "./spin_lock.c"
#include "./syscall.c"
#include "./vga.c"
uint32_t lock2 = 0;
void test_razzle() {
for (uint32_t i = 0;; i++) {
sl_acquire(&lock2);
row = 1;
col = 0;
printf("%s (pid %d): %u \n", process_table[current_pid].process_name,
current_pid, i);
sl_release(&lock2);
yield();
}
}
void cpuid() {
char model[13];
uint32_t res[3];
__asm__ volatile ("mov $0, %%eax; cpuid; mov %%ebx, %0; mov %%edx, %1; mov %%ecx, %2;" : "=r" (res[0]), "=r" (res[1]), "=r" (res[2]) ::"ebx", "ecx", "edx");
for(uint32_t i = 0; i < 3; i++) {
model[(i*4) + 0] = (res[i] >> 0) & 0xFF;
model[(i*4) + 1] = (res[i] >> 8) & 0xFF;
model[(i*4) + 2] = (res[i] >> 16) & 0xFF;
model[(i*4) + 3] = (res[i] >> 24) & 0xFF;
}
model[12] = '\0';
printf("%s", model);
}
void test_dazzle() {
char prompt[] = "you@razzle ~$";
char command[2048];
uint32_t cr = 2;
printf("%s", prompt);
for (uint32_t i = sizeof(prompt);;) {
char c = getc();
sl_acquire(&lock2);
row = cr;
col = i;
switch(c) {
case '\b':
if (i == 0) {
i = 79;
cr--;
} else {
i--;
}
col = i;
row = cr;
printf(" ");
break;
case '\n':
i = 0;
cr++;
row++;
col = 0;
cpuid();
cr++;
col = i;
row = cr;
printf("%s", prompt);
i = sizeof(prompt);
break;
default:
printf("%c", c);
command[((cr-2)*80) + i] = c;
i++;
break;
}
if (i >= 80) {
i = 0;
cr++;
}
sl_release(&lock2);
yield();
}
}

157
kernel/vga.c Normal file
View file

@ -0,0 +1,157 @@
#pragma once
#include "./spin_lock.c"
#include <stdarg.h>
#include <stdint.h>
#define WIDTH 80
#define HEIGHT 25
static uint8_t col = 0;
static uint8_t row = 0;
static uint8_t color_code = 10;
static char *vram = (char *)0xb8000;
void clear_screen() {
for (int i = 0; i < HEIGHT - 1; i++) {
for (int j = 0; j < WIDTH; j++) {
vram[(i * WIDTH * 2) + (j * 2)] = 0;
// vram[(i * WIDTH * 2) + (j*2 + 1)] = 0;
}
}
row = 0;
col = 0;
}
void putc(char c) {
if (col == WIDTH) {
row = (row + 1) % HEIGHT;
col = 0;
}
if (c == '\n') {
for (int i = col; i < WIDTH; i++) {
vram[(row * WIDTH * 2) + (i * 2)] = ' ';
vram[(row * WIDTH * 2) + (i * 2 + 1)] = color_code;
}
row = (row + 1) % HEIGHT;
col = 0;
return;
}
if (c == '\b') {
col--;
vram[(row * WIDTH * 2) + (col * 2)] = ' ';
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
return;
}
vram[(row * WIDTH * 2) + (col * 2)] = c;
vram[(row * WIDTH * 2) + (col * 2 + 1)] = color_code;
col++;
}
void print_uint(unsigned int x, uint8_t base) {
if (x == 0) {
if (base)
putc('0');
return;
}
print_uint(x / 10, 0);
putc('0' + (x % 10));
}
void print_int(int x, uint8_t base) {
if (x == 0) {
if (base)
putc('0');
return;
}
if (x < 0) {
putc('-');
print_int(-1 * (x / 10), 0);
putc('0' + (x % 10));
} else {
print_int(x / 10, 0);
putc('0' + (x % 10));
}
}
void print_hex(int x) {
putc('0');
putc('x');
do {
unsigned int digit = (x & 0xF0000000) >> 28;
putc((digit < 10) ? (digit + '0') : (digit - 10 + 'A'));
x <<= 4;
} while (x != 0);
}
void print_string(char *s) {
for (uint32_t i = 0; s[i] != '\0'; i++) {
putc(s[i]);
}
}
uint32_t lock;
void printf_base(char *str, va_list list) {
for (uint32_t i = 0; str[i] != '\0'; i++) {
if (str[i] == '%') {
switch (str[i + 1]) {
case '\0':
return;
case '%': {
putc('%');
break;
}
case 'c': {
putc(va_arg(list, int));
break;
}
case 'd': {
print_int(va_arg(list, int), 1);
break;
}
case 'x': {
print_hex(va_arg(list, int));
break;
}
case 'u': {
print_uint(va_arg(list, unsigned int), 1);
break;
}
case 's': {
print_string(va_arg(list, char *));
break;
}
}
i++;
} else {
putc(str[i]);
}
}
}
void printf_nolock(char *str, ...) {
va_list list;
va_start(list, str);
printf_base(str, list);
}
void printf(char *str, ...) {
va_list list;
va_start(list, str);
sl_acquire(&lock);
printf_base(str, list);
sl_release(&lock);
}