added TextIO module for outputting text
This commit is contained in:
parent
ab19abe12b
commit
26e70d2f60
9
Makefile
9
Makefile
@ -11,12 +11,15 @@ GCC_PREF=riscv32-unknown-elf-
|
||||
|
||||
CC=$(GCC_PREF)gcc
|
||||
OBJDUMP=$(GCC_PREF)objdump
|
||||
CFLAGS=-I$(KLIBDIR) -O3 -MD -mcmodel=medany -Wall -Wextra -pedantic-errors
|
||||
CFLAGS=-I$(KLIBDIR) -MD -mcmodel=medany -Wall -Wextra -pedantic-errors
|
||||
KERNEL_CFLAGS=-nostdlib -T linker.ld
|
||||
ARCH = rv32im # here you
|
||||
|
||||
### Build configuration:
|
||||
|
||||
# comment out if you don't have any text IO device memory mapped
|
||||
CFLAGS += -DTEXT_IO_ADDR=0xff0000 -DTEXT_IO_BUFLEN=64
|
||||
|
||||
# uncomment these to build with only the rv32i standard
|
||||
#CFLAGS += -D__risc_no_ext=1
|
||||
#ARCH = rv32i
|
||||
@ -30,10 +33,10 @@ ARCH = rv32im # here you
|
||||
CFLAGS += -march=$(ARCH)
|
||||
|
||||
# dependencies that need to be built:
|
||||
_DEPS = ecall.c csr.c sched.c
|
||||
_DEPS = ecall.c csr.c sched.c io.o
|
||||
|
||||
# dependencies as object files:
|
||||
_OBJ = ecall.o sched.o boot.o csr.o
|
||||
_OBJ = ecall.o sched.o boot.o csr.o io.o
|
||||
|
||||
|
||||
DEPS = $(patsubst %,$(KLIBDIR)/%,$(_DEPS))
|
||||
|
5
kernel.c
5
kernel.c
@ -1,6 +1,7 @@
|
||||
#include "kernel.h"
|
||||
#include "ecall.h"
|
||||
#include "sched.h"
|
||||
#include "io.h"
|
||||
|
||||
void create_processes_from_bin_table();
|
||||
|
||||
@ -8,10 +9,14 @@ extern ProcessControlBlock processes[PROCESS_COUNT];
|
||||
|
||||
loaded_binary binary_table[NUM_BINARIES] __attribute__ ((section (".data")));
|
||||
|
||||
extern void memset(unsigned int, void*, void*);
|
||||
|
||||
extern void init()
|
||||
{
|
||||
init_ecall_table();
|
||||
|
||||
dbgln("Kernel started!", 15);
|
||||
|
||||
create_processes_from_bin_table();
|
||||
|
||||
scheduler_run_next();
|
||||
|
2
kernel.h
2
kernel.h
@ -20,7 +20,7 @@
|
||||
typedef struct loaded_binary {
|
||||
int binid;
|
||||
int entrypoint;
|
||||
int bounds[2];
|
||||
void* bounds[2];
|
||||
} loaded_binary;
|
||||
|
||||
// create a global table holding all loaded binaries.
|
||||
|
@ -106,18 +106,21 @@ trap_vector:
|
||||
jal trap_handle
|
||||
|
||||
|
||||
// make memset global
|
||||
.global memset
|
||||
.type memset, @function
|
||||
#ifdef __risc_no_ext
|
||||
// "dumb" memset, if RV32M is not present on the target
|
||||
// since memset is currently only used at startup, the performance implications
|
||||
// should be minimal.
|
||||
memset:
|
||||
bge a1, a2, 2f
|
||||
bge a1, a2, 2f
|
||||
1:
|
||||
sw a0, 0(a1)
|
||||
addi a1, a1, 4
|
||||
blt a1, a2, 1b
|
||||
sw a0, 0(a1)
|
||||
addi a1, a1, 4
|
||||
blt a1, a2, 1b
|
||||
2:
|
||||
ret
|
||||
ret
|
||||
|
||||
#else
|
||||
|
||||
|
@ -1,6 +1,7 @@
|
||||
#include "ecall.h"
|
||||
#include "sched.h"
|
||||
#include "csr.h"
|
||||
#include "io.h"
|
||||
|
||||
typedef int (*ecall_handler)(int*,ProcessControlBlock*);
|
||||
|
||||
@ -44,6 +45,13 @@ int ecall_handle_exit(int* args, ProcessControlBlock* pcb)
|
||||
pcb->status = PROC_DEAD;
|
||||
pcb->exit_code = *args;
|
||||
|
||||
char msg[34] = "process exited with code ";
|
||||
|
||||
itoa(pcb->pid, &msg[8], 10);
|
||||
itoa(*args % 10, &msg[28], 10);
|
||||
|
||||
dbgln(msg, 34);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -54,7 +62,7 @@ void trap_handle_ecall() {
|
||||
};
|
||||
ProcessControlBlock* pcb = get_current_process();
|
||||
int *regs = pcb->regs;
|
||||
int code = regs[16];
|
||||
int code = regs[16]; // code is inside a7
|
||||
|
||||
// check if the code is too large/small or if the handler is zero
|
||||
if (code < 0 || code > ECALL_TABLE_LEN || ecall_table[code] == 0) {
|
||||
@ -129,5 +137,6 @@ void init_ecall_table()
|
||||
|
||||
void handle_exception(int ecode, int mtval)
|
||||
{
|
||||
|
||||
dbgln("Trap encountered!", 17);
|
||||
__asm__("ebreak");
|
||||
}
|
||||
|
@ -17,7 +17,7 @@ enum ecall_codes {
|
||||
|
||||
#define ECALL_TABLE_LEN 16
|
||||
|
||||
enum ecall_errors {
|
||||
enum error_code {
|
||||
ENOCODE = -1, // invalid syscall code
|
||||
EINVAL = -2, // invalid argument value
|
||||
ENOMEM = -3, // not enough memory
|
||||
|
63
kinclude/io.c
Normal file
63
kinclude/io.c
Normal file
@ -0,0 +1,63 @@
|
||||
#include "io.h"
|
||||
|
||||
#ifdef TEXT_IO_ADDR
|
||||
|
||||
#ifndef TEXT_IO_BUFLEN
|
||||
#error "When defining TEXT_IO_ADDR, please also provide TEXT_IO_BUFLEN, otherwise textIO won't work!"
|
||||
#endif
|
||||
|
||||
void dbgln(char* text, int len)
|
||||
{
|
||||
while (len > TEXT_IO_BUFLEN) {
|
||||
dbgln(text, TEXT_IO_BUFLEN);
|
||||
text += TEXT_IO_BUFLEN;
|
||||
len -= TEXT_IO_BUFLEN;
|
||||
}
|
||||
|
||||
char* ioaddr = (char*) TEXT_IO_ADDR + 4;
|
||||
|
||||
for (int i = 0; i < len; i++) {
|
||||
if (*text == 0)
|
||||
break;
|
||||
*ioaddr++ = *text++;
|
||||
}
|
||||
|
||||
if (len < TEXT_IO_BUFLEN)
|
||||
*ioaddr = '\n';
|
||||
|
||||
// write a 1 to the start of the textIO to signal a buffer flush
|
||||
*((char*) TEXT_IO_ADDR) = 1;
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* if no textIO module loaded, dbgln is a noop :( */
|
||||
void dbgln(char*, int){}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/* alphabet for itoa */
|
||||
char alpha[16] = "0123456789abcdef";
|
||||
char* itoa (int value, char* str, int base)
|
||||
{
|
||||
if (base > 16 || base < 2) {
|
||||
*str++ = '?';
|
||||
return str;
|
||||
}
|
||||
|
||||
if (value < 0) {
|
||||
*str++ = '-';
|
||||
value *= -1;
|
||||
}
|
||||
|
||||
int num;
|
||||
do {
|
||||
num = value % base;
|
||||
value = value / base;
|
||||
*str++ = alpha[num];
|
||||
}
|
||||
while (value > 0);
|
||||
|
||||
return str;
|
||||
}
|
10
kinclude/io.h
Normal file
10
kinclude/io.h
Normal file
@ -0,0 +1,10 @@
|
||||
#ifndef H_IO
|
||||
#define H_IO
|
||||
|
||||
/* print a line to the debug textIO module */
|
||||
void dbgln(char* text, int len);
|
||||
|
||||
/* alphabet for itoa */
|
||||
char* itoa (int value, char* str, int base);
|
||||
|
||||
#endif
|
Loading…
Reference in New Issue
Block a user