Crate keos

Crate keos 

Source
Expand description

§KeOS: KAIST Educational Operating System

Welcome to the KeOS project!

Operating systems (OS) form the backbone of modern computing, managing hardware resources and providing a foundation for applications to run efficiently. Understanding how an OS works is crucial for grasping the inner workings of computer systems and software performance.

KeOS is designed to offer a hands-on learning experience with core OS components. Through this project, you will explore the fundamental principles of OS design while building a minimal but functional operating system from the ground up.

We prioritize simplicity, focusing on the most essential aspects of OS development. You won’t have to worry about handling obscure edge cases or hidden test cases. The score you receive after running the grading scripts is your final score. Our goal is to make this project as straightforward as possible. If you have suggestions on how we can further minimize unnecessary complexity and focus on the core concepts, we encourage your feedback.

§⚠️ IMPORTANT NOTES on GRADING

  • DO NOT make public forks of this project.
  • The KeOS license explicitly prohibits public redistribution of this work.
  • You MUST NOT share or distribute your work based on the provided template.
  • Cheating, plagiarism, or uploading your code online is strictly prohibited and will result in disqualification.

Failure to comply may result in academic integrity violations.

For the grading, please refer to the following policy:

  • Your submission must pass all test cases without modifying the non-whitelisted code in each project.
  • Submissions that fail to compile will receive 0 points.

§Why Rust?

We have chosen Rust for this project because of its memory safety, zero-cost abstractions, and most importantly, its concurrency model. These features make Rust an excellent choice for operating system development.

In traditional system programming languages, concurrency and memory bugs such as data races, use-after-free errors, and null pointer dereferences are common. Rust prevents these issues at compile time by enforcing strict ownership, borrowing, and lifetime rules. This allows you to write safe and efficient concurrent code without sacrificing performance, and reduces debugging time for those bugs.

By using Rust in KeOS, you will:

  • Develop safe and efficient concurrent programs without the risk of data races.
  • Avoid common concurrency pitfalls such as race conditions.

§Project Structure

The KeOS project is divided into five projects:

  1. System Call – Learn how the OS interacts with user applications.
  2. Memory Management – Implement basic memory management and user-space execution.
  3. Advanced Memory Management – Expand the KeOS’s memory management system with advanced features.
  4. Process Management – Implement the advanced process management, including round robin scheduler and sychronization primitives.
  5. File System – Develop a simple yet functional filesystem for data storage.

Each project builds upon the previous ones, helping you progressively develop a deeper understanding of OS design.

§Implementation Notes

In KeOS, each process/thread is assigned a fixed execution stack of STACK_SIZE bytes. While KeOS attempts to detect stack overflows, its detection is not perfect. A stack overflow may lead to mysterious kernel panics. To avoid this:

  • Avoid declaring large data structures on the stack.
let v: [u8; 0x200000]; // ERROR: This may cause a stack overflow
  • Instead, allocate large data structures on the heap using Box.
let v = Box::new([0u8; 0x200000]); // OK: Allocates on the heap

§Implementation Strategy

We recommend using a “TODO-driven” approach to build KeOS systematically. This method ensures an incremental and structured development process:

  1. Run the code and identify todo!() placeholders that cause panics.
  2. Implement the missing functionality, ensuring it aligns with the expected behavior described in the project requirements.
  3. Repeat steps 1 and 2 until all test cases pass and the system behaves correctly.

This approach allows you to build your OS one step at a time, making debugging and understanding the system easier.

§Getting Started

To set up your KeOS development environment, run the following commands:

$ mkdir keos
$ cd keos
$ curl https://raw.githubusercontent.com/casys-kaist/KeOS/refs/heads/main/scripts/install.sh | sh

We recommend using VS Code as the editor, along with rust-analyzer for Rust support.

  • DO NOT make public forks of this project.
  • The KeOS license explicitly prohibits public redistribution of this work.
  • You MUST NOT share or distribute your work based on the provided template.

Failure to comply may result in academic integrity violations.

§Selectively run tests

In KeOS, you can run one or more specific test cases by passing their names as arguments to the test runner. For example:

$ cargo run -- syscall::pipe_normal syscall::pipe_partial

This command runs exactly the listed test cases, syscall::pipe_normal and syscall::pipe_partial. You may specify a single test case or multiple test cases, depending on your needs.

§Grading Policy

During grading, we will overwrite all files except those explicitly whitelisted for each project. Any modifications to non-whitelisted files may result in a zero score, even if your implementation otherwise works correctly.

You can run the cargo grade command to check your current score locally. This reported score will be treated as your final grade, as long as your submission complies with the whitelist policy.

⚠️ IMPORTANT NOTES:

  • Your submission must pass all test cases without modifying the test code.
  • Submissions that fail to compile will receive 0 points.
  • Cheating, plagiarism, or uploading your code online is strictly prohibited and will result in disqualification.

Grading rubrics and the list of whitelisted files can be found in each grader’s .grade-target file.

§Debugging with GDB

KeOS supports debugging with GDB and QEMU. This section provides step-by-step instructions on how to set up and use GDB for effective debugging.

§Running GDB

To launch KeOS in debug mode, run the following command inside each grader directory:

$ GDB=1 cargo run <TESTCASE>

