This commit is contained in:
Michael Zhang 2024-12-05 12:23:16 -06:00
parent ca02b44b71
commit 0bbf694137
29 changed files with 81 additions and 267 deletions

9
.cargo/config.toml Normal file
View file

@ -0,0 +1,9 @@
[build]
target = "riscv64gc-unknown-none-elf"
[target.riscv64gc-unknown-none-elf]
rustflags = ["-C", "link-arg=-Tsrc/ld/kernel.ld"]
runner = "./scripts/start.sh"
[term]
verbose = true

7
.gitignore vendored
View file

@ -1,2 +1,9 @@
/target /target
/build /build
# Added by cargo
#
# already existing elements were commented out
#/target

2
Cargo.lock generated
View file

@ -3,5 +3,5 @@
version = 3 version = 3
[[package]] [[package]]
name = "kernel" name = "eos0"
version = "0.1.0" version = "0.1.0"

View file

@ -1,5 +1,6 @@
workspace.members = ["kernel"] [package]
workspace.resolver = "2" name = "eos0"
version = "0.1.0"
edition = "2021"
profile.dev.panic = "abort" [dependencies]
profile.release.panic = "abort"

8
Makefile Normal file
View file

@ -0,0 +1,8 @@
KERNEL = target/riscv64gc-unknown-none-elf/debug/xv6-riscv-rust
SOURCES := $(shell find -name "*.rs")
$(KERNEL): $(SOURCES)
cargo build
fs.img: mkfs/mkfs README.md $(UPROGS)
mkfs/mkfs fs.img README.md $(UPROGS)

View file

@ -1,9 +0,0 @@
# EOS0
This is mainly a port of MIT's xv6 operating system, for educational purposes.
You can consider the "e" in EOS to be either educational or experimental.
## References
- https://lowenware.com/blog/aarch64-bare-metal-program-in-rust/

View file

@ -1,14 +0,0 @@
ENTRY(_start)
SECTIONS
{
. = 0x40080000;
.text.boot : { *(.text.boot) }
.text : { *(.text) }
.data : { *(.data) }
.rodata : { *(.rodata) }
.bss : { *(.bss) }
. = ALIGN(8);
. = . + 0x4000;
LD_STACK_PTR = .;
}

View file

@ -1,23 +0,0 @@
{
"arch": "aarch64",
"crt-objects-fallback": "false",
"data-layout": "e-m:e-i8:8:32-i16:16:32-i64:64-i128:128-n32:64-S128",
"disable-redzone": true,
"features": "-align,-neon",
"linker": "rust-lld",
"linker-flavor": "gnu-lld",
"llvm-target": "aarch64-unknown-none",
"max-atomic-width": 128,
"panic-strategy": "abort",
"pre-link-args": {
"gnu": ["--fix-cortex-a53-843419"],
"gnu-lld": ["--fix-cortex-a53-843419", "-Taarch64-qemu.ld"],
"ld.lld": ["-Taarch64-qemu.ld"]
},
"relocation-model": "static",
"stack-probes": {
"kind": "inline"
},
"supported-sanitizers": ["kcfi", "kernel-address"],
"target-pointer-width": "64"
}

View file

@ -1,5 +0,0 @@
# Run run.sh before this!
set -euo pipefail
exec rust-lldb \
-s lldb-init \
target/aarch64-unknown-none/debug/kernel

View file

@ -1,9 +0,0 @@
[package]
name = "kernel"
version = "0.1.0"
edition = "2021"
# [lib]
# crate-type = ["staticlib"]
[dependencies]

View file

@ -1,27 +0,0 @@
use core::fmt::{self, Write};
use crate::{spinlock::SpinLock, uart::UART};
/// A wrapper around the console
pub struct Console {
lock: SpinLock,
uart: UART,
}
impl Console {
pub fn init() -> Self {
let lock = SpinLock::init("console");
let uart = UART::init();
Console { lock, uart }
}
}
impl Write for Console {
fn write_str(&mut self, s: &str) -> fmt::Result {
// TODO: Lock
Ok(())
// TODO: Release lock
}
}

View file

@ -1 +0,0 @@

View file

@ -1 +0,0 @@

View file

@ -1,34 +0,0 @@
#![no_std]
#![no_main]
use core::fmt::Write;
use core::{arch::global_asm, ptr};
use crate::console::Console;
use crate::memory_layout::UART0;
#[macro_use]
mod macros;
mod console;
mod io;
mod memory_layout;
mod panic;
mod spinlock;
mod uart;
// global_asm!(include_str!("start.s"));
global_asm!(include_str!("riscv64gc/start.s"));
#[no_mangle]
pub extern "C" fn main() {
let mut console = Console::init();
// let _ = writeln!(console, "eos0 is booting...");
let out_str = b"AArch64 Bare Metal";
for byte in out_str {
unsafe {
ptr::write_volatile(UART0, *byte);
}
}
}

View file

@ -1 +0,0 @@
pub const UART0: *mut u8 = 0x0900_0000 as *mut u8;

View file

@ -1,7 +0,0 @@
use core::panic::PanicInfo;
#[cfg(not(test))]
#[panic_handler]
fn on_panic(_info: &PanicInfo) -> ! {
loop {}
}

