Compare commits
9 Commits
main
...
4cc12e6e26
| Author | SHA1 | Date | |
|---|---|---|---|
| 4cc12e6e26 | |||
| ef9899bac1 | |||
| b3db8e7e59 | |||
| 6db84bf318 | |||
| 10a38cf572 | |||
| 12f6e05a4e | |||
| 7367da52fb | |||
| d6522f5275 | |||
| 9fda2986ab |
8
.clang-format
Normal file
8
.clang-format
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
BasedOnStyle: LLVM
|
||||||
|
UseTab: Always
|
||||||
|
TabWidth: 4
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentCaseLabels: true
|
||||||
|
ColumnLimit: 120
|
||||||
|
PointerAlignment: Right
|
||||||
|
AllowShortFunctionsOnASingleLine: None
|
||||||
11
.gitignore
vendored
11
.gitignore
vendored
@@ -1,3 +1,13 @@
|
|||||||
|
/disk/*
|
||||||
|
!/disk/.gitkeep
|
||||||
|
*.map
|
||||||
|
*.tar
|
||||||
|
*.o
|
||||||
|
*.elf
|
||||||
|
*.bin
|
||||||
|
*.log
|
||||||
|
*.pcap
|
||||||
|
|
||||||
# ---> C
|
# ---> C
|
||||||
# Prerequisites
|
# Prerequisites
|
||||||
*.d
|
*.d
|
||||||
@@ -51,4 +61,3 @@ modules.order
|
|||||||
Module.symvers
|
Module.symvers
|
||||||
Mkfile.old
|
Mkfile.old
|
||||||
dkms.conf
|
dkms.conf
|
||||||
|
|
||||||
|
|||||||
@@ -1,2 +1,3 @@
|
|||||||
# rivos
|
# rivos
|
||||||
|
|
||||||
|
This toy os is made following the [OS in 1,000 lines](https://1000os.seiya.me/en/) project.
|
||||||
|
|||||||
5
format.sh
Executable file
5
format.sh
Executable file
@@ -0,0 +1,5 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
set -xue
|
||||||
|
|
||||||
|
find . -type f -name '*.c' -exec clang-format -i {} \;
|
||||||
|
find . -type f -name '*.h' -exec clang-format -i {} \;
|
||||||
14
include/io.h
Normal file
14
include/io.h
Normal file
@@ -0,0 +1,14 @@
|
|||||||
|
#ifndef RIVOS_IO_H
|
||||||
|
#define RIVOS_IO_H
|
||||||
|
|
||||||
|
#include "../include/types.h"
|
||||||
|
|
||||||
|
#define va_list __builtin_va_list
|
||||||
|
#define va_start __builtin_va_start
|
||||||
|
#define va_end __builtin_va_end
|
||||||
|
#define va_arg __builtin_va_arg
|
||||||
|
|
||||||
|
void r_printf(const char *fmt, ...);
|
||||||
|
size_t r_strlen(const char *str);
|
||||||
|
|
||||||
|
#endif
|
||||||
9
include/kernel.h
Normal file
9
include/kernel.h
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
#ifndef RIVOS_KERNEL_H
|
||||||
|
#define RIVOS_KERNEL_H
|
||||||
|
|
||||||
|
typedef struct sbiret_s {
|
||||||
|
long error;
|
||||||
|
long value;
|
||||||
|
} sbiret_s;
|
||||||
|
|
||||||
|
#endif
|
||||||
11
include/types.h
Normal file
11
include/types.h
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
#ifndef RIVOS_TYPES_H
|
||||||
|
#define RIVOS_TYPES_H
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Define our standard types
|
||||||
|
*/
|
||||||
|
typedef unsigned char u8;
|
||||||
|
typedef unsigned int u32;
|
||||||
|
typedef u32 size_t;
|
||||||
|
|
||||||
|
#endif
|
||||||
59
kernel.ld
Normal file
59
kernel.ld
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
/**
|
||||||
|
* This is the entry point
|
||||||
|
* `boot` should be a defined label
|
||||||
|
*/
|
||||||
|
ENTRY(boot)
|
||||||
|
|
||||||
|
/**
|
||||||
|
* SECTIONS tells to linker how to arrange sections inside the memory
|
||||||
|
*/
|
||||||
|
SECTIONS {
|
||||||
|
/**
|
||||||
|
* This is the base address (start address of the kernel)
|
||||||
|
* OpenSBI takes little ram
|
||||||
|
*/
|
||||||
|
. = 0x80200000;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This section contains the code of the program
|
||||||
|
*/
|
||||||
|
.text :{
|
||||||
|
/**
|
||||||
|
* Take the .text.boot before everything
|
||||||
|
* KEEP() prevents the linker to mark it as "unused"
|
||||||
|
*/
|
||||||
|
KEEP(*(.text.boot));
|
||||||
|
/**
|
||||||
|
* Include everything else inside the .text section
|
||||||
|
*/
|
||||||
|
*(.text .text.*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains constant read-only data
|
||||||
|
* Align the start of the section at 4 byte
|
||||||
|
*/
|
||||||
|
.rodata : ALIGN(4) {
|
||||||
|
*(.rodata .rodata.*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains read/write data
|
||||||
|
*/
|
||||||
|
.data : ALIGN(4) {
|
||||||
|
*(.data .data.*);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Contains read/data with an initial value of zero
|
||||||
|
*/
|
||||||
|
.bss : ALIGN(4) {
|
||||||
|
__bss = .;
|
||||||
|
*(.bss .bss.* .sbss .sbss.*);
|
||||||
|
__bss_end = .;
|
||||||
|
}
|
||||||
|
|
||||||
|
. = ALIGN(4);
|
||||||
|
. += 128 * 1024; /* 128KB */
|
||||||
|
__stack_top = .;
|
||||||
|
}
|
||||||
32
run.sh
Executable file
32
run.sh
Executable file
@@ -0,0 +1,32 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# -x -> trace: print every command
|
||||||
|
# -u -> exit if undefined variables are used
|
||||||
|
# -e -> exit if an error occurs
|
||||||
|
set -xue
|
||||||
|
|
||||||
|
QEMU=qemu-system-riscv32
|
||||||
|
|
||||||
|
# Compile
|
||||||
|
CC=clang
|
||||||
|
# -ffreestanding: do not use stdlib of the host environment
|
||||||
|
# -fuse-ld=lld: LLVM linker
|
||||||
|
# -fno-stack-protector: disable stack protection
|
||||||
|
# -Wl,-Tkernel.ld: linker script
|
||||||
|
# -Wl,-Map=kernel.map: output a map file (linker allocationr result)
|
||||||
|
CFLAGS="-std=c11 -O2 -g3 -Wall -Wextra --target=riscv32-unknown-elf -fuse-ld=lld -fno-stack-protector -ffreestanding -nostdlib"
|
||||||
|
|
||||||
|
$CC $CFLAGS -Wl,-Tkernel.ld -Wl,-Map=kernel.map -o kernel.elf \
|
||||||
|
src/kernel.c \
|
||||||
|
src/io.c
|
||||||
|
|
||||||
|
# Run QEMU
|
||||||
|
# -machine virt: generic riscv platform
|
||||||
|
# -bios default: load the default firmware (OpenSBI)
|
||||||
|
# -nographic: disable VGA, everything on console
|
||||||
|
# -serial mon:stdio: serial port is connected to terminal's stdin/stdout
|
||||||
|
# --no-reboot: do not reboot if there's panic/shutdown/crash
|
||||||
|
$QEMU -machine virt -bios default -nographic -serial mon:stdio --no-reboot \
|
||||||
|
-kernel kernel.elf
|
||||||
|
|
||||||
|
# Press Ctrl+A and then C to enter QEMU debug console and quit with `q`
|
||||||
100
src/io.c
Normal file
100
src/io.c
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
#include "../include/io.h"
|
||||||
|
|
||||||
|
void k_putchar(char ch);
|
||||||
|
|
||||||
|
void r_printf(const char *fmt, ...) {
|
||||||
|
va_list args;
|
||||||
|
va_start(args, fmt);
|
||||||
|
|
||||||
|
while (*fmt) {
|
||||||
|
if (*fmt != '%') {
|
||||||
|
k_putchar(*fmt);
|
||||||
|
fmt++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Skip '%' */
|
||||||
|
fmt++;
|
||||||
|
switch (*fmt) {
|
||||||
|
case '\0': {
|
||||||
|
/* Simply print the char */
|
||||||
|
k_putchar('%');
|
||||||
|
|
||||||
|
goto end;
|
||||||
|
}
|
||||||
|
case '%': {
|
||||||
|
/* Print '%' */
|
||||||
|
k_putchar('%');
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 's': {
|
||||||
|
/* Print a NULL-terminated string */
|
||||||
|
const char *s = va_arg(args, const char *);
|
||||||
|
while (*s) {
|
||||||
|
k_putchar(*s);
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'd': {
|
||||||
|
/* Print an integer in decimal */
|
||||||
|
int value = va_arg(args, int);
|
||||||
|
unsigned magnitude = value;
|
||||||
|
if (value < 0) {
|
||||||
|
k_putchar('-');
|
||||||
|
magnitude = -magnitude;
|
||||||
|
}
|
||||||
|
|
||||||
|
unsigned divisor = 1;
|
||||||
|
while (magnitude / divisor > 9) {
|
||||||
|
divisor *= 10;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (divisor > 0) {
|
||||||
|
k_putchar('0' + magnitude);
|
||||||
|
k_putchar('0' + magnitude / divisor);
|
||||||
|
magnitude %= divisor;
|
||||||
|
k_putchar('0' + magnitude);
|
||||||
|
divisor /= 10;
|
||||||
|
k_putchar('0' + magnitude);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case 'x': {
|
||||||
|
/* Print an integer in hexadecimal */
|
||||||
|
unsigned value = va_arg(args, unsigned);
|
||||||
|
for (int i = 7; i >= 0; --i) {
|
||||||
|
unsigned nibble = (value >> (i * 4)) & 0xF;
|
||||||
|
/* From a char array we get the nibble position */
|
||||||
|
k_putchar("0123456789ABCDEF"[nibble]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default: {
|
||||||
|
const char *str = "NOT IMPLEMENTED";
|
||||||
|
size_t len = r_strlen(str);
|
||||||
|
for (size_t i = 0; i < len; ++i) {
|
||||||
|
k_putchar(str[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Next char */
|
||||||
|
fmt++;
|
||||||
|
}
|
||||||
|
end:
|
||||||
|
va_end(args);
|
||||||
|
}
|
||||||
|
|
||||||
|
size_t r_strlen(const char *str) {
|
||||||
|
size_t len = 0;
|
||||||
|
|
||||||
|
while (*str) {
|
||||||
|
len++;
|
||||||
|
str++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return len;
|
||||||
|
}
|
||||||
74
src/kernel.c
Normal file
74
src/kernel.c
Normal file
@@ -0,0 +1,74 @@
|
|||||||
|
#include "../include/kernel.h"
|
||||||
|
#include "../include/io.h"
|
||||||
|
#include "../include/types.h"
|
||||||
|
|
||||||
|
extern char __bss[], __bss_end[], __stack_top[];
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This function will call OpenSBI
|
||||||
|
* ecall is used as the control transfer instruction,
|
||||||
|
* it switches from kernel mode (s-mode) to opensbi mode (m-mode)
|
||||||
|
* a7 encodes the SBI extension ID (EID)
|
||||||
|
* a6 encodes the SBI function ID (FID)
|
||||||
|
*
|
||||||
|
* a0 returns and error code
|
||||||
|
*/
|
||||||
|
sbiret_s sbi_call(long arg0, long arg1, long arg2, long arg3, long arg4, long arg5, long fid, long eid) {
|
||||||
|
register long a0 __asm("a0") = arg0;
|
||||||
|
register long a1 __asm__("a1") = arg1;
|
||||||
|
register long a2 __asm__("a2") = arg2;
|
||||||
|
register long a3 __asm__("a3") = arg3;
|
||||||
|
register long a4 __asm__("a4") = arg4;
|
||||||
|
register long a5 __asm__("a5") = arg5;
|
||||||
|
register long a6 __asm__("a6") = fid;
|
||||||
|
register long a7 __asm__("a7") = eid;
|
||||||
|
|
||||||
|
__asm__ __volatile__("ecall"
|
||||||
|
: "=r"(a0), "=r"(a1)
|
||||||
|
: "r"(a0), "r"(a1), "r"(a2), "r"(a3), "r"(a4), "r"(a5), "r"(a6), "r"(a7)
|
||||||
|
: "memory");
|
||||||
|
|
||||||
|
return (sbiret_s){.error = a0, .value = a1};
|
||||||
|
}
|
||||||
|
|
||||||
|
void k_putchar(char ch) {
|
||||||
|
sbi_call(ch, 0, 0, 0, 0, 0, 0, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void *k_memset(void *buf, char c, size_t n) {
|
||||||
|
u8 *p = (u8 *)buf;
|
||||||
|
while (n--) {
|
||||||
|
*p++ = c;
|
||||||
|
}
|
||||||
|
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Kernel main */
|
||||||
|
void kernel_main(void) {
|
||||||
|
/* Usually it is not required */
|
||||||
|
k_memset(__bss, 0, __bss_end - __bss);
|
||||||
|
|
||||||
|
/* Start here */
|
||||||
|
r_printf("%s, %s\n", "Hello", "world!");
|
||||||
|
r_printf("3 + 4 = %d\n", 3 + 4);
|
||||||
|
|
||||||
|
for (;;) {
|
||||||
|
__asm__ __volatile__("wfi");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* This is the entry section (boot) */
|
||||||
|
__attribute__((section(".text.boot")))
|
||||||
|
/* Do not add other stuff like return */
|
||||||
|
__attribute__((naked)) void
|
||||||
|
boot(void) {
|
||||||
|
/**
|
||||||
|
* Put stack_top inside sp (stack pointer)
|
||||||
|
* and jump to kernel_main
|
||||||
|
*/
|
||||||
|
__asm__ __volatile__("mv sp, %[stack_top]\n"
|
||||||
|
"j kernel_main\n"
|
||||||
|
:
|
||||||
|
: [stack_top] "r"(__stack_top));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user