You must specify a single test case to debug with a GDB.

This starts QEMU and waits for a GDB connection on TCP port 1234. A .gdbinit script will also be generated to automate the debugging setup.

In a separate terminal, start GDB using:

$ rust-gdb keos_kernel

Why rust-gdb? We recommend rust-gdb, as it provides better support for Rust-specific data structures and improves debugging readability.

§One-time setup

Before using rust-gdb, you may need to modify your ~/.gdbinit file to allow script execution. Add the following line:

set auto-load safe-path /

After launching rust-gdb, the execution will halt at the startup stage, showing output similar to this:

$ rust-gdb
warning: No executable has been specified and target does not support
determining executable automatically. Try using the "file" command.
0x000000000000fff0 in ?? ()
(gdb)

Now, you can continue execution by typing:

§Inspect Each Core

In QEMU, each CPU core is treated as a separate thread. When debugging multi-core execution, be aware that some cores may panic while others continue running.

To inspect all active cores, use:

(gdb) info threads

This will display the state of each thread, including which CPU core it belongs to and its current stack frame. For example:

(gdb) info threads
Id   Target Id         Frame
* 1    Thread 1 (CPU#0 [running]) 0x000000000000fff0 in ?? ()
2    Thread 2 (CPU#1 [running]) 0x000000000000fff0 in ?? ()
3    Thread 3 (CPU#2 [running]) 0x000000000000fff0 in ?? ()
4    Thread 4 (CPU#3 [running]) 0x000000000000fff0 in ?? ()

To switch to a specific CPU core (thread), use:

(gdb) thread {thread_id}

This allows you to inspect registers, call stacks, and execution state per core.


§Analyzing Execution State

§Viewing the Call Stack (Backtrace)

Use backtrace (or bt) to display the call stack of the current thread:

(gdb) bt

Each function call in the stack is represented as a frame. To switch to a specific frame, use:

(gdb) frame {frame_id}

Once inside a frame, you can inspect variables:

(gdb) info args
(gdb) info locals
(gdb) i r

Debugging a Panic: If you encounter a kernel panic during a test, use:

  1. info threads to locate the crashing core
  2. bt to examine the backtrace
  3. frame {frame_id} to inspect function parameters

§Setting Breakpoints

Breakpoints help stop execution at specific points. However, in multi-core debugging, regular breakpoints may not always work correctly. Instead, use hardware breakpoints:

(gdb) hb * {address_of_breakpoint}

To view the source code that the current CPU is executing, use:

(gdb) layout asm
(gdb) layout src

§Examples

Here are some examples of how to set breakpoints in GDB:

(gdb) hbreak function_name  # Example: hbreak keos::fs::Directory::open
(gdb) hbreak *address       # Example: hbreak *0x1000
(gdb) hbreak (file:)line    # Example: hbreak syscall.rs:164
§Example 1

To debug the syscall::read_normal test case in project 1, and set a breakpoint at syscall.rs:150, use:

(gdb) hbreak syscall.rs:150

Alternatively, you can set a breakpoint by the test case’s name:

(gdb) hbreak project1_grader::syscall::read_normal

You can even set a breakpoint on the closure entry, for instance, to set a on a closure of sync::semaphore::sema_0 test case in project 3:

(gdb) hbreak project3_grader::sync::semaphore::{{closure}}

To limit debugging to one core, use thread apply:

(gdb) thread apply 1 hbreak syscall.rs:150
(gdb) c
§Example 2

To stop at a breakpoint only when a specific condition is met (e.g., when a parameter is 0xcafe0000), use:

(gdb) hbreak walk if va.__0 == 0xcafe0000

This approach allows you to focus on specific conditions and skip over unrelated calls.


§Stopping an execution

When KeOS got stuck in deadlock or does not automatically shut down after it panicked, you may need to forcibly shut down the QEMU.

For execution in cargo grade or cargo run without argument in project 5, press Ctrl-C to stop execution.

Otherwise, such as running KeOS by cargo run in project 1-4, press Ctrl-A, then press X to stop execution.

Modules§

channel
Multi-producer, multi-consumer FIFO queue communication primitives.
fs
Filesystem abstraction.
interrupt 🔒
Interrupt management.
intrinsics
Intrinsics of x86_64 not included in core::arch::x86_64.
lang 🔒
Rust-specific implemenations.
mm
Memory Management.
sync
Synchronization primitives.
syscall
System call infrastructure.
task
Task trait for interact with user process.
teletype
A teletype (TTY) interface for character-based I/O.
thread
Thread abstration, an abstraction of a cpu core.
util
Debugging Utilities.

Macros§

debug
Display a debug message.
info
Display an information message.
print
Prints out the message.
println
Prints out the message with a newline.
warning
Display a warning message.

Structs§

SystemConfigurationBuilder
A builder for system configuration settings.
TestDriver
A driver for running tests.
TryFromError
The given isize does not indicate an KernelError.

Enums§

KernelError
Enum representing errors that can occur during a kernel operation.

Constants§

MAX_CPU
Maximum number of CPU the kernel can support.

Statics§

PANIC_DEPTH
Panic depth level.

Functions§

rust_ap_main
The entry of the KeOS for application processor.
rust_main
The entry of the KeOS for bootstrap processor.