This commit is contained in:
Paul Pan 2023-09-06 22:51:24 +08:00
commit 4736cfcb4e
21 changed files with 519 additions and 0 deletions

2
.cargo/config.toml Normal file
View File

@ -0,0 +1,2 @@
[build]
target = "riscv64imac-unknown-none-elf"

1
.gitignore vendored Normal file
View File

@ -0,0 +1 @@
/target

91
Cargo.lock generated Normal file
View File

@ -0,0 +1,91 @@
# This file is automatically @generated by Cargo.
# It is not intended for manual editing.
version = 3
[[package]]
name = "bit_field"
version = "0.10.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "dc827186963e592360843fb5ba4b973e145841266c1357f7180c43526f2e5b61"
[[package]]
name = "bitflags"
version = "1.3.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a"
[[package]]
name = "log"
version = "0.4.20"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f"
[[package]]
name = "raw-cpuid"
version = "10.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6c297679cb867470fa8c9f67dbba74a78d78e3e98d7cf2b08d6d71540f797332"
dependencies = [
"bitflags",
]
[[package]]
name = "rustversion"
version = "1.0.14"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4"
[[package]]
name = "sbi-rt"
version = "0.0.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "8c113c53291db8ac141e01f43224ed488b8d6001ab66737b82e04695a43a42b7"
dependencies = [
"sbi-spec",
]
[[package]]
name = "sbi-spec"
version = "0.0.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6d4027cf9bb591a9fd0fc0e283be6165c5abe96cb73e9f0e24738c227f425377"
dependencies = [
"static_assertions",
]
[[package]]
name = "static_assertions"
version = "1.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f"
[[package]]
name = "tiny_os"
version = "0.1.0"
dependencies = [
"log",
"sbi-rt",
"uart_16550",
]
[[package]]
name = "uart_16550"
version = "0.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "6dc00444796f6c71f47c85397a35e9c4dbf9901902ac02386940d178e2b78687"
dependencies = [
"bitflags",
"rustversion",
"x86",
]
[[package]]
name = "x86"
version = "0.52.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2781db97787217ad2a2845c396a5efe286f87467a5810836db6d74926e94a385"
dependencies = [
"bit_field",
"bitflags",
"raw-cpuid",
]

26
Cargo.toml Normal file
View File

@ -0,0 +1,26 @@
[package]
name = "tiny_os"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[features]
default = ["arch_riscv64", "board_virt"]
arch_riscv64 = []
arch_arm = []
arch_x86 = []
board_default = []
board_virt = []
board_thead = []
[profile.dev]
panic = "abort"
[profile.release]
panic = "abort"
[dependencies]
sbi-rt = { version = "0.0.2", features = ["legacy"] }
uart_16550 = "0.3"
log = "0.4"

23
build.rs Normal file
View File

@ -0,0 +1,23 @@
fn main() {
println!("cargo:rerun-if-changed=build.rs");
struct TargetConfiguration {
target: &'static str,
lds: &'static str,
}
const TARGET_CONFIGURATIONS: &[TargetConfiguration] = &[TargetConfiguration {
target: "riscv64",
lds: "src/arch/riscv/boot/linker64.ld",
}];
let target = std::env::var("TARGET").unwrap();
for cfg in TARGET_CONFIGURATIONS {
if target.starts_with(cfg.target) {
println!("cargo:rustc-link-arg=-T{}", cfg.lds);
return;
}
}
panic!("Unsupported target: {}", target);
}

2
rust-toolchain.toml Normal file
View File

@ -0,0 +1,2 @@
[toolchain]
channel = "nightly"

72
src/arch/io.rs Normal file
View File

@ -0,0 +1,72 @@
use core::fmt::Write;
pub struct RawConsole;
pub trait Printer: Write {
fn put_char(c: char);
#[inline]
fn put_str(s: &str) {
for c in s.chars() {
Self::put_char(c);
}
}
#[inline]
fn put_line(s: &str) {
Self::put_str(s);
Self::put_char('\n');
}
fn put_num(mut num: usize) {
if num == 0 {
Self::put_char('0');
return;
}
let digits = "0123456789".as_bytes();
let mut buf = [0u8; 10];
let mut i = 0;
while num != 0 {
buf[i] = digits[num % 10];
num /= 10;
i += 1;
}
buf[..i]
.iter()
.rev()
.for_each(|c| Self::put_char(*c as char));
}
fn put_hex(mut num: usize) {
if num == 0 {
Self::put_str("0x0");
return;
}
let alphabet = "0123456789abcdef".as_bytes();
let mut buf = [0u8; 8];
let mut i = 0;
while num != 0 {
buf[i] = alphabet[num % 16];
num /= 16;
i += 1;
}
Self::put_str("0x");
buf[..i]
.iter()
.rev()
.for_each(|c| Self::put_char(*c as char));
}
}
impl Write for RawConsole {
fn write_str(&mut self, s: &str) -> core::fmt::Result {
Self::put_str(s);
Ok(())
}
}

