Renamed rust library to theseus. Replaced uartgetc() with rust implementation.
parent
8d44d9c964
commit
1ee5be8cd6
12
Makefile
12
Makefile
|
|
@ -1,8 +1,5 @@
|
||||||
K=kernel
|
K=kernel
|
||||||
U=user
|
U=user
|
||||||
R=rust
|
|
||||||
|
|
||||||
RTARGET = riscv64gc-unknown-none-elf
|
|
||||||
|
|
||||||
OBJS = \
|
OBJS = \
|
||||||
$K/entry.o \
|
$K/entry.o \
|
||||||
|
|
@ -33,8 +30,11 @@ OBJS = \
|
||||||
$K/plic.o \
|
$K/plic.o \
|
||||||
$K/virtio_disk.o
|
$K/virtio_disk.o
|
||||||
|
|
||||||
|
R = theseus
|
||||||
|
RTARGET = riscv64gc-unknown-none-elf
|
||||||
|
|
||||||
RLIBS = \
|
RLIBS = \
|
||||||
$R/foo/target/$(RTARGET)/release/libfoo.a
|
$R/target/$(RTARGET)/debug/lib$(R).a
|
||||||
|
|
||||||
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
# riscv64-unknown-elf- or riscv64-linux-gnu-
|
||||||
# perhaps in /opt/riscv/bin
|
# perhaps in /opt/riscv/bin
|
||||||
|
|
@ -145,7 +145,7 @@ fs.img: mkfs/mkfs README $(UPROGS)
|
||||||
-include kernel/*.d user/*.d
|
-include kernel/*.d user/*.d
|
||||||
|
|
||||||
rustlibs:
|
rustlibs:
|
||||||
cargo build -r --manifest-path $R/foo/Cargo.toml
|
cargo build --manifest-path $R/Cargo.toml
|
||||||
|
|
||||||
clean:
|
clean:
|
||||||
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
rm -f *.tex *.dvi *.idx *.aux *.log *.ind *.ilg \
|
||||||
|
|
@ -154,7 +154,7 @@ clean:
|
||||||
mkfs/mkfs .gdbinit \
|
mkfs/mkfs .gdbinit \
|
||||||
$U/usys.S \
|
$U/usys.S \
|
||||||
$(UPROGS)
|
$(UPROGS)
|
||||||
cargo clean --manifest-path $R/foo/Cargo.toml
|
cargo clean --manifest-path $R/Cargo.toml
|
||||||
|
|
||||||
# try to generate a unique GDB port
|
# try to generate a unique GDB port
|
||||||
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
GDBPORT = $(shell expr `id -u` % 5000 + 25000)
|
||||||
|
|
|
||||||
|
|
@ -3,7 +3,6 @@
|
||||||
#include "memlayout.h"
|
#include "memlayout.h"
|
||||||
#include "riscv.h"
|
#include "riscv.h"
|
||||||
#include "defs.h"
|
#include "defs.h"
|
||||||
#include "rust.h"
|
|
||||||
|
|
||||||
volatile static int started = 0;
|
volatile static int started = 0;
|
||||||
|
|
||||||
|
|
@ -15,8 +14,6 @@ void main() {
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("xv6 kernel is booting\n");
|
printf("xv6 kernel is booting\n");
|
||||||
printf("\n");
|
printf("\n");
|
||||||
printf("rust library call: add(1, 2) = %d\n", add(1, 2));
|
|
||||||
printf("\n");
|
|
||||||
kinit(); // physical page allocator
|
kinit(); // physical page allocator
|
||||||
kvminit(); // create kernel page table
|
kvminit(); // create kernel page table
|
||||||
kvminithart(); // turn on paging
|
kvminithart(); // turn on paging
|
||||||
|
|
|
||||||
|
|
@ -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
|
// handle a uart interrupt, raised because input has
|
||||||
// arrived, or the uart is ready for more output, or
|
// arrived, or the uart is ready for more output, or
|
||||||
// both. called from devintr().
|
// both. called from devintr().
|
||||||
|
|
|
||||||
|
|
@ -3,5 +3,5 @@
|
||||||
version = 3
|
version = 3
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "foo"
|
name = "theseus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
[package]
|
[package]
|
||||||
name = "foo"
|
name = "theseus"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
edition = "2021"
|
edition = "2021"
|
||||||
|
|
||||||
|
|
@ -9,6 +9,4 @@ crate-type = [ "staticlib" ]
|
||||||
[profile.release]
|
[profile.release]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|
||||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
|
||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
|
|
@ -1,10 +1,9 @@
|
||||||
#![no_std]
|
#![no_std]
|
||||||
#![crate_type = "staticlib"]
|
#![crate_type = "staticlib"]
|
||||||
|
|
||||||
#[no_mangle]
|
pub mod memlayout;
|
||||||
pub extern "C" fn add(left: i32, right: i32) -> i32 {
|
pub mod riscv;
|
||||||
left + right
|
pub mod uart;
|
||||||
}
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
|
|
@ -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;
|
||||||
|
|
@ -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);
|
||||||
|
|
@ -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<u8>
|
||||||
|
pub unsafe extern "C" fn uartgetc() -> i32 {
|
||||||
|
if ReadReg(LSR) & 0x01 != 0 {
|
||||||
|
ReadReg(RHR) as i32
|
||||||
|
} else {
|
||||||
|
-1
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue