initial razzle
This commit is contained in:
commit
cd3d8871df
29 changed files with 1986 additions and 0 deletions
74
kernel/kernel.c
Normal file
74
kernel/kernel.c
Normal 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
24
kernel/memory.c
Normal 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
302
kernel/ps2.c
Normal 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
95
kernel/scheduler.c
Normal 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
9
kernel/spin_lock.c
Normal 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
64
kernel/syscall.c
Normal 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
96
kernel/test_processes.c
Normal 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
157
kernel/vga.c
Normal 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);
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue