SloperatingSystem — Minimal RISC-V Operating System
A small, educational operating system built for CSCE 311 and designed to run on a RISC-V machine. This OS includes a kernel, interactive shell, cooperative scheduler, user programs, and a simple in-memory file system. It demonstrates many core OS concepts in a compact, understandable codebase.
✨ Features 🧵 Multitasking / Multiprogramming
Create and run multiple user programs simultaneously
Cooperative round-robin scheduling (proc.c)
Context switching implemented in assembly (swtch.S)
Shell commands: ps, kill, step, etc.
📂 Simple In-Memory File System
Hierarchical tree of directories and files (fs.c)
Built-in files compiled into the kernel (e.g., hello.txt, readme.txt)
Dynamic directories via mkdir
Shell commands: ls, cd, pwd, cat
🔐 Basic Protection & Synchronization
Per-process kernel-managed stacks
Isolated user-task contexts
Infrastructure ready for locks & kernel synchronization primitives
💻 Command-Line Shell
Commands include:
Command Description ls List files in current directory cd
Change directory pwd Print working directory cat Print file contents mkdir Create directory ps List processes kill Terminate process runuser Run built-in demo user tasks step Step scheduler hello Test command clear Clear screen help Show help 📁 Directory Structure SloperatingSystem/ Makefile linker.ld start.S kernel.c kernel.h shell.c shell.h proc.c proc.h fs.c fs.h user.c user.h swtch.S uart.c uart.h🛠️ Building the OS Prerequisites
Install a RISC-V cross-compiler and QEMU:
riscv64-unknown-elf-gcc
qemu-system-riscv64
Build the kernel
From SloperatingSystem/:
make
If needed, specify your toolchain prefix:
make CROSS_PREFIX=riscv64-unknown-elf-
This drops you into the interactive shell.
🧪 Writing & Running New Programs
There are two ways to create new programs in this OS:
A) Create a new user task (recommended)
Edit user.c and add a function:
void my_task(void) { for (int i = 0; i < 10; i++) { uart_puts("[my_task] Iter "); uart_putint(i); uart_puts("\n"); } }
Register the task (e.g., in run_user_program() inside shell.c):
proc_create(my_task);
Rebuild and run:
make qemu-system-riscv64 -nographic -machine virt -kernel kernel.elf
Use shell commands: ps, kill , etc.
B) Add a new file to the file system
Edit fs.c:
static const char file_myfile_txt[] = "Hello from myfile!\n";
static struct FsNode node_myfile = { .name = "myfile.txt", .type = FS_NODE_FILE, .parent = &node_root, .u.file = { .data = file_myfile_txt, .size = sizeof(file_myfile_txt) - 1 } };
Then add it to the root directory’s entry list.
After rebuilding:
cat myfile.txt
🚀 Potential Extensions
Implement a real ELF loader (exec)
Add paging (Sv39) for real user–kernel memory protection
Add a persistent disk-backed FS with a mkfs tool
Preemptive scheduling using timer interrupts
IPC: pipes, semaphores, message queues
A real syscall interface for user programs