18
src/arch/lowlevel.rs Normal file
View File

@ -0,0 +1,18 @@
pub struct Hardware;
pub trait LowLevel {
fn halt() {}
fn shutdown(_failure: bool) -> ! {
Self::halt();
#[allow(clippy::empty_loop)]
loop {}
}
fn reset(_failure: bool) -> ! {
panic!("Reset is not implemented for this architecture");
}
fn disable_interrupt() {}
}

10
src/arch/mod.rs Normal file
View File

@ -0,0 +1,10 @@
// Basic IO
pub mod io;
// Low Level
pub mod lowlevel;
// Arch Level
#[cfg(feature = "arch_riscv64")]
#[path = "riscv/mod.rs"]
mod riscv;

View File

@ -0,0 +1,3 @@
pub const UART0_BASE: usize = 0x1000_0000;
pub mod printer;

View File

@ -0,0 +1,17 @@
use crate::arch::io::{Printer, RawConsole};
impl Printer for RawConsole {
#[inline]
fn put_char(c: char) {
let uart = super::UART0_BASE as *mut char;
unsafe { uart.write_volatile(c) }
}
#[inline]
fn put_str(s: &str) {
let uart = super::UART0_BASE as *mut char;
for c in s.chars() {
unsafe { uart.write_volatile(c) }
}
}
}

View File

@ -0,0 +1,52 @@
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80200000;
MEMORY {
DRAM : ORIGIN = BASE_ADDRESS, LENGTH = 16M
}
SECTIONS {
. = BASE_ADDRESS;
.text : {
__text_start = .;
*(.text.entry)
*(.text .text.*)
__text_end = .;
} > DRAM
.rodata : {
. = ALIGN(8);
__rodata_start = .;
*(.rodata .rodata.*)
*(.srodata .srodata.*)
__rodata_end = .;
} > DRAM
.data : {
. = ALIGN(8);
__data_start = .;
*(.data .data.*)
*(.sdata .sdata.*)
__data_end = .;
} > DRAM
.stack : {
. = ALIGN(8);
*(.boot_stack)
} > DRAM
.bss : {
. = ALIGN(8);
__bss_start = .;
*(.bss .bss.*)
*(.sbss .sbss.*)
__bss_end = .;
} > DRAM
/DISCARD/ : {
*(.eh_frame)
}
}

43
src/arch/riscv/entry.rs Normal file
View File

@ -0,0 +1,43 @@
#[naked]
#[no_mangle]
#[link_section = ".text.entry"]
unsafe extern "C" fn _start(hart_id: usize, device_tree_addr: usize) -> ! {
// simplest starter
// no stack here
const STACK_SIZE: usize = 4096 * 16;
#[link_section = ".boot_stack"]
static mut STACK: [u8; STACK_SIZE] = [0u8; STACK_SIZE];
core::arch::asm!(
"la sp, {stack} + {stack_size}",
"j {main}",
stack_size = const STACK_SIZE,
stack = sym STACK,
main = sym pre_main,
options(noreturn),
)
}
extern "C" fn pre_main(hart_id: usize, device_tree_addr: usize) -> ! {
unsafe { zero_bss() }
// TODO: initialize page table
crate::entry::rust_main(hart_id, device_tree_addr);
}
extern "C" {
static mut __bss_start: u8;
static mut __bss_end: u8;
}
unsafe fn zero_bss() {
let mut cur = &mut __bss_start as *mut u8;
let end = &mut __bss_end as *mut u8;
while cur < end {
cur.write_volatile(0);
cur = cur.add(1);
}
}

10
src/arch/riscv/io.rs Normal file
View File

@ -0,0 +1,10 @@
#[allow(unused_imports)]
use crate::arch::io::{Printer, RawConsole};
#[cfg(feature = "board_default")]
impl Printer for RawConsole {
fn put_char(c: char) {
#[allow(deprecated)]
sbi_rt::legacy::console_putchar(c as usize);
}
}

