QTechOS/kernel/kernel.cpp
Quantum b35d58df1f
Build System: More better
Split code into generic, arch, and platform

Made QEMU its own platform

Added shitty uart upload script for lichee board until I can get fel to
actually upload uboot payloads without hanging

TODO: Move platform selection out of build script

TODO: Move arch specific stuff from kernel to arch

TODO: Common linker script for arch instead of having a copy in each
platform
2022-01-04 01:50:46 -05:00

351 lines
7.2 KiB
C++

#include <stdarg.h>
#include <inttypes.h>
#define read_csr(csr) \
({ \
unsigned long __v; \
asm volatile ("csrr %0, " csr : "=r"(__v) : : "memory");\
__v;\
})
#define write_csr(csr, v) \
({ \
unsigned long __v = (v); \
asm volatile ("csrw " csr ", %0" : : "r"(__v) : "memory");\
})
#define set_csr_bits(csr, bits) \
({ \
unsigned long __v = (bits); \
asm volatile ("csrs " csr ", %0" : : "r"(__v) : "memory");\
})
#define clear_csr_bits(csr, bits) \
({ \
unsigned long __v = (bits); \
asm volatile ("csrc " csr ", %0" : : "r"(__v) : "memory");\
})
typedef unsigned long sbi_word;
void sbi_call1(int ext, int func, sbi_word arg0) {
register sbi_word rExt asm("a7") = ext;
register sbi_word rFunc asm("a6") = func;
register sbi_word rArg0 asm("a0") = arg0;
register sbi_word rArg1 asm("a1");
asm volatile("ecall" : "+r"(rArg0), "=r"(rArg1) : "r"(rExt), "r"(rFunc));
if(rArg0)
__builtin_trap();
}
void sbi_call2(int ext, int func, sbi_word arg0, sbi_word arg1) {
register sbi_word rExt asm("a7") = ext;
register sbi_word rFunc asm("a6") = func;
register sbi_word rArg0 asm("a0") = arg0;
register sbi_word rArg1 asm("a1") = arg1;
asm volatile("ecall" : "+r"(rArg0), "+r"(rArg1) : "r"(rExt), "r"(rFunc));
if(rArg0)
__builtin_trap();
}
void fmt(const char *f, ...) {
va_list va;
va_start(va, f);
while(*f) {
if(*f != '{') {
sbi_call1(1, 0, *(f++));
continue;
}
f++;
while(*f != '}') {
if(!(*f))
return;
f++;
}
f++;
unsigned long v = va_arg(va, unsigned long);
for(int i = 0; i < 16; ++i) {
const char *digits = "0123456789abcdef";
int d = (v >> (60 - i * 4)) & 0xF;
sbi_call1(1, 0, digits[d]);
}
}
va_end(va);
}
enum {
pte_valid = 1 << 0,
pte_r = 1 << 1,
pte_w = 1 << 2,
pte_x = 1 << 3,
pte_user = 1 << 4,
pte_access = 1 << 6,
pte_dirty = 1 << 7,
};
enum {
pte_ppn_shift = 10
};
struct pt_t {
unsigned long ptes[512];
} __attribute__((aligned(4096)));
enum {
satp_sv48 = 9UL << 60
};
const char *exception_strings[] = {
"instruction misaligned",
"instruction access fault",
"illegal instruction",
"breakpoint",
"load misaligned",
"load access fault",
"store misaligned",
"store access fault",
"u-mode ecall",
"s-mode ecall",
"reserved (10)",
"reserved (11)",
"instruction page fault",
"load page fault",
"reserved (14)",
"store page fault",
};
enum {
sie_s_software = (1 << 1),
sie_s_timer = (1 << 5)
};
enum {
sstatus_sie = (1 << 1)
};
void cli() {
clear_csr_bits("sstatus", sstatus_sie);
}
void sti() {
set_csr_bits("sstatus", sstatus_sie);
}
typedef struct {
void *sp;
} continuation_t;
struct task_t;
struct isr_frame_t {
task_t *task;
isr_frame_t *next;
unsigned long ra; // Offset 0x10.
unsigned long a[8]; // Offset 0x18.
unsigned long t[7]; // Offset 0x58.
unsigned long s1; // Offset 0x90.
unsigned long sstatus; // Offset 0x98.
unsigned long sepc; // Offset 0xA0.
};
enum {
kernel_stack_size = 0x10000
};
struct task_t {
continuation_t cont;
isr_frame_t isr_frames[2];
isr_frame_t *next_isr;
char kernel_stack[kernel_stack_size];
};
task_t task1;
task_t task2;
task_t *current_task;
continuation_t prepare_stack(void *s_top, void (*mainfn)(continuation_t)) {
void *sp = (void *)((uintptr_t)s_top - 0x78);
*((uint64_t *)((uintptr_t)sp + 0x70)) = (uint64_t)mainfn;
return (continuation_t){.sp = sp};
}
extern "C" void save_stack(void (*f)(void *, continuation_t), void *ctx);
extern "C" void restore_stack(continuation_t c);
void create_task(task_t *task, void (*mainfn)(continuation_t)) {
task->isr_frames[0].task = task;
task->isr_frames[1].task = task;
task->isr_frames[0].next = &task->isr_frames[1];
task->isr_frames[1].next = 0;
task->next_isr = &task->isr_frames[0];
task->cont = prepare_stack((void *)(task->kernel_stack + kernel_stack_size), mainfn);
}
void switch_task(void *ctx, continuation_t c) {
task_t *task = (task_t *)ctx;
if(task) {
task->next_isr = (isr_frame_t *)read_csr("sscratch");
task->cont = c;
}
task_t *next;
if(task == &task1) {
next = &task2;
}else{
next = &task1;
}
current_task = next;
write_csr("sscratch", (unsigned long)next->next_isr);
restore_stack(next->cont);
}
extern "C" void isr();
extern "C" void handle_isr(isr_frame_t *frame) {
unsigned long cause = read_csr("scause");
unsigned long code = cause & ~(1UL << 63);
if(cause & (1UL << 63)) {
if(code == 1) {
fmt("it's an IPI\n");
clear_csr_bits("sip", sie_s_software);
}else if(code == 5) { // Timer interrupt.
//clear_csr_bits("sie", sie_s_timer);
unsigned long time = read_csr("time");
sbi_call1(0x54494D45, 0, time + 100000);
save_stack(switch_task, current_task);
}else{
fmt("it's an unhandled interrupt, code: {}\n", code);
}
}else{
if(code == 8) { // Syscall.
sbi_call1(1, 0, frame->a[0]);
}else{
unsigned long sepc = read_csr("sepc");
fmt("it's an exception at {}\n", sepc);
const char *s = exception_strings[cause];
while(*s)
sbi_call1(1, 0, *(s++));
while(1)
;
}
}
}
extern "C" void isr_frame_overflow() {
fmt("isr frame overflow\n");
while(1)
;
}
pt_t pml4;
extern "C" void enter_umode(void *entry);
void syscall(int n, unsigned long arg0) {
register sbi_word rArg0 asm("a0") = arg0;
register sbi_word rN asm("a7") = n;
asm volatile("ecall" : "+r"(rArg0) : "r"(rN) : "memory");
if(rArg0)
__builtin_trap();
}
void task1_umode() {
while(1)
syscall(0, '!');
}
void task1_main(continuation_t c) {
fmt("hello from task1\n");
sti();
//syscall(0, '!');
//enter_umode((void *)task1_umode);
}
void task2_main(continuation_t c) {
fmt("hello from task2\n");
sti();
//while(1)
//fmt(".");
}
isr_frame_t global_isr_frames[2];
extern "C" void kmain(unsigned long hart, void *dtb) {
(void)hart;
(void)dtb;
//fmt("test\n");
/*
volatile uint32_t *cfg = (uint32_t *)0x2000060;
volatile uint32_t *dat = (uint32_t *)0x2000070;
*cfg = 0x10;
*dat = 0xFF;
*/
fmt("y");
cli();
global_isr_frames[0].next = &global_isr_frames[1];
write_csr("sscratch", (unsigned long)&global_isr_frames[0]);
write_csr("stvec", ((unsigned long)&isr));
const char *s;
set_csr_bits("sie", sie_s_software | sie_s_timer);
// Self-IPI.
sbi_call2(0x735049, 0, 1 << hart, 0);
sti();
cli();
unsigned long time;
//volatile uint32_t *meme = (uint32_t *)0x6011010;
//while(true) {
time = read_csr("time");
fmt("hello world {}\n", time);
//*meme = *meme | (0xA57 << 1) | (1 << 0);
//}
// Identity map the first 512GiB.
pml4.ptes[0] = ((0UL >> 12) << pte_ppn_shift) | pte_valid
| pte_r | pte_w | pte_x | pte_access | pte_dirty | pte_user;
// Map 512GiB -> 0.
pml4.ptes[1] = ((0UL >> 12) << pte_ppn_shift) | pte_valid
| pte_r | pte_w | pte_x | pte_access | pte_dirty | pte_user;
fmt("Writing paging memes\n");
unsigned long pml4p = (unsigned long)&pml4;
fmt("pml4p @ {}\n", pml4p);
fmt("Setting SStatus\n");
set_csr_bits("sstatus", 1 << 18);
fmt("Setting Satp\n");
write_csr("satp", (pml4p >> 12) | satp_sv48);
fmt("Paging might work?...\n");
s = "paging works!\n";
s += 512UL * 1024 * 1024 * 1024;
while(*s)
sbi_call1(1, 0, *(s++));
create_task(&task1, task1_main);
create_task(&task2, task2_main);
time = read_csr("time");
sbi_call1(0x54494D45, 0, time + 100000);
save_stack(switch_task, 0);
sbi_call1(8, 0, 0);
while(1);
}