From 1ee5be8cd6be7f9182f0d3b0b68318ff37d06c1f Mon Sep 17 00:00:00 2001 From: hheik <4469778+hheik@users.noreply.github.com> Date: Tue, 30 Apr 2024 17:41:56 +0300 Subject: [PATCH] Renamed rust library to theseus. Replaced uartgetc() with rust implementation. --- Makefile | 12 ++-- kernel/main.c | 3 - kernel/uart.c | 11 ---- {rust/foo => theseus}/.gitignore | 0 {rust/foo => theseus}/Cargo.lock | 2 +- {rust/foo => theseus}/Cargo.toml | 4 +- {rust/foo => theseus}/src/lib.rs | 7 +-- theseus/src/memlayout.rs | 94 ++++++++++++++++++++++++++++++++ theseus/src/riscv.rs | 50 +++++++++++++++++ theseus/src/uart.rs | 70 ++++++++++++++++++++++++ 10 files changed, 225 insertions(+), 28 deletions(-) rename {rust/foo => theseus}/.gitignore (100%) rename {rust/foo => theseus}/Cargo.lock (88%) rename {rust/foo => theseus}/Cargo.toml (54%) rename {rust/foo => theseus}/src/lib.rs (61%) create mode 100644 theseus/src/memlayout.rs create mode 100644 theseus/src/riscv.rs create mode 100644 theseus/src/uart.rs diff --git a/Makefile b/Makefile index e4383e7..85a8333 100644 --- a/Makefile +++ b/Makefile @@ -1,8 +1,5 @@ K=kernel U=user -R=rust - -RTARGET = riscv64gc-unknown-none-elf OBJS = \ $K/entry.o \ @@ -33,8 +30,11 @@ OBJS = \ $K/plic.o \ $K/virtio_disk.o +R = theseus +RTARGET = riscv64gc-unknown-none-elf + RLIBS = \ - $R/foo/target/$(RTARGET)/release/libfoo.a + $R/target/$(RTARGET)/debug/lib$(R).a # riscv64-unknown-elf- or riscv64-linux-gnu- # perhaps in /opt/riscv/bin @@ -145,7 +145,7 @@ fs.img: mkfs/mkfs README $(UPROGS) -include kernel/*.d user/*.d rustlibs: - cargo build -r --manifest-path $R/foo/Cargo.toml + cargo build --manifest-path $R/Cargo.toml clean: rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \ @@ -154,7 +154,7 @@ clean: mkfs/mkfs .gdbinit \ $U/usys.S \ $(UPROGS) - cargo clean --manifest-path $R/foo/Cargo.toml + cargo clean --manifest-path $R/Cargo.toml # try to generate a unique GDB port GDBPORT = $(shell expr `id -u` % 5000 + 25000) diff --git a/kernel/main.c b/kernel/main.c index 09adc5e..cab0e2a 100644 --- a/kernel/main.c +++ b/kernel/main.c @@ -3,7 +3,6 @@ #include "memlayout.h" #include "riscv.h" #include "defs.h" -#include "rust.h" volatile static int started = 0; @@ -15,8 +14,6 @@ void main() { printf("\n"); printf("xv6 kernel is booting\n"); printf("\n"); - printf("rust library call: add(1, 2) = %d\n", add(1, 2)); - printf("\n"); kinit(); // physical page allocator kvminit(); // create kernel page table kvminithart(); // turn on paging diff --git a/kernel/uart.c b/kernel/uart.c index 5ad60c9..8056142 100644 --- a/kernel/uart.c +++ b/kernel/uart.c @@ -147,17 +147,6 @@ void uartstart() { } } -// read one input character from the UART. -// return -1 if none is waiting. -int uartgetc(void) { - if (ReadReg(LSR) & 0x01) { - // input data is ready. - return ReadReg(RHR); - } else { - return -1; - } -} - // handle a uart interrupt, raised because input has // arrived, or the uart is ready for more output, or // both. called from devintr(). diff --git a/rust/foo/.gitignore b/theseus/.gitignore similarity index 100% rename from rust/foo/.gitignore rename to theseus/.gitignore diff --git a/rust/foo/Cargo.lock b/theseus/Cargo.lock similarity index 88% rename from rust/foo/Cargo.lock rename to theseus/Cargo.lock index 0e5399e..cf79c5f 100644 --- a/rust/foo/Cargo.lock +++ b/theseus/Cargo.lock @@ -3,5 +3,5 @@ version = 3 [[package]] -name = "foo" +name = "theseus" version = "0.1.0" diff --git a/rust/foo/Cargo.toml b/theseus/Cargo.toml similarity index 54% rename from rust/foo/Cargo.toml rename to theseus/Cargo.toml index fe36c4f..412e968 100644 --- a/rust/foo/Cargo.toml +++ b/theseus/Cargo.toml @@ -1,5 +1,5 @@ [package] -name = "foo" +name = "theseus" version = "0.1.0" edition = "2021" @@ -9,6 +9,4 @@ crate-type = [ "staticlib" ] [profile.release] panic = "abort" -# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html - [dependencies] diff --git a/rust/foo/src/lib.rs b/theseus/src/lib.rs similarity index 61% rename from rust/foo/src/lib.rs rename to theseus/src/lib.rs index d635dc8..d3275d5 100644 --- a/rust/foo/src/lib.rs +++ b/theseus/src/lib.rs @@ -1,10 +1,9 @@ #![no_std] #![crate_type = "staticlib"] -#[no_mangle] -pub extern "C" fn add(left: i32, right: i32) -> i32 { - left + right -} +pub mod memlayout; +pub mod riscv; +pub mod uart; #[panic_handler] #[no_mangle] diff --git a/theseus/src/memlayout.rs b/theseus/src/memlayout.rs new file mode 100644 index 0000000..114ca5d --- /dev/null +++ b/theseus/src/memlayout.rs @@ -0,0 +1,94 @@ +use crate::riscv::{MAXVA, PGSIZE}; + +// Physical memory layout + +// qemu -machine virt is set up like this, +// based on qemu's hw/riscv/virt.c: +// +// 00001000 -- boot ROM, provided by qemu +// 02000000 -- CLINT +// 0C000000 -- PLIC +// 10000000 -- uart0 +// 10001000 -- virtio disk +// 80000000 -- boot ROM jumps here in machine mode +// -kernel loads the kernel here +// unused RAM after 80000000. + +// the kernel uses physical memory thus: +// 80000000 -- entry.S, then kernel text and data +// end -- start of kernel page allocation area +// PHYSTOP -- end RAM used by the kernel + +// qemu puts UART registers here in physical memory. +pub const UART0: u64 = 0x10000000; +pub const UART0_IRQ: i32 = 10; + +// virtio mmio interface +pub const VIRTIO0: i32 = 0x10001000; +pub const VIRTIO0_IRQ: i32 = 1; + +// core local interruptor (CLINT), which contains the timer. +pub const CLINT: i64 = 0x2000000; +// const CLINT_MTIMECMP(hartid) (CLINT + 0x4000 + 8 * (hartid)); +#[inline] +pub fn CLINT_MTIMECMP(hartid: i32) -> i64 { + CLINT + 0x4000 + 8 * hartid as i64 +} +pub const CLINT_MTIME: i64 = CLINT + 0xBFF8; // cycles since boot. + +// qemu puts platform-level interrupt controller (PLIC) here. +pub const PLIC: i64 = 0x0c000000; +pub const PLIC_PRIORITY: i64 = PLIC + 0x0; +pub const PLIC_PENDING: i64 = PLIC + 0x1000; +#[inline] +pub fn PLIC_MENABLE(hart: i32) -> i64 { + PLIC + 0x2000 + hart as i64 * 0x100 +} +#[inline] +pub fn PLIC_SENABLE(hart: i32) -> i64 { + PLIC + 0x2080 + hart as i64 * 0x100 +} +#[inline] +pub fn PLIC_MPRIORITY(hart: i32) -> i64 { + PLIC + 0x200000 + hart as i64 * 0x2000 +} +#[inline] +pub fn PLIC_SPRIORITY(hart: i32) -> i64 { + PLIC + 0x201000 + hart as i64 * 0x2000 +} +#[inline] +pub fn PLIC_MCLAIM(hart: i32) -> i64 { + PLIC + 0x200004 + hart as i64 * 0x2000 +} +#[inline] +pub fn PLIC_SCLAIM(hart: i32) -> i64 { + PLIC + 0x201004 + hart as i64 * 0x2000 +} + +// the kernel expects there to be RAM +// for use by the kernel and user pages +// from physical address 0x80000000 to PHYSTOP. +pub const KERNBASE: i64 = 0x80000000; +pub const PHYSTOP: i64 = KERNBASE + 128 * 1024 * 1024; + +// map the trampoline page to the highest address, +// in both user and kernel space. +pub const TRAMPOLINE: u64 = MAXVA - PGSIZE; + +// map kernel stacks beneath the trampoline, +// each surrounded by invalid guard pages. +#[inline] +pub fn KSTACK(p: i32) -> u64 { + TRAMPOLINE - (p as u64 + 1) * 2 * PGSIZE +} + +// User memory layout. +// Address zero first: +// text +// original data and bss +// fixed-size stack +// expandable heap +// ... +// TRAPFRAME (p->trapframe, used by the trampoline) +// TRAMPOLINE (the same page as in the kernel) +pub const TRAPFRAME: u64 = TRAMPOLINE - PGSIZE; diff --git a/theseus/src/riscv.rs b/theseus/src/riscv.rs new file mode 100644 index 0000000..4a16823 --- /dev/null +++ b/theseus/src/riscv.rs @@ -0,0 +1,50 @@ +pub const PGSIZE: u64 = 4096; // bytes per page +pub const PGSHIFT: i32 = 12; // bits of offset within a page + +#[inline] +pub fn PGROUNDUP(sz: u64) -> u64 { + (sz + PGSIZE as u64 - 1) & !(PGSIZE as u64 - 1) +} +#[inline] +pub fn PGROUNDDOWN(a: u64) -> u64 { + a & !(PGSIZE as u64 - 1) +} + +pub const PTE_V: i64 = 1 << 0; // valid +pub const PTE_R: i64 = 1 << 1; +pub const PTE_W: i64 = 1 << 2; +pub const PTE_X: i64 = 1 << 3; +pub const PTE_U: i64 = 1 << 4; // user can access + +// shift a physical address to the right place for a PTE. +#[inline] +pub fn PA2PTE(pa: u64) -> u64 { + (pa >> 12) << 10 +} + +#[inline] +pub fn PTE2PA(pte: u64) -> u64 { + (pte >> 10) << 12 +} + +#[inline] +pub fn PTE_FLAGS(pte: u64) -> u64 { + pte & 0x3FF +} + +// extract the three 9-bit page table indices from a virtual address. +const PXMASK: i32 = 0x1FF; // 9 bits +#[inline] +pub fn PXSHIFT(level: u64) -> u64 { + PGSHIFT as u64 + (9 * level) +} +#[inline] +pub fn PX(level: u64, va: u64) -> u64 { + (va >> PXSHIFT(level)) & PXMASK as u64 +} + +// one beyond the highest possible virtual address. +// MAXVA is actually one bit less than the max allowed by +// Sv39, to avoid having to sign-extend virtual addresses +// that have the high bit set. +pub const MAXVA: u64 = 1 << (9 + 9 + 9 + 12 - 1); diff --git a/theseus/src/uart.rs b/theseus/src/uart.rs new file mode 100644 index 0000000..81116cc --- /dev/null +++ b/theseus/src/uart.rs @@ -0,0 +1,70 @@ +use crate::memlayout::UART0; + +// the UART control registers are memory-mapped +// at address UART0. this macro returns the +// address of one of the registers. +#[inline] +pub fn Reg(reg: u8) -> *mut u8 { + (UART0 + reg as u64) as *mut u8 +} + +// the UART control registers. +// some have different meanings for +// read vs write. +// see http://byterunner.com/16550.html +const RHR: u8 = 0; // receive holding register (for input bytes) +const THR: u8 = 0; // transmit holding register (for output bytes) +const IER: u8 = 1; // interrupt enable register +const IER_RX_ENABLE: u8 = 1 << 0; +const IER_TX_ENABLE: u8 = 1 << 1; +const FCR: u8 = 2; // FIFO control register +const FCR_FIFO_ENABLE: u8 = 1 << 0; +const FCR_FIFO_CLEAR: u8 = 3 << 1; // clear the content of the two FIFOs +const ISR: u8 = 2; // interrupt status register +const LCR: u8 = 3; // line control register +const LCR_EIGHT_BITS: u8 = 3 << 0; +const LCR_BAUD_LATCH: u8 = 1 << 7; // special mode to set baud rate +const LSR: u8 = 5; // line status register +const LSR_RX_READY: u8 = 1 << 0; // input is waiting to be read from RHR +const LSR_TX_IDLE: u8 = 1 << 5; // THR can accept another character to send + +#[inline] +pub fn ReadReg(reg: u8) -> u8 { + unsafe { *Reg(reg) } +} +#[inline] +pub fn WriteReg(reg: u8, v: u8) { + unsafe { *Reg(reg) = v } +} + +// the transmit output buffer. +// static mut uart_tx_lock: crate::spinlock::SpinLock = crate::spinlock::SpinLock { locked: false }; + +const UART_TX_BUF_SIZE: usize = 32; +static mut uart_tx_buf: [u8; UART_TX_BUF_SIZE] = [0; UART_TX_BUF_SIZE]; +static mut uart_tx_w: u64 = 0; // write next to uart_tx_buf[uart_tx_w % UART_TX_BUF_SIZE] +static mut uart_tx_r: u64 = 0; // read next from uart_tx_buf[uart_tx_r % UART_TX_BUF_SIZE] + +static mut panicked: i32 = 0; + +// #[no_mangle] +// pub extern "C" fn uartinit() {} + +// #[no_mangle] +// pub extern "C" fn uartintr() {} + +// #[no_mangle] +// pub extern "C" fn uartputc(c: i32) {} + +// #[no_mangle] +// pub extern "C" fn uartputc_sync(c: i32) {} + +#[no_mangle] +// TODO: Convert to Option +pub unsafe extern "C" fn uartgetc() -> i32 { + if ReadReg(LSR) & 0x01 != 0 { + ReadReg(RHR) as i32 + } else { + -1 + } +}