Compare commits

...

2 commits

Author SHA1 Message Date
94fbea02ca
Kernel: tabs -> spaces 2022-01-05 02:50:14 -05:00
d5d92555ae
Drivers: Started OpenSBI driver
Just ecall wrapper for now

TODO: Build system changes are lazy and need to be figured out

TODO: Looks like kernel.cpp was indented with tabs, fix
2022-01-05 02:47:30 -05:00
6 changed files with 367 additions and 201 deletions

View file

@ -8,6 +8,7 @@ arch_sources += [
elf = executable( elf = executable(
'kernel.elf', 'kernel.elf',
arch_sources, arch_sources,
include_directories: includes,
link_args: [ link_args: [
'-Wl,-T,' + meson.current_source_dir() + '/platform.ld', '-Wl,-T,' + meson.current_source_dir() + '/platform.ld',
'-static' '-static'

View file

@ -0,0 +1,62 @@
#pragma once
typedef unsigned long uintmax_t;
namespace drivers {
namespace opensbi {
// We use uintmax_t to make sure this works on 32 and 64 bit
// At least thats how I hope this works..
// TODO: Add assert() to make sure this is the case
struct sbiret_t {
uintmax_t error;
uintmax_t value;
};
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3,
uintmax_t a4,
uintmax_t a5);
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3,
uintmax_t a4);
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3);
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2);
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1);
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0);
} // End namespace opensbi
} // End namespace drivers

View file

@ -0,0 +1,9 @@
kernel_sources += [
files(
'opensbi.cpp'
),
]
kernel_includes += include_directories(
'include'
)

View file

@ -0,0 +1,78 @@
#include <cstdint>
#include <opensbi.h>
namespace drivers {
namespace opensbi {
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3,
uintmax_t a4,
uintmax_t a5) {
register uintmax_t r_a7 asm("a7") = extension;
register uintmax_t r_a6 asm("a6") = function;
register uintmax_t r_a0 asm("a0") = a0;
register uintmax_t r_a1 asm("a1") = a1;
register uintmax_t r_a2 asm("a2") = a2;
register uintmax_t r_a3 asm("a3") = a3;
register uintmax_t r_a4 asm("a4") = a4;
register uintmax_t r_a5 asm("a5") = a5;
asm volatile("ecall" : // Instruction
"=r"(r_a0), "=r"(r_a1) : // Inputs
"r"(r_a7), "r"(r_a6), // Outputs
"r"(r_a0), "r"(r_a1), "r"(r_a2),
"r"(r_a3), "r"(r_a4), "r"(r_a5));
return {.error = a0, .value = a1};
}
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3,
uintmax_t a4) {
return call(extension, function, a0, a1, a2, a3, a4, 0);
}
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2,
uintmax_t a3) {
return call(extension, function, a0, a1, a2, a3, 0, 0);
}
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1,
uintmax_t a2) {
return call(extension, function, a0, a1, a2, 0, 0, 0);
}
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0,
uintmax_t a1) {
return call(extension, function, a0, a1, 0, 0, 0, 0);
}
sbiret_t call(
uintmax_t extension,
uintmax_t function,
uintmax_t a0) {
return call(extension, function, a0, 0, 0, 0, 0, 0);
}
} // End namespace opensbi
} // End namespace drivers

View file

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

View file

@ -4,5 +4,16 @@ kernel_sources = [
) )
] ]
kernel_includes = [
include_directories('include')
]
subdir('drivers/opensbi')
includes = [
# arch_includes,
kernel_includes
]
subdir('arch/' + arch) subdir('arch/' + arch)