View file

@ -1,15 +0,0 @@
.section .text
.global _entry
_entry:
la sp, stack0
li a0, 1024*4
csrr a1, mhartid
addi a1, a1, 1
mul a0, a0, a1
add sp, sp, a0
call main
spin:
j spin

View file

@ -1,18 +0,0 @@
pub struct SpinLock {
locked: bool,
/// The name of the lock, for debugging
name: [u8; 32],
}
impl SpinLock {
pub fn init(name: &'static str) -> Self {
let mut this_name = [0; 32];
this_name.copy_from_slice(&name.as_bytes()[..32.min(name.len())]);
SpinLock {
locked: false,
name: this_name,
}
}
}

View file

@ -1,15 +0,0 @@
.globl _start
.extern LD_STACK_PTR
.section ".text.boot"
_start:
ldr x30, =LD_STACK_PTR
mov sp, x30
bl main
.equ PSCI_SYSTEM_OFF, 0x84000008
.globl system_off
system_off:
ldr x0, =PSCI_SYSTEM_OFF
hvc #0

View file

@ -1,40 +0,0 @@
//! UART (Universal Asynchronous Receiver-Transmitter)
use crate::memory_layout::UART0;
/// The UART Interface
pub struct UART {}
impl UART {
/// Most of this is just a port from xv6 right now, I have no idea why any of this works
pub fn init() -> Self {
unsafe {
UART::write_register(WriteRegister::IER, 0x00);
}
UART {}
}
#[inline]
pub unsafe fn write_register(reg: WriteRegister, val: u8) {
*reg.as_mut_ptr() = val;
}
pub unsafe fn put_char(&self) {}
}
/// <http://byterunner.com/16550.html>
pub enum ReadRegister {}
#[derive(Copy, Clone)]
pub enum WriteRegister {
IER = 1,
}
impl WriteRegister {
pub fn as_mut_ptr(&self) -> *mut u8 {
unsafe { UART0.offset(*self as isize) }
}
}
#[inline]
fn read_register() {}

View file

@ -1,2 +0,0 @@
target create target/aarch64-unknown-none/debug/kernel
gdb-remote 1234

View file

@ -1,22 +0,0 @@
{
"arch": "riscv64",
"code-model": "medium",
"cpu": "generic-rv64",
"crt-objects-fallback": "false",
"data-layout": "e-m:e-p:64:64-i64:64-i128:128-n32:64-S128",
"eh-frame-header": false,
"emit-debug-gdb-scripts": true,
"features": "+m,+a,+f,+d,+c",
"linker": "rust-lld",
"linker-flavor": "gnu-lld",
"llvm-abiname": "lp64d",
"llvm-target": "riscv64",
"max-atomic-width": 64,
"panic-strategy": "abort",
"relocation-model": "static",
"pre-link-args": {
"gnu-lld": ["-Taarch64-qemu.ld"]
},
"supported-sanitizers": ["kernel-address"],
"target-pointer-width": "64"
}

16
run.sh
View file

@ -1,16 +0,0 @@
set -euo pipefail
cargo xbuild --target=aarch64-unknown-none.json
DEBUG=
DEBUG="-s -S -d exec"
printf "Running with qemu...\n"
set -x
exec qemu-system-aarch64 \
-machine virt \
$DEBUG \
-m 1024M \
-cpu cortex-a53 \
-no-reboot \
-nographic \
-kernel target/aarch64-unknown-none/debug/kernel

View file

@ -1 +0,0 @@
nightly

View file

@ -1,2 +0,0 @@
tab_spaces = 2
max_width = 80

14
scripts/start.sh Executable file
View file

@ -0,0 +1,14 @@
#!/usr/bin/env bash
KERNEL=$1
shift
qemu-system-riscv64 \
-nographic \
-machine virt \
-bios none \
-m 3G \
-smp 3 \
# -drive file=fs.img,if=none,format=raw,id=x0 \
-device virtio-blk-device,drive=x0,bus=virtio-mmio-bus.0 \
-kernel "$KERNEL"

12
src/ld/kernel.ld Normal file
View file

@ -0,0 +1,12 @@
OUTPUT_ARCH("riscv")
ENTRY(_entry)
SECTIONS {
/*
It seems that QEMU jumps to 0x8000000 after setting up memory, so we want
our kernel code to begin here.
TODO: Is there an authoritative source that says that this is the address?
*/
. = 0x8000000;
}

25
src/main.rs Normal file
View file

@ -0,0 +1,25 @@
#![no_std]
#![no_main]
use core::panic::PanicInfo;
#[panic_handler]
fn panic_handler(_: &PanicInfo) -> ! {
loop {}
}
static HELLO: &[u8] = b"Hello World!";
#[no_mangle]
pub extern "C" fn _start() -> ! {
let vga_buffer = 0xb8000 as *mut u8;
for (i, &byte) in HELLO.iter().enumerate() {
unsafe {
*vga_buffer.offset(i as isize * 2) = byte;
*vga_buffer.offset(i as isize * 2 + 1) = 0xb;
}
}
loop {}
}

BIN
xv6-book.pdf Normal file

Binary file not shown.