View File

@ -0,0 +1,37 @@
use crate::arch::lowlevel::{Hardware, LowLevel};
use log::error;
impl LowLevel for Hardware {
#[inline]
fn halt() {
unsafe { core::arch::asm!("wfi") }
}
#[inline]
fn shutdown(failure: bool) -> ! {
Self::disable_interrupt();
if failure {
sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::SystemFailure);
} else {
sbi_rt::system_reset(sbi_rt::Shutdown, sbi_rt::NoReason);
}
loop {
// in case system_reset failed
Self::halt()
}
}
#[inline]
fn reset(failure: bool) -> ! {
if failure {
sbi_rt::system_reset(sbi_rt::ColdReboot, sbi_rt::SystemFailure);
} else {
sbi_rt::system_reset(sbi_rt::WarmReboot, sbi_rt::NoReason);
}
error!("[riscv/lowlevel] system_reset failed, shutdown instead");
Self::shutdown(true);
}
}

7
src/arch/riscv/mod.rs Normal file
View File

@ -0,0 +1,7 @@
#[cfg(feature = "board_virt")]
#[path = "board/virt/mod.rs"]
mod board;
pub mod entry;
pub mod io;
pub mod lowlevel;

30
src/entry.rs Normal file
View File

@ -0,0 +1,30 @@
use crate::arch::lowlevel::{Hardware, LowLevel};
use log::{error, info};
pub extern "C" fn rust_main(hart_id: usize, device_tree_addr: usize) -> ! {
crate::logging::init();
info!("[rust_main] Kernel Started");
info!("Hello World!");
info!("hart_id = {}", hart_id);
info!("device_tree_addr = {:#x}", device_tree_addr);
// TODO: setup and start scheduler
error!("[rust_main] Should not reach here! Maybe scheduler is not working?");
Hardware::shutdown(true);
}
pub fn print_hello() {
const SERIAL_PORT_BASE_ADDRESS: usize = 0x1000_0000;
const HELLO: &[u8] = b"Hello World!\n";
use uart_16550::MmioSerialPort;
let mut serial_port = unsafe { MmioSerialPort::new(SERIAL_PORT_BASE_ADDRESS) };
serial_port.init();
for &byte in HELLO {
serial_port.send(byte);
}
}

21
src/lang.rs Normal file
View File

@ -0,0 +1,21 @@
use crate::arch::lowlevel::{Hardware, LowLevel};
use core::panic::PanicInfo;
use log::error;
#[panic_handler]
fn panic(info: &PanicInfo) -> ! {
error!("[lang] Kernel panic!");
if let Some(location) = info.location() {
error!(
"[lang] Panicked: [{}:{}] {}",
location.file(),
location.line(),
info.message().unwrap(),
);
} else {
error!("[lang] Panicked: {}", info.message().unwrap());
}
Hardware::shutdown(true);
}

17
src/lib.rs Normal file
View File

@ -0,0 +1,17 @@
#![no_std]
#![feature(asm_const)]
#![feature(naked_functions)]
#![feature(panic_info_message)]
#![feature(fmt_internals)]
// arch
pub mod arch;
// rust language runtime
pub mod lang;
// entrypoint
pub mod entry;
// logging
pub mod logging;

31
src/logging.rs Normal file
View File

@ -0,0 +1,31 @@
use crate::arch::io::RawConsole;
use core::fmt::Write;
use log::{self, LevelFilter, Log, Metadata, Record};
struct SimpleLogger;
impl Log for SimpleLogger {
fn enabled(&self, _metadata: &Metadata) -> bool {
true
}
fn log(&self, record: &Record) {
if !self.enabled(record.metadata()) {
return;
}
RawConsole
.write_fmt(format_args!("[{}] {}\n", record.level(), record.args()))
.unwrap();
}
fn flush(&self) {}
}
pub fn init() {
static LOGGER: SimpleLogger = SimpleLogger;
log::set_logger(&LOGGER).unwrap();
// TODO: get log level from boot env
log::set_max_level(LevelFilter::Trace);
}

6
src/main.rs Normal file
View File

@ -0,0 +1,6 @@
#![no_std]
#![no_main]
#[allow(unused_imports)]
#[allow(clippy::single_component_path_imports)]
use tiny_os;