Merge remote-tracking branch 'origin/master' into dev

toolchain_update
Jiajie Chen 6 years ago
commit 41dab25f9c

4
.gitignore vendored

@ -1,6 +1,8 @@
build build
target target
/kernel/src/arch/x86_64/interrupt/vector.asm /kernel/src/arch/x86_64/interrupt/vector.asm
*.gen.s
*.dtb
Cargo.lock Cargo.lock
!kernel/Cargo.lock !kernel/Cargo.lock
@ -11,3 +13,5 @@ Cargo.lock
# for eclipse # for eclipse
.project .project
.vscode

@ -28,6 +28,7 @@ env:
- ARCH="riscv32" - ARCH="riscv32"
- ARCH="x86_64" - ARCH="x86_64"
- ARCH="aarch64" - ARCH="aarch64"
- ARCH="mipsel" OPTS="board=malta"
matrix: matrix:
allow_failures: allow_failures:
@ -45,10 +46,10 @@ install:
if [ $TRAVIS_OS_NAME = linux ]; then if [ $TRAVIS_OS_NAME = linux ]; then
export FILE="gcc-arm-8.2-2018.11-x86_64-aarch64-elf"; export FILE="gcc-arm-8.2-2018.11-x86_64-aarch64-elf";
wget https://developer.arm.com/-/media/Files/downloads/gnu-a/8.2-2018.11/$FILE.tar.xz; wget https://developer.arm.com/-/media/Files/downloads/gnu-a/8.2-2018.11/$FILE.tar.xz;
tar -xvf $FILE.tar.xz; tar -xf $FILE.tar.xz;
export PATH=$PATH:$PWD/$FILE/bin; export PATH=$PATH:$PWD/$FILE/bin;
wget https://musl.cc/aarch64-linux-musl-cross.tgz; wget https://musl.cc/aarch64-linux-musl-cross.tgz;
tar -xvf aarch64-linux-musl-cross.tgz; tar -xf aarch64-linux-musl-cross.tgz;
export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin; export PATH=$PATH:$PWD/aarch64-linux-musl-cross/bin;
elif [ $TRAVIS_OS_NAME = osx ]; then elif [ $TRAVIS_OS_NAME = osx ]; then
brew tap SergioBenitez/osxct; brew tap SergioBenitez/osxct;
@ -60,16 +61,16 @@ install:
sudo apt update; sudo apt update;
sudo apt install linux-headers-$(uname -r); sudo apt install linux-headers-$(uname -r);
wget https://musl.cc/x86_64-linux-musl-cross.tgz; wget https://musl.cc/x86_64-linux-musl-cross.tgz;
tar -xvf x86_64-linux-musl-cross.tgz; tar -xf x86_64-linux-musl-cross.tgz;
export PATH=$PATH:$PWD/x86_64-linux-musl-cross/bin; export PATH=$PATH:$PWD/x86_64-linux-musl-cross/bin;
fi; fi;
fi fi
- if [ $TRAVIS_OS_NAME = linux ]; then - if [ $TRAVIS_OS_NAME = linux ]; then
wget https://download.qemu.org/qemu-3.1.0.tar.xz && tar xvJf qemu-3.1.0.tar.xz > /dev/null && cd qemu-3.1.0 && ./configure --target-list=$ARCH-softmmu && make && cd ..; wget https://download.qemu.org/qemu-3.1.0.tar.xz && tar xJf qemu-3.1.0.tar.xz > /dev/null && cd qemu-3.1.0 && ./configure --target-list=$ARCH-softmmu && make && cd ..;
export PATH=$PATH:$PWD/qemu-3.1.0/$ARCH-softmmu:$PWD/qemu-3.1.0; export PATH=$PATH:$PWD/qemu-3.1.0/$ARCH-softmmu:$PWD/qemu-3.1.0;
sudo apt update; sudo apt update;
sudo apt install libfuse-dev; sudo apt install libfuse-dev device-tree-compiler -y;
fi fi
- if [ $ARCH = riscv32 ]; then - if [ $ARCH = riscv32 ]; then
@ -77,7 +78,7 @@ install:
sudo apt update; sudo apt update;
sudo apt install linux-headers-$(uname -r); sudo apt install linux-headers-$(uname -r);
wget https://musl.cc/riscv32-linux-musl-cross.tgz; wget https://musl.cc/riscv32-linux-musl-cross.tgz;
tar -xvf riscv32-linux-musl-cross.tgz; tar -xf riscv32-linux-musl-cross.tgz;
export PATH=$PATH:$PWD/riscv32-linux-musl-cross/bin; export PATH=$PATH:$PWD/riscv32-linux-musl-cross/bin;
fi; fi;
fi fi
@ -86,10 +87,19 @@ install:
sudo apt update; sudo apt update;
sudo apt install linux-headers-$(uname -r); sudo apt install linux-headers-$(uname -r);
wget https://musl.cc/riscv64-linux-musl-cross.tgz; wget https://musl.cc/riscv64-linux-musl-cross.tgz;
tar -xvf riscv64-linux-musl-cross.tgz; tar -xf riscv64-linux-musl-cross.tgz;
export PATH=$PATH:$PWD/riscv64-linux-musl-cross/bin; export PATH=$PATH:$PWD/riscv64-linux-musl-cross/bin;
fi; fi;
fi fi
- if [ $ARCH = mipsel ]; then
if [ $TRAVIS_OS_NAME = linux ]; then
sudo apt update;
sudo apt install linux-headers-$(uname -r);
wget https://musl.cc/mipsel-linux-musln32-cross.tgz;
tar -xf mipsel-linux-musln32-cross.tgz;
export PATH=$PATH:$PWD/mipsel-linux-musln32-cross/bin;
fi;
fi
before_script: before_script:

@ -13,6 +13,8 @@ else ifeq ($(arch), riscv32)
prefix := riscv64-unknown-elf- prefix := riscv64-unknown-elf-
else ifeq ($(arch), riscv64) else ifeq ($(arch), riscv64)
prefix := riscv64-unknown-elf- prefix := riscv64-unknown-elf-
else ifeq ($(arch), mipsel)
prefix := mipsel-linux-gnu-
else ifeq ($(arch), aarch64) else ifeq ($(arch), aarch64)
prefix ?= aarch64-none-elf- prefix ?= aarch64-none-elf-
ifeq (,$(shell which $(prefix)ld)) ifeq (,$(shell which $(prefix)ld))
@ -30,6 +32,7 @@ strip := $(prefix)strip
export CC = $(cc) export CC = $(cc)
export PAYLOAD = $(payload) export PAYLOAD = $(payload)
export DTB = $(dtb)
build_args := --target=targets/$(arch).json build_args := --target=targets/$(arch).json
ifeq ($(mode), release) ifeq ($(mode), release)

@ -10,14 +10,22 @@ fn main() {
} }
} }
/// include payload and dtb in sections of asm
fn gen_payload_asm() -> Result<std::path::PathBuf> { fn gen_payload_asm() -> Result<std::path::PathBuf> {
let out_dir = std::env::var("OUT_DIR").unwrap(); let out_dir = std::env::var("OUT_DIR").unwrap();
let payload = std::env::var("PAYLOAD").unwrap(); let payload = std::env::var("PAYLOAD").unwrap();
let dtb = std::env::var("DTB").unwrap();
if !Path::new(&payload).is_file() { if !Path::new(&payload).is_file() {
panic!("Kernel payload `{}` not found", payload) panic!("Kernel payload `{}` not found", payload)
} }
let mut has_dtb = true;
if !Path::new(&dtb).is_file() {
has_dtb = false;
}
let file_path = Path::new(&out_dir).join("payload.S"); let file_path = Path::new(&out_dir).join("payload.S");
let mut f = File::create(&file_path).unwrap(); let mut f = File::create(&file_path).unwrap();
@ -31,10 +39,24 @@ fn gen_payload_asm() -> Result<std::path::PathBuf> {
_kernel_payload_start: _kernel_payload_start:
.incbin "{}" .incbin "{}"
_kernel_payload_end: _kernel_payload_end:
"#, payload)?; "#, payload)?;
println!("cargo:rerun-if-changed={}", payload); println!("cargo:rerun-if-changed={}", payload);
println!("cargo:rerun-if-env-changed=PAYLOAD"); println!("cargo:rerun-if-env-changed=PAYLOAD");
if has_dtb {
write!(f, r#"
.section .dtb,"a"
.align 12
.global _dtb_start, _dtb_end
_dtb_start:
.incbin "{}"
_dtb_end:
"#, dtb)?;
println!("{:x?} {:x?}", dtb, file_path);
println!("cargo:rerun-if-changed={}", dtb);
println!("cargo:rerun-if-env-changed=DTB");
}
Ok(file_path) Ok(file_path)
} }

@ -0,0 +1,20 @@
.section .text.boot
.globl _start
_start:
# read cpu affinity, start core 0, halt the rest
mfc0 $8, $15, 1
beqz $8, setup
andi $8, $8, 0x3ff # use bits 11 ~ 0
halt:
# core affinity != 0, halt it
b halt
nop
setup:
# put the bootstack at 8MB offset of physical mem
la $29, 0x80800000 # $sp
la $28, _gp # $gp
b boot_main
nop

@ -0,0 +1,41 @@
ENTRY(_start)
SECTIONS {
/* MIPS entry point after cold reset */
. = 0xBFC00000;
.text : {
KEEP(*(.text.boot)) /* from boot.S */
*(.text .text.* .gnu.linkonce.t*)
. = ALIGN(4K);
}
.rodata : {
*(.rodata .rodata.* .gnu.linkonce.r*)
. = ALIGN(4K);
}
.data : {
*(.data .data.* .gnu.linkonce.d*)
. = ALIGN(4K);
}
.bss : {
_sbss = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(4K);
_ebss = .;
}
.payload : {
*(.payload)
}
.dtb : {
*(.dtb)
}
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }
}

@ -0,0 +1,34 @@
use core::ptr;
use fixedvec::FixedVec;
use xmas_elf::program::{ProgramHeader32, Type};
const KERNEL_OFFSET: u32 = 0x80000000;
global_asm!(include_str!("boot.S"));
pub fn copy_kernel(kernel_start: usize, segments: &FixedVec<ProgramHeader32>) {
// reverse program headers to avoid overlapping in memory copying
let mut space = alloc_stack!([ProgramHeader32; 32]);
let mut rev_segments = FixedVec::new(&mut space);
for i in (0..segments.len()).rev() {
rev_segments.push(segments[i]).unwrap();
}
for segment in &rev_segments {
if segment.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = segment.virtual_addr;
let offset = segment.offset;
let file_size = segment.file_size;
let mem_size = segment.mem_size;
unsafe {
let src = (kernel_start as u32 + offset) as *const u8;
let dst = virt_addr.wrapping_sub(KERNEL_OFFSET) as *mut u8;
ptr::copy(src, dst, file_size as usize);
ptr::write_bytes(dst.offset(file_size as isize), 0, (mem_size - file_size) as usize);
}
}
}

@ -12,13 +12,18 @@ use core::slice;
use fixedvec::FixedVec; use fixedvec::FixedVec;
use xmas_elf::{ use xmas_elf::{
header, header,
program::{ProgramHeader, ProgramHeader64}, program::{ProgramHeader, ProgramHeader32, ProgramHeader64},
ElfFile, ElfFile,
}; };
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
#[path = "arch/aarch64/mod.rs"] #[path = "arch/aarch64/mod.rs"]
pub mod arch; pub mod arch;
#[cfg(target_arch = "mips")]
#[path = "arch/mipsel/mod.rs"]
pub mod arch;
pub mod lang_items; pub mod lang_items;
extern "C" { extern "C" {
@ -26,8 +31,15 @@ extern "C" {
fn _kernel_payload_end(); fn _kernel_payload_end();
} }
#[cfg(target_arch = "mips")]
extern "C" {
fn _dtb_start();
fn _dtb_end();
}
/// The entry point of bootloader /// The entry point of bootloader
#[no_mangle] // don't mangle the name of this function #[cfg(target_arch = "aarch64")]
#[no_mangle]
pub extern "C" fn boot_main() -> ! { pub extern "C" fn boot_main() -> ! {
let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize; let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize;
let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) }; let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) };
@ -54,3 +66,33 @@ pub extern "C" fn boot_main() -> ! {
loop {} loop {}
} }
#[cfg(target_arch = "mips")]
#[no_mangle]
pub extern "C" fn boot_main() -> ! {
let kernel_size = _kernel_payload_end as usize - _kernel_payload_start as usize;
let kernel = unsafe { slice::from_raw_parts(_kernel_payload_start as *const u8, kernel_size) };
let kernel_elf = ElfFile::new(kernel).unwrap();
header::sanity_check(&kernel_elf).unwrap();
let mut preallocated_space = alloc_stack!([ProgramHeader32; 32]);
let mut segments = FixedVec::new(&mut preallocated_space);
for program_header in kernel_elf.program_iter() {
match program_header {
ProgramHeader::Ph32(header) => segments
.push(*header)
.expect("does not support more than 32 program segments"),
ProgramHeader::Ph64(_) => panic!("does not support 64 bit elf files"),
}
}
let entry = kernel_elf.header.pt2.entry_point() as u32;
let kernel_main: extern "C" fn(dtb: usize) = unsafe { transmute(entry) };
arch::copy_kernel(_kernel_payload_start as usize, &segments);
kernel_main(_dtb_start as usize);
loop {}
}

@ -0,0 +1,36 @@
{
"arch": "mips",
"cpu": "mips32r2",
"llvm-target": "mipsel-unknown-none",
"data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"features": "+mips32r2",
"max-atomic-width": "32",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": [
"-Tsrc/arch/mipsel/boot.ld"
]
},
"executables": true,
"panic-strategy": "abort",
"relocation-model": "static",
"abi-blacklist": [
"cdecl",
"stdcall",
"fastcall",
"vectorcall",
"thiscall",
"aapcs",
"win64",
"sysv64",
"ptx-kernel",
"msp430-interrupt",
"x86-interrupt"
],
"eliminate-frame-pointer": false
}

90
kernel/Cargo.lock generated

@ -115,7 +115,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.32" version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
@ -234,6 +234,15 @@ name = "managed"
version = "0.7.1" version = "0.7.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "mips"
version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "nodrop" name = "nodrop"
version = "0.1.13" version = "0.1.13"
@ -249,6 +258,26 @@ name = "os_bootinfo"
version = "0.2.1" version = "0.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "paste"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "paste-impl"
version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)",
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "pc-keyboard" name = "pc-keyboard"
version = "0.5.0" version = "0.5.0"
@ -262,6 +291,24 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "proc-macro-hack"
version = "0.5.4"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "proc-macro2"
version = "0.4.27"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "pulldown-cmark" name = "pulldown-cmark"
version = "0.0.3" version = "0.0.3"
@ -270,6 +317,14 @@ dependencies = [
"getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)", "getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
[[package]]
name = "quote"
version = "0.6.11"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "rand" name = "rand"
version = "0.4.6" version = "0.4.6"
@ -301,7 +356,7 @@ version = "6.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)", "bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)", "rustc_version 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
] ]
@ -318,14 +373,16 @@ dependencies = [
"bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)", "bitvec 0.11.0 (git+https://github.com/myrrlyn/bitvec.git)",
"bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)", "bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)",
"buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)", "buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
"cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)", "cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)",
"console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)", "device_tree 1.0.3 (git+https://github.com/rcore-os/device_tree-rs)",
"heapless 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)", "heapless 0.4.2 (registry+https://github.com/rust-lang/crates.io-index)",
"isomorphic_drivers 0.1.0 (git+https://github.com/rcore-os/isomorphic_drivers)", "isomorphic_drivers 0.1.0 (git+https://github.com/rcore-os/isomorphic_drivers)",
"lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)", "lazy_static 1.3.0 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
"mips 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)", "once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)",
"pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)", "pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)",
"pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)", "pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)",
"raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)", "raw-cpuid 6.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -369,7 +426,7 @@ dependencies = [
[[package]] [[package]]
name = "rcore-thread" name = "rcore-thread"
version = "0.1.0" version = "0.1.0"
source = "git+https://github.com/rcore-os/rcore-thread#765ea6c7b97de4b154fd8b9b8b4678deb7d7c93b" source = "git+https://github.com/rcore-os/rcore-thread#7236bfd2e2bde673773214739695bb2925a77ae5"
dependencies = [ dependencies = [
"deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)", "deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)", "log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -467,6 +524,16 @@ name = "static_assertions"
version = "0.3.1" version = "0.3.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "syn"
version = "0.15.30"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)",
"quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)",
"unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]] [[package]]
name = "tempdir" name = "tempdir"
version = "0.3.7" version = "0.3.7"
@ -500,6 +567,11 @@ name = "unicode-width"
version = "0.1.5" version = "0.1.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "unicode-xid"
version = "0.1.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]] [[package]]
name = "usize_conversions" name = "usize_conversions"
version = "0.2.0" version = "0.2.0"
@ -609,7 +681,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>" "checksum bootloader 0.4.0 (git+https://github.com/rcore-os/bootloader)" = "<none>"
"checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595" "checksum buddy_system_allocator 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "2ed828f1e227d6e32b998d6375b67fd63ac5389d50b23f258ce151d22b6cc595"
"checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb" "checksum byteorder 1.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "a019b10a2a7cdeb292db131fc8113e57ea2a908f6e7894b0c3c671893b65dbeb"
"checksum cc 1.0.32 (registry+https://github.com/rust-lang/crates.io-index)" = "ad0daef304fa0b4238f5f7ed7178774b43b06f6a9b6509f6642bef4ff1f7b9b2" "checksum cc 1.0.31 (registry+https://github.com/rust-lang/crates.io-index)" = "c9ce8bb087aacff865633f0bd5aeaed910fe2fe55b55f4739527f2e023a2e53d"
"checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4" "checksum cfg-if 0.1.7 (registry+https://github.com/rust-lang/crates.io-index)" = "11d43355396e872eefb45ce6342e4374ed7bc2b3a502d1b28e36d6e23c05d1f4"
"checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6" "checksum console-traits 0.3.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f711b3d1d5c3f7ae7d6428901c0f3e5d5f5c800fcfac86bf0252e96373a2cec6"
"checksum deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)" = "<none>" "checksum deque 0.3.2 (git+https://github.com/rcore-os/deque.git?branch=no_std)" = "<none>"
@ -627,12 +699,18 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b" "checksum log 0.3.9 (registry+https://github.com/rust-lang/crates.io-index)" = "e19e8d5c34a3e0e2223db8e060f9e8264aeeb5c5fc64a4ee9965c062211c024b"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6" "checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6" "checksum managed 0.7.1 (registry+https://github.com/rust-lang/crates.io-index)" = "fdcec5e97041c7f0f1c5b7d93f12e57293c831c646f4cc7a5db59460c7ea8de6"
"checksum mips 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "4cbf449a63e4db77af9f662d6b42068c0925e779a3a7c70ad02f191cf1e6c802"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945" "checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
"checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73" "checksum once 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "931fb7a4cf34610cf6cbe58d52a8ca5ef4c726d4e2e178abd0dc13a6551c6d73"
"checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a" "checksum os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)" = "66481dbeb5e773e7bd85b63cd6042c30786f834338288c5ec4f3742673db360a"
"checksum paste 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "1f4a4a1c555c6505821f9d58b8779d0f630a6b7e4e1be24ba718610acf01fa79"
"checksum paste-impl 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "26e796e623b8b257215f27e6c80a5478856cae305f5b59810ff9acdaa34570e6"
"checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce" "checksum pc-keyboard 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "c48392db76c4e9a69e0b3be356c5f97ebb7b14413c5e4fd0af4755dbf86e2fce"
"checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "<none>" "checksum pci 0.0.1 (git+https://github.com/rcore-os/pci-rs)" = "<none>"
"checksum proc-macro-hack 0.5.4 (registry+https://github.com/rust-lang/crates.io-index)" = "3e90aa19cd73dedc2d0e1e8407473f073d735fef0ab521438de6da8ee449ab66"
"checksum proc-macro2 0.4.27 (registry+https://github.com/rust-lang/crates.io-index)" = "4d317f9caece796be1980837fd5cb3dfec5613ebdb04ad0956deea83ce168915"
"checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07" "checksum pulldown-cmark 0.0.3 (registry+https://github.com/rust-lang/crates.io-index)" = "8361e81576d2e02643b04950e487ec172b687180da65c731c03cf336784e6c07"
"checksum quote 0.6.11 (registry+https://github.com/rust-lang/crates.io-index)" = "cdd8e04bd9c52e0342b406469d494fcb033be4bdbe5c606016defbb1681411e1"
"checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293" "checksum rand 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "552840b97013b1a26992c11eac34bdd778e464601a4c2054b5f0bff7c6761293"
"checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b" "checksum rand_core 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "7a6fdeb83b075e8266dcc8762c22776f6877a63111121f5f8c7411e5be7eed4b"
"checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0" "checksum rand_core 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "d0e7a549d590831370895ab7ba4ea0c1b6b011d106b5ff2da6eee112615e6dc0"
@ -652,11 +730,13 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f" "checksum spin 0.4.10 (registry+https://github.com/rust-lang/crates.io-index)" = "ceac490aa12c567115b40b7b7fceca03a6c9d53d5defea066123debc83c5dc1f"
"checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55" "checksum spin 0.5.0 (registry+https://github.com/rust-lang/crates.io-index)" = "44363f6f51401c34e7be73db0db371c04705d35efbe9f7d6082e03a921a32c55"
"checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1" "checksum static_assertions 0.3.1 (registry+https://github.com/rust-lang/crates.io-index)" = "389ce475f424f267dbed6479cbd8f126c5e1afb053b0acdaa019c74305fc65d1"
"checksum syn 0.15.30 (registry+https://github.com/rust-lang/crates.io-index)" = "66c8865bf5a7cbb662d8b011950060b3c8743dca141b054bf7195b20d314d8e2"
"checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8" "checksum tempdir 0.3.7 (registry+https://github.com/rust-lang/crates.io-index)" = "15f2b5fb00ccdf689e0149d1b1b3c03fead81c2b37735d812fa8bddbbf41b6d8"
"checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316" "checksum tock-registers 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "3a385d94f3f62e60445a0adb9ff8d9621faa272234530d4c0f848ec98f88e316"
"checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169" "checksum typenum 1.10.0 (registry+https://github.com/rust-lang/crates.io-index)" = "612d636f949607bdf9b123b4a6f6d966dedf3ff669f7f045890d3a4a73948169"
"checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e" "checksum uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "269f953d8de3226f7c065c589c7b4a3e83d10a419c7c3b5e2e0f197e6acc966e"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526" "checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum unicode-xid 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)" = "fc72304796d0818e357ead4e000d19c9c174ab23dc11093ac919054d20a6a7fc"
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5" "checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
"checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f" "checksum ux 0.1.3 (registry+https://github.com/rust-lang/crates.io-index)" = "88dfeb711b61ce620c0cb6fd9f8e3e678622f0c971da2a63c4b3e25e88ed012f"
"checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29" "checksum volatile 0.2.6 (registry+https://github.com/rust-lang/crates.io-index)" = "6af0edf5b4faacc31fc51159244d78d65ec580f021afcef7bd53c04aeabc7f29"

@ -13,7 +13,9 @@ authors = [
"chenqiuhao <haohao0924@126.com>", "chenqiuhao <haohao0924@126.com>",
"maoyuchaxue <wangjt15@mails.tsinghua.edu.cn>", "maoyuchaxue <wangjt15@mails.tsinghua.edu.cn>",
"Jiajie Chen <jiegec@qq.com>", "Jiajie Chen <jiegec@qq.com>",
"chyyuu <yuchen@mail.tsinghua.edu.cn>" "chyyuu <yuchen@mail.tsinghua.edu.cn>",
"Shengqi Chen <harry-chen@outlok.com>",
"Yuhao Zhou <miskcoo@gmail.com>"
] ]
[features] [features]
@ -24,6 +26,11 @@ board_u540 = ["sv39", "link_user"]
nographic = [] nographic = []
board_raspi3 = ["bcm2837", "link_user"] board_raspi3 = ["bcm2837", "link_user"]
raspi3_use_generic_timer = ["bcm2837/use_generic_timer"] raspi3_use_generic_timer = ["bcm2837/use_generic_timer"]
# for qemu machine
board_malta = ["link_user"]
board_mipssim = ["link_user"]
# for thinpad
board_thinpad = ["link_user"]
# Hard link user program # Hard link user program
link_user = [] link_user = []
# Run cmdline instead of user shell, useful for automatic testing # Run cmdline instead of user shell, useful for automatic testing
@ -71,6 +78,10 @@ riscv = { git = "https://github.com/rcore-os/riscv", features = ["inline-asm"] }
aarch64 = { git = "https://github.com/rcore-os/aarch64" } aarch64 = { git = "https://github.com/rcore-os/aarch64" }
bcm2837 = { git = "https://github.com/rcore-os/bcm2837", optional = true } bcm2837 = { git = "https://github.com/rcore-os/bcm2837", optional = true }
[target.'cfg(target_arch = "mips")'.dependencies]
mips = "^0.2.0"
paste = "0.1"
[package.metadata.bootimage] [package.metadata.bootimage]
default-target = "targets/x86_64.json" default-target = "targets/x86_64.json"
output = "target/x86_64/bootimage.bin" output = "target/x86_64/bootimage.bin"

@ -15,7 +15,7 @@
# make clean Clean # make clean Clean
# #
# Options: # Options:
# arch = x86_64 | riscv32 | riscv64 | aarch64 # arch = x86_64 | riscv32 | riscv64 | aarch64 | mipsel
# d = int | in_asm | ... QEMU debug info # d = int | in_asm | ... QEMU debug info
# mode = debug | release # mode = debug | release
# LOG = off | error | warn | info | debug | trace # LOG = off | error | warn | info | debug | trace
@ -50,16 +50,37 @@ bootloader := $(bootloader_dir)/target/$(target)/$(mode)/rcore-bootloader
bbl_path := $(PWD)/../riscv-pk bbl_path := $(PWD)/../riscv-pk
user_dir := ../user user_dir := ../user
### export environments ### ### export environments ###
export ARCH = $(arch)
export BOARD = $(board) ifeq ($(arch), $(filter $(arch), aarch64 mipsel))
export SMP = $(smp) #link user img, so use original image
export SFSIMG = $(user_dir)/build/$(arch).img
else
export SFSIMG = $(user_dir)/build/$(arch).qcow2 export SFSIMG = $(user_dir)/build/$(arch).qcow2
endif
ifeq ($(arch), aarch64) ifeq ($(arch), aarch64)
board := raspi3 board := raspi3
export SFSIMG = $(user_dir)/build/$(arch).img need_bootloader := true
endif
# currently only mipsel architecture needs DTB linked to the kernel
ifeq ($(arch), mipsel)
dtb := src/arch/$(arch)/board/$(board)/device.dtb
endif
# mipssim does not support SMP
ifeq ($(board), mipssim)
smp := 1
endif endif
export ARCH = $(arch)
export BOARD = $(board)
export SMP = $(smp)
export DTB = $(dtb)
### qemu options ### ### qemu options ###
qemu_opts := \ qemu_opts := \
-smp cores=$(smp) -smp cores=$(smp)
@ -119,6 +140,20 @@ ifneq ($(u_boot), )
qemu_opts += \ qemu_opts += \
-sd $(bootloader) -sd $(bootloader)
endif endif
else ifeq ($(arch), mipsel)
ifeq ($(board), malta)
qemu_opts += \
-machine $(board) -device VGA \
-serial null -serial null -serial mon:stdio \
-kernel $(kernel_img)
endif
ifeq ($(board), mipssim)
qemu_opts += \
-machine $(board) \
-serial mon:stdio \
-kernel $(kernel_img)
endif
endif endif
ifdef d ifdef d
@ -172,6 +207,8 @@ else ifeq ($(arch), riscv32)
prefix := riscv64-unknown-elf- prefix := riscv64-unknown-elf-
else ifeq ($(arch), riscv64) else ifeq ($(arch), riscv64)
prefix := riscv64-unknown-elf- prefix := riscv64-unknown-elf-
else ifeq ($(arch), mipsel)
prefix ?= mipsel-linux-musln32-
else ifeq ($(arch), aarch64) else ifeq ($(arch), aarch64)
prefix ?= aarch64-none-elf- prefix ?= aarch64-none-elf-
ifeq (,$(shell which $(prefix)ld)) ifeq (,$(shell which $(prefix)ld))
@ -186,8 +223,11 @@ cc := $(prefix)gcc
as := $(prefix)as as := $(prefix)as
gdb := $(prefix)gdb gdb := $(prefix)gdb
strip := $(prefix)strip strip := $(prefix)strip
dtc := dtc
export CC = $(cc) export CC = $(cc)
hostcc := gcc
.PHONY: all clean build asm doc debug kernel sfsimg install run justrun runnet justrunnet runui justrunui runtest justruntest .PHONY: all clean build asm doc debug kernel sfsimg install run justrun runnet justrunnet runui justrunui runtest justruntest
all: kernel all: kernel
@ -235,8 +275,17 @@ header:
sym: sym:
@$(objdump) -t $(kernel) | less @$(objdump) -t $(kernel) | less
### device tree process ###
%.dtb: %.dts
@echo Generating device tree file $@
@$(dtc) -I dts -O dtb -o $@ $<
@rm -rf src/arch/${arch}/boot/dtb.gen.s
### bootloader and kernel image ###
$(bootloader): $(kernel) $(bootloader): $(kernel)
ifeq ($(arch), aarch64) ifeq ($(need_bootloader), true)
@echo Building $(arch) bootloader @echo Building $(arch) bootloader
@$(strip) $(kernel) -o $(kernel)_stripped @$(strip) $(kernel) -o $(kernel)_stripped
@cd $(bootloader_dir) && make arch=$(arch) mode=$(mode) payload=../kernel/$(kernel)_stripped @cd $(bootloader_dir) && make arch=$(arch) mode=$(mode) payload=../kernel/$(kernel)_stripped
@ -272,9 +321,12 @@ ifneq ($(u_boot), )
else else
@$(objcopy) $(bootloader) --strip-all -O binary $@ @$(objcopy) $(bootloader) --strip-all -O binary $@
endif endif
else ifeq ($(arch), mipsel)
# qemu-system-mipsel accepts ELF file only, so objcopy is not needed
@$(strip) $(kernel) -o $@
endif endif
kernel: kernel: $(dtb)
@echo Building $(arch) kernel @echo Building $(arch) kernel
ifeq ($(arch), x86_64) ifeq ($(arch), x86_64)
@bootimage build $(build_args) @bootimage build $(build_args)
@ -292,6 +344,11 @@ else ifeq ($(arch), riscv64)
@cargo xbuild $(build_args) @cargo xbuild $(build_args)
else ifeq ($(arch), aarch64) else ifeq ($(arch), aarch64)
@cargo xbuild $(build_args) @cargo xbuild $(build_args)
else ifeq ($(arch), mipsel)
@for file in context entry trap ; do \
$(hostcc) -E src/arch/$(arch)/boot/$${file}.S -o src/arch/$(arch)/boot/$${file}.gen.s ; \
done
@cargo xbuild $(build_args)
endif endif

@ -2,6 +2,7 @@ extern crate cc;
use std::fs::File; use std::fs::File;
use std::io::{Result, Write}; use std::io::{Result, Write};
use std::path::Path;
fn main() { fn main() {
println!("cargo:rerun-if-env-changed=LOG"); println!("cargo:rerun-if-env-changed=LOG");
@ -16,6 +17,9 @@ fn main() {
} }
"riscv32" => {} "riscv32" => {}
"riscv64" => {} "riscv64" => {}
"mipsel" => {
gen_dtb_asm(&arch, &board).unwrap();
}
"aarch64" => {} "aarch64" => {}
_ => panic!("Unknown arch {}", arch), _ => panic!("Unknown arch {}", arch),
} }
@ -44,3 +48,32 @@ fn gen_vector_asm() -> Result<()> {
} }
Ok(()) Ok(())
} }
fn gen_dtb_asm(arch: &String, _board: &String) -> Result<()> {
let dtb = std::env::var("DTB").unwrap();
if !Path::new(&dtb).is_file() {
panic!("DTB `{}` not found", dtb)
}
let mut f = File::create(format!("src/arch/{}/boot/dtb.gen.s", arch)).unwrap();
println!("cargo:rerun-if-changed={}", dtb);
println!("cargo:rerun-if-env-changed=DTB");
writeln!(f, "# generated by build.rs - do not edit")?;
write!(
f,
r#"
.section .dtb,"a"
.align 12
.global _dtb_start, _dtb_end
_dtb_start:
.incbin "{}"
_dtb_end:
"#,
dtb
)?;
Ok(())
}

@ -1,14 +1,18 @@
//! Raspberry PI 3 Model B/B+ //! Raspberry PI 3 Model B/B+
use alloc::string::String;
use bcm2837::atags::Atags; use bcm2837::atags::Atags;
use once::*; use once::*;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb; pub mod fb;
pub mod irq; pub mod irq;
pub mod mailbox; pub mod mailbox;
pub mod serial; pub mod serial;
pub mod timer; pub mod timer;
use fb::{ColorConfig, FramebufferInfo, FramebufferResult};
pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE; pub const IO_REMAP_BASE: usize = bcm2837::consts::IO_BASE;
pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000; pub const IO_REMAP_END: usize = bcm2837::consts::KERNEL_OFFSET + 0x4000_1000;
@ -41,3 +45,42 @@ pub fn probe_memory() -> Option<(usize, usize)> {
} }
None None
} }
pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> FramebufferResult {
let (width, height) = if width == 0 || height == 0 {
mailbox::framebuffer_get_physical_size()?
} else {
(width, height)
};
let depth = if depth == 0 {
mailbox::framebuffer_get_depth()?
} else {
depth
};
let info = mailbox::framebuffer_alloc(width, height, depth)?;
if info.bus_addr == 0 || info.screen_size == 0 {
Err(format!("mailbox call returned an invalid address/size"))?;
}
if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 {
Err(format!(
"mailbox call returned an invalid pitch value {}",
info.pitch
))?;
}
use crate::arch::memory;
let paddr = info.bus_addr & !0xC0000000;
let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb");
if vaddr == 0 {
Err(format!(
"cannot remap memory range [{:#x?}..{:#x?}]",
paddr,
paddr + info.screen_size
))?;
}
Ok((info, fb::ColorConfig::BGRA8888, vaddr))
}

@ -5,6 +5,7 @@ use once::*;
pub use self::board::fb; pub use self::board::fb;
pub use self::board::serial; pub use self::board::serial;
#[path = "../../../drivers/console/mod.rs"]
pub mod console; pub mod console;
/// Initialize ARM64 common drivers /// Initialize ARM64 common drivers

@ -0,0 +1,3 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8800_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;

@ -0,0 +1,51 @@
/dts-v1/;
/ {
model = "qemu malta";
compatible = "qemu,malta";
#address-cells = <1>;
#size-cells = <1>;
chosen {
stdio = &uart2;
bootargs = "rust/sh";
};
aliases { };
cpu_intc: interrupt-controller {
compatible = "mti,cpu-interrupt-controller";
interrupt-controller;
#interrupt-cells = <1>;
};
main_memory: memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
};
uart0: serial@b80003f8 {
compatible = "ns16550a";
reg = <0xb80003f8 0x8>;
clock-frequency = <1843200>;
};
uart2: serial@bf000900 {
compatible = "ns16550a";
reg = <0xbf000900 0x40>;
reg-shift = <3>;
clock-frequency = <1843200>;
/* The CBUS UART is attached to the MIPS CPU INT2 pin, ie interrupt 4 */
interrupt-parent = <&cpu_intc>;
interrupts = <4>;
};
nor0: flash@be000000 {
compatible = "cfi-flash";
reg = <0xbe000000 0x00400000>;
};
// TODO: add graphics and ethernet adapter
};

@ -0,0 +1,54 @@
use crate::drivers::bus::pci;
use alloc::string::String;
use mips::registers::cp0;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
pub mod consts;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
#[path = "../../../../drivers/serial/ti_16c550c.rs"]
pub mod serial;
#[path = "../../../../drivers/gpu/qemu_stdvga.rs"]
pub mod vga;
use fb::FramebufferInfo;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
// initialize serial driver
serial::init(0xbf000900);
// Enable serial interrupt
unsafe {
let mut status = cp0::status::read();
status.enable_hard_int2();
cp0::status::write(status);
}
println!("Hello QEMU Malta!");
}
/// Initialize other board drivers
pub fn init_driver() {
// TODO: add possibly more drivers
vga::init(0xbbe00000, 0xb2050000, 800, 600);
pci::init();
fb::init();
}
pub fn probe_fb_info(_width: u32, _height: u32, _depth: u32) -> fb::FramebufferResult {
let fb_info = FramebufferInfo {
xres: 800,
yres: 600,
xres_virtual: 800,
yres_virtual: 600,
xoffset: 0,
yoffset: 0,
depth: 8,
pitch: 800,
bus_addr: 0xb0000000,
screen_size: 800 * 600,
};
Ok((fb_info, fb::ColorConfig::VgaPalette, 0xb0000000))
}

@ -0,0 +1,3 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8800_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x00a0_0000;

@ -0,0 +1,36 @@
/dts-v1/;
/ {
model = "qemu mipssim";
compatible = "qemu,mipssim";
#address-cells = <1>;
#size-cells = <1>;
chosen {
stdio = &uart0;
};
aliases { };
cpu_intc: interrupt-controller {
compatible = "mti,cpu-interrupt-controller";
interrupt-controller;
#interrupt-cells = <1>;
};
main_memory: memory@0 {
device_type = "memory";
reg = <0x00000000 0x10000000>;
};
uart0: serial@bfd003f8 {
compatible = "ns16550a";
reg = <0xbfd003f8 0x8>;
clock-frequency = <1843200>;
/* attached to the MIPS CPU INT2 pin, ie interrupt 4 */
interrupt-parent = <&cpu_intc>;
interrupts = <4>;
};
};

@ -0,0 +1,27 @@
use alloc::string::String;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
pub mod consts;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
#[path = "../../../../drivers/serial/16550_reg.rs"]
pub mod serial;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
serial::init(0xbfd003f8);
println!("Hello QEMU MIPSSIM!");
}
/// Initialize other board drivers
pub fn init_driver() {
// TODO: add possibly more drivers
// timer::init();
}
pub fn probe_fb_info(_width: u32, _height: u32, _depth: u32) -> fb::FramebufferResult {
Err(String::from("Framebuffer not usable on mipssim board"))
}

@ -0,0 +1,3 @@
/// board specific constants
pub const MEMORY_END: usize = 0x8080_0000;
pub const KERNEL_HEAP_SIZE: usize = 0x0020_0000;

@ -0,0 +1,85 @@
/dts-v1/;
/ {
model = "thinpad trivialmips";
compatible = "tsinghua,thinpad";
#address-cells = <1>;
#size-cells = <1>;
chosen {
stdio = &uart;
bootargs = "";
};
aliases { };
cpu_intc: interrupt-controller {
compatible = "mti,cpu-interrupt-controller";
interrupt-controller;
#interrupt-cells = <1>;
};
memory: memory@80000000 {
device_type = "memory";
reg = <0x80000000 0x00800000>;
};
bus: trivial_bus@a0000000 {
compatible = "thinpad,bus";
reg = <0xa0000000 0x800000>;
#address-cells = <1>;
#size-cells = <1>;
ranges;
flash: flash@a1000000 {
compatible = "cfi-flash";
reg = <0xa1000000 0x00800000>;
};
framebuffer: framebuffer@a2000000 {
compatible = "thinpad,framebuffer";
reg = <0xa2000000 0x75300
0xa2075300 0x4>;
};
uart: serial@a3000000 {
compatible = "thinpad,uart";
reg = <0xa3000000 0x1
0xa3000004 0x1>;
clock-frequency = <115200>;
interrupt-parent = <&cpu_intc>;
interrupts = <1>;
};
timer: gpio@a4000000 {
compatible = "thinpad,timer";
reg = <0xa400000 0x8>;
};
eth: ethernet@a5000000 {
compatible = "davicom,dm9000";
reg = <0xa5000000 0x2
0xa5000004 0x2>;
interrupt-parent = <&cpu_intc>;
interrupts = <2>;
davicom,no-eeprom;
mac-address = [00 0a 2d 98 01 29];
};
gpio: gpio@a6000000 {
compatible = "thinpad,gpio";
reg = <0xa6000000 0x2
0xa6000004 0x2
0xa6000008 0x2>;
reg-io-width = <2>;
};
usb: usb@a7000000 {
compatible = "cypress,sl811";
reg = <0xa7000000 0x1
0xa7000004 0x1>;
};
};
};

@ -0,0 +1,42 @@
use alloc::string::String;
use once::*;
#[path = "../../../../drivers/console/mod.rs"]
pub mod console;
pub mod consts;
#[path = "../../../../drivers/gpu/fb.rs"]
pub mod fb;
#[path = "../../../../drivers/serial/simple_uart.rs"]
pub mod serial;
use fb::FramebufferInfo;
use fb::FramebufferResult;
/// Initialize serial port first
pub fn init_serial_early() {
assert_has_not_been_called!("board::init must be called only once");
serial::init(0xa3000000);
println!("Hello ThinPad!");
}
/// Initialize other board drivers
pub fn init_driver() {
// TODO: add possibly more drivers
// timer::init();
}
pub fn probe_fb_info(width: u32, height: u32, depth: u32) -> FramebufferResult {
let fb_info = FramebufferInfo {
xres: 800,
yres: 600,
xres_virtual: 800,
yres_virtual: 600,
xoffset: 0,
yoffset: 0,
depth: 8,
pitch: 800,
bus_addr: 0xa2000000,
screen_size: 800 * 600,
};
Ok((fb_info, fb::ColorConfig::RGB332, 0xa2000000))
}

@ -0,0 +1,59 @@
#include "regdef.h"
.set noat
.set noreorder
.section .text.context
.globl switch_context
.extern _root_page_table_ptr
.extern _cur_kstack_ptr
switch_context:
// save from's registers
addi sp, sp, (-4*14)
sw sp, 0(a0)
sw ra, 0(sp)
sw s0, 2*4(sp)
sw s1, 3*4(sp)
sw s2, 4*4(sp)
sw s3, 5*4(sp)
sw s4, 6*4(sp)
sw s5, 7*4(sp)
sw s6, 8*4(sp)
sw s7, 9*4(sp)
sw s8, 10*4(sp)
sw gp, 11*4(sp)
// sw ra, 12*4(sp)
// sw sp, 13*4(sp)
// save page table address
la s0, _root_page_table_ptr
lw s1, 0(s0)
sw s1, 4(sp)
// restore to's registers
lw sp, 0(a1)
lw s1, 4(sp)
sw s1, 0(s0)
// restore kstack ptr
// la s0, _cur_kstack_ptr
// addi s1, sp, 4 * 14
// sw s1, 0(s0)
lw ra, 0(sp)
lw s0, 2*4(sp)
lw s1, 3*4(sp)
lw s2, 4*4(sp)
lw s3, 5*4(sp)
lw s4, 6*4(sp)
lw s5, 7*4(sp)
lw s6, 8*4(sp)
lw s7, 9*4(sp)
lw s8, 10*4(sp)
lw gp, 11*4(sp)
addi sp, sp, (4*14)
sw zero, 0(a1)
jr ra
nop

@ -0,0 +1,40 @@
#include "regdef.h"
.set noreorder
.section .text.entry
.globl _start
.extern _root_page_table_buffer
.extern _cur_kstack_ptr
_start:
# setup stack and gp
la sp, bootstacktop
la gp, _gp
la t0, _cur_kstack_ptr
la t1, _root_page_table_buffer
sw t1, 0(t0)
# set ebase
la t0, trap_entry
mfc0 t1, $15, 1 # C0_EBASE
or t1, t1, t0
mtc0 t1, $15, 1
# exit bootstrap mode
mfc0 t0, $12 # C0_STATUS
li t1, 0xFFBFFFFF # set BEV (bit 22) to 0
and t0, t0, t1
mtc0 t0, $12
# directly jump to main function
jal rust_main
nop
.section .bss.stack
.align 12 #PGSHIFT
.global bootstack
bootstack:
.space 4096 * 16 * 8
.global bootstacktop
bootstacktop:

@ -0,0 +1,50 @@
/* Simple linker script for the ucore kernel.
See the GNU ld 'info' manual ("info ld") to learn the syntax. */
OUTPUT_ARCH(riscv)
ENTRY(_start)
BASE_ADDRESS = 0x80100000;
SECTIONS
{
. = BASE_ADDRESS;
start = .;
.text : {
stext = .;
*(.text.entry)
. = ALIGN(4K);
*(.text.ebase)
*(.text .text.*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.*)
*(.dtb)
. = ALIGN(4K);
erodata = .;
}
.data : {
sdata = .;
*(.data .data.*)
edata = .;
}
.stack : {
*(.bss.stack)
}
.bss : {
sbss = .;
*(.bss .bss.*)
ebss = .;
}
PROVIDE(end = .);
}

@ -0,0 +1,55 @@
/*
* This file is subject to the terms and conditions of the GNU General Public
* License. See the file "COPYING" in the main directory of this archive
* for more details.
*
* Copyright (C) 1985 MIPS Computer Systems, Inc.
* Copyright (C) 1994, 95, 99, 2003 by Ralf Baechle
* Copyright (C) 1990 - 1992, 1999 Silicon Graphics, Inc.
*/
#ifndef _ASM_REGDEF_H
#define _ASM_REGDEF_H
/*
* Symbolic register names for 32 bit ABI
*/
#define zero $0 /* wired zero */
#define AT $1 /* assembler temp - uppercase because of ".set at" */
#define v0 $2 /* return value */
#define v1 $3
#define a0 $4 /* argument registers */
#define a1 $5
#define a2 $6
#define a3 $7
#define t0 $8 /* caller saved */
#define t1 $9
#define t2 $10
#define t3 $11
#define t4 $12
#define t5 $13
#define t6 $14
#define t7 $15
#define s0 $16 /* callee saved */
#define s1 $17
#define s2 $18
#define s3 $19
#define s4 $20
#define s5 $21
#define s6 $22
#define s7 $23
#define t8 $24 /* caller saved */
#define t9 $25
#define jp $25 /* PIC jump register */
#define k0 $26 /* kernel scratch */
#define k1 $27
#define gp $28 /* global pointer */
#define sp $29 /* stack pointer */
#define fp $30 /* frame pointer */
#define s8 $30 /* same like fp! */
#define ra $31 /* return address */
#endif /* _ASM_REGDEF_H */

@ -0,0 +1,179 @@
#include "regdef.h"
.set noat
.set noreorder
.section .text.ebase
.globl trap_entry
.org 0x0
trap_entry:
# +0x000: TLB-miss vector
b general_trap_vec
# +0x180: general vector
.org 0x180
general_trap_vec:
move k1, sp # save stack pointer to k1
mfc0 k0, $12 # read cp0.status
andi k0, k0, 0x10 # extract cp0.status.ksu
beq k0, zero, trap_from_kernel
nop # delayslot
trap_from_user:
# load kstack, we can use k0 to store something
# la k0, kernel_stack
# la sp, kernel_stack_top
la k0, _cur_kstack_ptr
lw sp, 0(k0)
trap_from_kernel:
/*
* k0 is damaged
* k1 = old stack pointer
* sp = kernel stack */
# allocate 38 words for trapframe + 4 extra words
addiu sp, sp, -168
# save general registers
sw ra, 160(sp)
sw fp, 156(sp)
sw k1, 152(sp) # k1 = old sp
sw gp, 148(sp)
sw k1, 144(sp) # real k1 is damaged
sw k0, 140(sp) # real k0 is damaged
sw t9, 136(sp)
sw t8, 132(sp)
sw s7, 128(sp)
sw s6, 124(sp)
sw s5, 120(sp)
sw s4, 116(sp)
sw s3, 112(sp)
sw s2, 108(sp)
sw s1, 104(sp)
sw s0, 100(sp)
sw t7, 96(sp)
sw t6, 92(sp)
sw t5, 88(sp)
sw t4, 84(sp)
sw t3, 80(sp)
sw t2, 76(sp)
sw t1, 72(sp)
sw t0, 68(sp)
sw a3, 64(sp)
sw a2, 60(sp)
sw a1, 56(sp)
sw a0, 52(sp)
sw v1, 48(sp)
sw v0, 44(sp)
sw AT, 40(sp)
nop
# save hi/lo
mflo t1
sw t1, 36(sp)
mfhi t0
sw t0, 32(sp)
# save special registers
mfc0 t0, $8 # cp0.vaddr
sw t0, 28(sp)
mfc0 t1, $14 # cp0.epc
sw t1, 24(sp)
mfc0 t0, $13 # cp0.cause
sw t0, 20(sp)
mfc0 t1, $12 # cp0.status
sw t1, 16(sp)
# support nested interrupt
la t0, ~0x1b # reset status.ksu, status.exl, status.ie
and t1, t1, t0
mtc0 t1, $12 # cp0.status
# prepare to call rust_trap
ori a0, sp, 0 /* set argument (trapframe) */
jal rust_trap
nop
.globl trap_return
trap_return:
# restore special registers
lw t1, 16(sp)
ori t1, t1, 0x2 # status.exl
nop
mtc0 t1, $12 # cp0.status
lw k0, 24(sp)
mtc0 k0, $14 # cp0.epc
lw t0, 32(sp)
mthi t0
lw t1, 36(sp)
mtlo t1
# restore general registers
lw AT, 40(sp)
lw v0, 44(sp)
lw v1, 48(sp)
lw a0, 52(sp)
lw a1, 56(sp)
lw a2, 60(sp)
lw a3, 64(sp)
lw t0, 68(sp)
lw t1, 72(sp)
lw t2, 76(sp)
lw t3, 80(sp)
lw t4, 84(sp)
lw t5, 88(sp)
lw t6, 92(sp)
lw t7, 96(sp)
lw s0, 100(sp)
lw s1, 104(sp)
lw s2, 108(sp)
lw s3, 112(sp)
lw s4, 116(sp)
lw s5, 120(sp)
lw s6, 124(sp)
lw s7, 128(sp)
lw t8, 132(sp)
lw t9, 136(sp)
# lw k0, 140(sp)
# lw k1, 144(sp)
lw gp, 148(sp)
lw fp, 156(sp)
lw ra, 160(sp)
// save kernel stack
la k0, _cur_kstack_ptr
addiu k1, sp, 168
sw k1, 0(k0)
nop
// restore stack
lw sp, 152(sp)
eret
nop
.section .bss.stack
.align 12 #PGSHIFT
.global kernel_stack
kernel_stack:
.space 1024 * 16 # 16KB for kernel stack
.global kernel_stack_top
kernel_stack_top:
.align 12 #PGSHIFT
.global _root_page_table_buffer
_root_page_table_buffer:
.space 1024 * 64 # 64KB
.global _root_page_table_ptr
_root_page_table_ptr:
.space 4 # 4bytes
.global _cur_kstack_ptr
_cur_kstack_ptr:
.space 4 # 4bytes

@ -0,0 +1,8 @@
//! Workaround for missing compiler-builtin symbols
//!
//! [atomic](http://llvm.org/docs/Atomics.html#libcalls-atomic)
#[no_mangle]
pub extern "C" fn abort() {
panic!("abort");
}

@ -0,0 +1,13 @@
/// Platform specific constants
///
pub use super::board::consts::*;
pub const KERNEL_OFFSET: usize = 0x80100000;
pub const MEMORY_OFFSET: usize = 0x8000_0000;
pub const USER_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const USER_STACK_SIZE: usize = 0x10000;
pub const USER32_STACK_OFFSET: usize = 0x80000000 - USER_STACK_SIZE;
pub const MAX_DTB_SIZE: usize = 0x2000;

@ -0,0 +1,273 @@
use mips::registers::cp0;
use mips::tlb;
/// Saved registers on a trap.
#[derive(Clone)]
#[repr(C)]
pub struct TrapFrame {
/// unused 16 bytes
pub unused: [usize; 4],
/// CP0 status register
pub status: cp0::status::Status,
/// CP0 cause register
pub cause: cp0::cause::Cause,
/// CP0 EPC register
pub epc: usize,
/// CP0 vaddr register
pub vaddr: usize,
/// HI/LO registers
pub hi: usize,
pub lo: usize,
/// General registers
pub at: usize,
pub v0: usize,
pub v1: usize,
pub a0: usize,
pub a1: usize,
pub a2: usize,
pub a3: usize,
pub t0: usize,
pub t1: usize,
pub t2: usize,
pub t3: usize,
pub t4: usize,
pub t5: usize,
pub t6: usize,
pub t7: usize,
pub s0: usize,
pub s1: usize,
pub s2: usize,
pub s3: usize,
pub s4: usize,
pub s5: usize,
pub s6: usize,
pub s7: usize,
pub t8: usize,
pub t9: usize,
pub k0: usize,
pub k1: usize,
pub gp: usize,
pub sp: usize,
pub fp: usize,
pub ra: usize,
/// Reserve space for hartid
pub _hartid: usize,
}
impl TrapFrame {
/// Constructs TrapFrame for a new kernel thread.
///
/// The new thread starts at function `entry` with an usize argument `arg`.
/// The stack pointer will be set to `sp`.
fn new_kernel_thread(entry: extern "C" fn(usize) -> !, arg: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.a0 = arg;
tf.sp = sp;
tf.epc = entry as usize;
tf.status = cp0::status::read();
tf.status.set_kernel_mode();
tf.status.set_ie();
tf.status.set_exl();
tf
}
/// Constructs TrapFrame for a new user thread.
///
/// The new thread starts at `entry_addr`.
/// The stack pointer will be set to `sp`.
fn new_user_thread(entry_addr: usize, sp: usize) -> Self {
use core::mem::zeroed;
let mut tf: Self = unsafe { zeroed() };
tf.sp = sp;
tf.epc = entry_addr;
tf.status = cp0::status::read();
tf.status.set_user_mode();
tf.status.set_ie();
tf.status.set_exl();
tf
}
}
use core::fmt::{Debug, Error, Formatter};
impl Debug for TrapFrame {
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
f.debug_struct("TrapFrame")
.field("status", &self.status.bits)
.field("epc", &self.epc)
.field("cause", &self.cause.bits)
.field("vaddr", &self.vaddr)
.finish()
}
}
/// Kernel stack contents for a new thread
#[derive(Debug)]
#[repr(C)]
pub struct InitStack {
context: ContextData,
tf: TrapFrame,
}
impl InitStack {
/// Push the InitStack on the stack and transfer to a Context.
unsafe fn push_at(self, stack_top: usize) -> Context {
let ptr = (stack_top as *mut Self).sub(1); //real kernel stack top
*ptr = self;
Context { sp: ptr as usize }
}
}
extern "C" {
fn trap_return();
}
/// Saved registers for kernel context switches.
#[derive(Debug, Default)]
#[repr(C)]
struct ContextData {
/// Return address
ra: usize,
/// Page table token
satp: usize,
/// Callee-saved registers
s: [usize; 12],
}
impl ContextData {
fn new(satp: usize) -> Self {
ContextData {
ra: trap_return as usize,
satp,
..ContextData::default()
}
}
}
/// Context of a kernel thread.
#[derive(Debug)]
#[repr(C)]
pub struct Context {
/// The stack pointer of the suspended thread.
/// A `ContextData` is stored here.
sp: usize,
}
impl Context {
/// Switch to another kernel thread.
///
/// Push all callee-saved registers at the current kernel stack.
/// Store current sp, switch to target.
/// Pop all callee-saved registers, then return to the target.
#[inline(always)]
pub unsafe fn switch(&mut self, target: &mut Self) {
extern "C" {
fn switch_context(src: *mut Context, dst: *mut Context);
}
tlb::clear_all_tlb();
switch_context(self as *mut Context, target as *mut Context);
}
/// Constructs a null Context for the current running thread.
pub unsafe fn null() -> Self {
Context { sp: 0 }
}
/// Constructs Context for a new kernel thread.
///
/// The new thread starts at function `entry` with an usize argument `arg`.
/// The stack pointer will be set to `kstack_top`.
/// The SATP register will be set to `satp`.
pub unsafe fn new_kernel_thread(
entry: extern "C" fn(usize) -> !,
arg: usize,
kstack_top: usize,
satp: usize,
) -> Self {
info!(
"New kernel thread @ {:x}, stack = {:x}",
entry as usize, kstack_top
);
InitStack {
context: ContextData::new(satp),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}
.push_at(kstack_top)
}
/// Constructs Context for a new user thread.
///
/// The new thread starts at `entry_addr`.
/// The stack pointer of user and kernel mode will be set to `ustack_top`, `kstack_top`.
/// The SATP register will be set to `satp`.
pub unsafe fn new_user_thread(
entry_addr: usize,
ustack_top: usize,
kstack_top: usize,
_is32: bool,
satp: usize,
) -> Self {
info!(
"New user thread @ {:x}, stack = {:x}",
entry_addr, kstack_top
);
InitStack {
context: ContextData::new(satp),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}
.push_at(kstack_top)
}
/// Fork a user process and get the new Context.
///
/// The stack pointer in kernel mode will be set to `kstack_top`.
/// The SATP register will be set to `satp`.
/// All the other registers are same as the original.
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, satp: usize) -> Self {
InitStack {
context: ContextData::new(satp),
tf: {
let mut tf = tf.clone();
// fork function's ret value, the new process is 0
tf.v0 = 0;
tf
},
}
.push_at(kstack_top)
}
/// Fork a user thread and get the new Context.
///
/// The stack pointer in kernel mode will be set to `kstack_top`.
/// The SATP register will be set to `satp`.
/// The new user stack will be set to `ustack_top`.
/// The new thread pointer will be set to `tls`.
/// All the other registers are same as the original.
pub unsafe fn new_clone(
tf: &TrapFrame,
ustack_top: usize,
kstack_top: usize,
satp: usize,
tls: usize,
) -> Self {
InitStack {
context: ContextData::new(satp),
tf: {
let mut tf = tf.clone();
tf.sp = ustack_top; // sp
tf.v1 = tls;
tf.v0 = 0; // return value
tf
},
}
.push_at(kstack_top)
}
/// Used for getting the init TrapFrame of a new user context in `sys_exec`.
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.sp as *const InitStack)).tf.clone()
}
}

@ -0,0 +1,30 @@
use crate::consts::MAX_CPU_NUM;
use core::ptr::{read_volatile, write_volatile};
use mips::registers::cp0;
static mut STARTED: [bool; MAX_CPU_NUM] = [false; MAX_CPU_NUM];
pub fn id() -> usize {
(cp0::ebase::read_u32() as usize) & 0x3ff
}
pub unsafe fn has_started(cpu_id: usize) -> bool {
read_volatile(&STARTED[cpu_id])
}
pub unsafe fn start_others(hart_mask: usize) {
for cpu_id in 0..MAX_CPU_NUM {
if (hart_mask >> cpu_id) & 1 != 0 {
write_volatile(&mut STARTED[cpu_id], true);
}
}
}
pub fn halt() {
/* nothing to do */
}
pub unsafe fn exit_in_qemu(error_code: u8) -> ! {
/* nothing to do */
loop {}
}

@ -0,0 +1,16 @@
//! mipsel drivers
use super::board;
use once::*;
pub use self::board::fb;
pub use self::board::serial;
#[path = "../../../drivers/console/mod.rs"]
pub mod console;
/// Initialize common drivers
pub fn init() {
assert_has_not_been_called!("driver::init must be called only once");
board::init_driver();
console::init();
}

@ -0,0 +1,175 @@
pub use self::context::*;
use crate::arch::paging::get_root_page_table_ptr;
use crate::drivers::DRIVERS;
use log::*;
use mips::addr::*;
use mips::interrupts;
use mips::paging::{
PageTable as MIPSPageTable, PageTableEntry, PageTableFlags as EF, TwoLevelPageTable,
};
use mips::registers::cp0;
use mips::tlb;
#[path = "context.rs"]
mod context;
/// Initialize interrupt
pub fn init() {
extern "C" {
fn trap_entry();
}
unsafe {
// Set the exception vector address
cp0::ebase::write_u32(trap_entry as u32);
println!("Set ebase = {:x}", trap_entry as u32);
let mut status = cp0::status::read();
// Enable IPI
status.enable_soft_int0();
status.enable_soft_int1();
// Enable clock interrupt
status.enable_hard_int5();
cp0::status::write(status);
}
info!("interrupt: init end");
}
/// Enable interrupt
#[inline]
pub unsafe fn enable() {
interrupts::enable();
}
/// Disable interrupt and return current interrupt status
#[inline]
pub unsafe fn disable_and_store() -> usize {
let e = cp0::status::read_u32() & 1;
interrupts::disable();
e as usize
}
/// Enable interrupt if `flags` != 0
#[inline]
pub unsafe fn restore(flags: usize) {
if flags != 0 {
enable();
}
}
/// Dispatch and handle interrupt.
///
/// This function is called from `trap.asm`.
#[no_mangle]
pub extern "C" fn rust_trap(tf: &mut TrapFrame) {
use cp0::cause::Exception as E;
trace!("Exception @ CPU{}: {:?} ", 0, tf.cause.cause());
match tf.cause.cause() {
E::Interrupt => interrupt_dispatcher(tf),
E::Syscall => syscall(tf),
E::TLBModification => page_fault(tf),
E::TLBLoadMiss => page_fault(tf),
E::TLBStoreMiss => page_fault(tf),
_ => {
error!("Unhandled Exception @ CPU{}: {:?} ", 0, tf.cause.cause());
crate::trap::error(tf)
}
}
trace!("Interrupt end");
}
fn interrupt_dispatcher(tf: &mut TrapFrame) {
let pint = tf.cause.pending_interrupt();
trace!(" Interrupt {:08b} ", pint);
if (pint & 0b100_000_00) != 0 {
timer();
} else if (pint & 0b011_111_00) != 0 {
external();
} else {
ipi();
}
}
fn external() {
// true means handled, false otherwise
let handlers = [try_process_serial, try_process_drivers];
for handler in handlers.iter() {
if handler() == true {
break;
}
}
}
fn try_process_serial() -> bool {
match super::io::getchar_option() {
Some(ch) => {
trace!("Get char {} from serial", ch);
crate::trap::serial(ch);
true
}
None => false,
}
}
fn try_process_drivers() -> bool {
// TODO
for driver in DRIVERS.read().iter() {
if driver.try_handle_interrupt(None) == true {
return true;
}
}
return false;
}
fn ipi() {
debug!("IPI");
cp0::cause::reset_soft_int0();
cp0::cause::reset_soft_int1();
}
fn timer() {
super::timer::set_next();
crate::trap::timer();
}
fn syscall(tf: &mut TrapFrame) {
tf.epc += 4; // Must before syscall, because of fork.
let arguments = [tf.a0, tf.a1, tf.a2, tf.a3, tf.t0, tf.t1];
trace!("MIPS syscall {} invoked with {:?}", tf.v0, arguments);
let ret = crate::syscall::syscall(tf.v0, arguments, tf) as isize;
// comply with mips n32 abi, always return a positive value
// https://git.musl-libc.org/cgit/musl/tree/arch/mipsn32/syscall_arch.h
if (ret < 0) {
tf.v0 = (-ret) as usize;
tf.a3 = 1;
} else {
tf.v0 = ret as usize;
tf.a3 = 0;
}
}
fn page_fault(tf: &mut TrapFrame) {
// TODO: set access/dirty bit
let addr = tf.vaddr;
trace!("\nEXCEPTION: Page Fault @ {:#x}", addr);
let virt_addr = VirtAddr::new(addr);
let root_table = unsafe { &mut *(get_root_page_table_ptr() as *mut MIPSPageTable) };
let tlb_result = root_table.lookup(addr);
match tlb_result {
Ok(tlb_entry) => {
trace!(
"PhysAddr = {:x}/{:x}",
tlb_entry.entry_lo0.get_pfn() << 12,
tlb_entry.entry_lo1.get_pfn() << 12
);
tlb::write_tlb_random(tlb_entry)
}
Err(()) => {
if !crate::memory::handle_page_fault(addr) {
crate::trap::error(tf);
}
}
}
}

@ -0,0 +1,25 @@
//! Input/output for mipsel.
use super::driver::console::CONSOLE;
use super::driver::serial::*;
use core::fmt::{Arguments, Write};
pub fn getchar() -> char {
unsafe { SERIAL_PORT.force_unlock() }
SERIAL_PORT.lock().getchar()
}
pub fn getchar_option() -> Option<char> {
unsafe { SERIAL_PORT.force_unlock() }
SERIAL_PORT.lock().getchar_option()
}
pub fn putfmt(fmt: Arguments) {
unsafe { SERIAL_PORT.force_unlock() }
SERIAL_PORT.lock().write_fmt(fmt).unwrap();
unsafe { CONSOLE.force_unlock() }
if let Some(console) = CONSOLE.lock().as_mut() {
console.write_fmt(fmt).unwrap();
}
}

@ -0,0 +1,77 @@
use crate::arch::paging::*;
use crate::consts::{KERNEL_OFFSET, MEMORY_END, MEMORY_OFFSET};
use crate::memory::{init_heap, Linear, MemoryAttr, MemorySet, FRAME_ALLOCATOR};
use core::mem;
use log::*;
use rcore_memory::PAGE_SIZE;
/// Initialize the memory management module
pub fn init() {
// initialize heap and Frame allocator
init_frame_allocator();
init_heap();
set_root_page_table_ptr(0xFFFF_FFFF);
extern "C" {
fn _root_page_table_buffer();
fn _root_page_table_ptr();
}
println!("_root_page_table_ptr {:x}", _root_page_table_ptr as usize);
}
pub fn init_other() {
// TODO: init other CPU cores
}
fn init_frame_allocator() {
use bitmap_allocator::BitAlloc;
use core::ops::Range;
let mut ba = FRAME_ALLOCATOR.lock();
let range = to_range(
(end as usize) - KERNEL_OFFSET + MEMORY_OFFSET + PAGE_SIZE,
MEMORY_END,
);
ba.insert(range);
info!("frame allocator: init end");
/// Transform memory area `[start, end)` to integer range for `FrameAllocator`
fn to_range(start: usize, end: usize) -> Range<usize> {
let page_start = (start - MEMORY_OFFSET) / PAGE_SIZE;
let page_end = (end - MEMORY_OFFSET - 1) / PAGE_SIZE + 1;
assert!(page_start < page_end, "illegal range for frame allocator");
page_start..page_end
}
}
// First core stores its SATP here.
// Other cores load it later.
static mut SATP: usize = 0;
pub unsafe fn clear_bss() {
let start = sbss as usize;
let end = ebss as usize;
let step = core::mem::size_of::<usize>();
for i in (start..end).step_by(step) {
(i as *mut usize).write(0);
}
}
// Symbols provided by linker script
#[allow(dead_code)]
extern "C" {
fn stext();
fn etext();
fn sdata();
fn edata();
fn srodata();
fn erodata();
fn sbss();
fn ebss();
fn start();
fn end();
fn bootstack();
fn bootstacktop();
}

@ -0,0 +1,83 @@
pub mod compiler_rt;
pub mod consts;
pub mod cpu;
pub mod driver;
pub mod interrupt;
pub mod io;
pub mod memory;
pub mod paging;
pub mod rand;
pub mod syscall;
pub mod timer;
use log::*;
use mips::registers::cp0;
#[cfg(feature = "board_malta")]
#[path = "board/malta/mod.rs"]
pub mod board;
#[cfg(feature = "board_thinpad")]
#[path = "board/thinpad/mod.rs"]
pub mod board;
#[cfg(feature = "board_mipssim")]
#[path = "board/mipssim/mod.rs"]
pub mod board;
extern "C" {
fn _dtb_start();
fn _dtb_end();
}
#[no_mangle]
pub extern "C" fn rust_main() -> ! {
// unsafe { cpu::set_cpu_id(hartid); }
let ebase = cp0::ebase::read_u32();
let cpu_id = ebase & 0x3ff;
let dtb_start = _dtb_start as usize;
if cpu_id != BOOT_CPU_ID {
// TODO: run others_main on other CPU
// while unsafe { !cpu::has_started(hartid) } { }
// println!("Hello RISCV! in hart {}, dtb @ {:#x}", hartid, dtb);
// others_main();
loop {}
}
unsafe {
memory::clear_bss();
}
board::init_serial_early();
crate::logging::init();
interrupt::init();
memory::init();
timer::init();
driver::init();
println!("Hello MIPS 32 from CPU {}, dtb @ {:#x}", cpu_id, dtb_start);
crate::drivers::init(dtb_start);
crate::process::init();
// TODO: start other CPU
// unsafe { cpu::start_others(hart_mask); }
crate::kmain();
}
fn others_main() -> ! {
interrupt::init();
memory::init_other();
timer::init();
crate::kmain();
}
const BOOT_CPU_ID: u32 = 0;
global_asm!(include_str!("boot/context.gen.s"));
global_asm!(include_str!("boot/entry.gen.s"));
global_asm!(include_str!("boot/trap.gen.s"));
global_asm!(include_str!("boot/dtb.gen.s"));

@ -0,0 +1,232 @@
// Depends on kernel
use crate::memory::{active_table, alloc_frame, dealloc_frame};
use log::*;
use mips::addr::*;
use mips::paging::{FrameAllocator, FrameDeallocator};
use mips::paging::{
Mapper, PageTable as MIPSPageTable, PageTableEntry, PageTableFlags as EF, TwoLevelPageTable,
};
use mips::tlb::*;
use rcore_memory::paging::*;
pub struct ActivePageTable(TwoLevelPageTable<'static>, PageEntry);
/// PageTableEntry: the contents of this entry.
/// Page: this entry is the pte of page `Page`.
pub struct PageEntry(&'static mut PageTableEntry, Page);
impl PageTable for ActivePageTable {
fn map(&mut self, addr: usize, target: usize) -> &mut Entry {
// map the 4K `page` to the 4K `frame` with `flags`
let flags = EF::VALID | EF::WRITABLE | EF::CACHEABLE;
let page = Page::of_addr(VirtAddr::new(addr));
let frame = Frame::of_addr(PhysAddr::new(target));
// map the page to the frame using FrameAllocatorForRiscv
// we may need frame allocator to alloc frame for new page table(first/second)
self.0
.map_to(page, frame, flags, &mut FrameAllocatorForRiscv)
.unwrap()
.flush();
self.get_entry(addr).expect("fail to get entry")
}
fn unmap(&mut self, addr: usize) {
let page = Page::of_addr(VirtAddr::new(addr));
let (_, flush) = self.0.unmap(page).unwrap();
flush.flush();
}
fn get_entry(&mut self, vaddr: usize) -> Option<&mut Entry> {
let page = Page::of_addr(VirtAddr::new(vaddr));
if let Ok(e) = self.0.ref_entry(page.clone()) {
let e = unsafe { &mut *(e as *mut PageTableEntry) };
self.1 = PageEntry(e, page);
Some(&mut self.1 as &mut Entry)
} else {
None
}
}
}
extern "C" {
fn _root_page_table_buffer();
fn _root_page_table_ptr();
}
pub fn set_root_page_table_ptr(ptr: usize) {
unsafe {
clear_all_tlb();
*(_root_page_table_ptr as *mut usize) = ptr;
}
}
pub fn get_root_page_table_ptr() -> usize {
unsafe { *(_root_page_table_ptr as *mut usize) }
}
pub fn root_page_table_buffer() -> &'static mut MIPSPageTable {
unsafe { &mut *(_root_page_table_ptr as *mut MIPSPageTable) }
}
impl PageTableExt for ActivePageTable {}
/// The virtual address of root page table
impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(
TwoLevelPageTable::new(root_page_table_buffer()),
::core::mem::uninitialized(),
)
}
}
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
impl Entry for PageEntry {
fn update(&mut self) {
unsafe {
clear_all_tlb();
}
}
fn accessed(&self) -> bool {
self.0.flags().contains(EF::ACCESSED)
}
fn dirty(&self) -> bool {
self.0.flags().contains(EF::DIRTY)
}
fn writable(&self) -> bool {
self.0.flags().contains(EF::WRITABLE)
}
fn present(&self) -> bool {
self.0.flags().contains(EF::VALID)
}
fn clear_accessed(&mut self) {
self.0.flags_mut().remove(EF::ACCESSED);
}
fn clear_dirty(&mut self) {
self.0.flags_mut().remove(EF::DIRTY);
}
fn set_writable(&mut self, value: bool) {
self.0.flags_mut().set(EF::WRITABLE, value);
}
fn set_present(&mut self, value: bool) {
self.0.flags_mut().set(EF::VALID, value);
}
fn target(&self) -> usize {
self.0.addr().as_usize()
}
fn set_target(&mut self, target: usize) {
let flags = self.0.flags();
let frame = Frame::of_addr(PhysAddr::new(target));
self.0.set(frame, flags);
}
fn writable_shared(&self) -> bool {
false
}
fn readonly_shared(&self) -> bool {
false
}
fn set_shared(&mut self, writable: bool) {}
fn clear_shared(&mut self) {}
fn swapped(&self) -> bool {
self.0.flags().contains(EF::RESERVED1)
}
fn set_swapped(&mut self, value: bool) {
self.0.flags_mut().set(EF::RESERVED1, value);
}
fn user(&self) -> bool {
true
}
fn set_user(&mut self, value: bool) {}
fn execute(&self) -> bool {
true
}
fn set_execute(&mut self, value: bool) {}
fn mmio(&self) -> u8 {
0
}
fn set_mmio(&mut self, _value: u8) {}
}
#[derive(Debug)]
pub struct InactivePageTable0 {
root_frame: Frame,
}
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
fn new_bare() -> Self {
let target = alloc_frame().expect("failed to allocate frame");
let frame = Frame::of_addr(PhysAddr::new(target));
let table = unsafe { &mut *(target as *mut MIPSPageTable) };
table.zero();
InactivePageTable0 { root_frame: frame }
}
fn map_kernel(&mut self) {
/* nothing to do */
}
fn token(&self) -> usize {
self.root_frame.to_kernel_unmapped().as_usize()
}
unsafe fn set_token(token: usize) {
set_root_page_table_ptr(token);
}
fn active_token() -> usize {
get_root_page_table_ptr()
}
fn flush_tlb() {
unsafe {
clear_all_tlb();
}
}
fn edit<T>(&mut self, f: impl FnOnce(&mut Self::Active) -> T) -> T {
let pt: *mut MIPSPageTable = unsafe { self.token() as *mut MIPSPageTable };
unsafe {
clear_all_tlb();
}
let mut active = unsafe {
ActivePageTable(
TwoLevelPageTable::new(&mut *pt),
::core::mem::uninitialized(),
)
};
let ret = f(&mut active);
unsafe {
clear_all_tlb();
}
ret
}
}
impl Drop for InactivePageTable0 {
fn drop(&mut self) {
dealloc_frame(self.root_frame.start_address().as_usize());
}
}
struct FrameAllocatorForRiscv;
impl FrameAllocator for FrameAllocatorForRiscv {
fn alloc(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(PhysAddr::new(addr)))
}
}
impl FrameDeallocator for FrameAllocatorForRiscv {
fn dealloc(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_usize());
}
}

@ -0,0 +1,3 @@
pub fn rand() -> u64 {
return 0;
}

@ -0,0 +1,391 @@
//! MIPS N32 ABI syscall ids
//! Reference: https://git.linux-mips.org/cgit/ralf/linux.git/tree/arch/mips/include/uapi/asm/unistd.h
extern crate paste;
pub const MIPS_SYSCALL_OFFSET: usize = 4000;
macro_rules! define_syscall {
($name: ident, $id: expr) => {
paste::item! {
pub const [<SYS_ $name>] : usize = MIPS_SYSCALL_OFFSET + $id;
}
};
}
define_syscall!(SYSCALL, 0);
define_syscall!(EXIT, 1);
define_syscall!(FORK, 2);
define_syscall!(READ, 3);
define_syscall!(WRITE, 4);
define_syscall!(OPEN, 5);
define_syscall!(CLOSE, 6);
define_syscall!(WAITPID, 7);
define_syscall!(CREAT, 8);
define_syscall!(LINK, 9);
define_syscall!(UNLINK, 10);
define_syscall!(EXECVE, 11);
define_syscall!(CHDIR, 12);
define_syscall!(TIME, 13);
define_syscall!(MKNOD, 14);
define_syscall!(CHMOD, 15);
define_syscall!(LCHOWN, 16);
define_syscall!(BREAK, 17);
define_syscall!(UNUSED18, 18);
define_syscall!(LSEEK, 19);
define_syscall!(GETPID, 20);
define_syscall!(MOUNT, 21);
define_syscall!(UMOUNT, 22);
define_syscall!(SETUID, 23);
define_syscall!(GETUID, 24);
define_syscall!(STIME, 25);
define_syscall!(PTRACE, 26);
define_syscall!(ALARM, 27);
define_syscall!(UNUSED28, 28);
define_syscall!(PAUSE, 29);
define_syscall!(UTIME, 30);
define_syscall!(STTY, 31);
define_syscall!(GTTY, 32);
define_syscall!(ACCESS, 33);
define_syscall!(NICE, 34);
define_syscall!(FTIME, 35);
define_syscall!(SYNC, 36);
define_syscall!(KILL, 37);
define_syscall!(RENAME, 38);
define_syscall!(MKDIR, 39);
define_syscall!(RMDIR, 40);
define_syscall!(DUP, 41);
define_syscall!(PIPE, 42);
define_syscall!(TIMES, 43);
define_syscall!(PROF, 44);
define_syscall!(BRK, 45);
define_syscall!(SETGID, 46);
define_syscall!(GETGID, 47);
define_syscall!(SIGNAL, 48);
define_syscall!(GETEUID, 49);
define_syscall!(GETEGID, 50);
define_syscall!(ACCT, 51);
define_syscall!(UMOUNT2, 52);
define_syscall!(LOCK, 53);
define_syscall!(IOCTL, 54);
define_syscall!(FCNTL, 55);
define_syscall!(MPX, 56);
define_syscall!(SETPGID, 57);
define_syscall!(ULIMIT, 58);
define_syscall!(UNUSED59, 59);
define_syscall!(UMASK, 60);
define_syscall!(CHROOT, 61);
define_syscall!(USTAT, 62);
define_syscall!(DUP2, 63);
define_syscall!(GETPPID, 64);
define_syscall!(GETPGRP, 65);
define_syscall!(SETSID, 66);
define_syscall!(SIGACTION, 67);
define_syscall!(SGETMASK, 68);
define_syscall!(SSETMASK, 69);
define_syscall!(SETREUID, 70);
define_syscall!(SETREGID, 71);
define_syscall!(SIGSUSPEND, 72);
define_syscall!(SIGPENDING, 73);
define_syscall!(SETHOSTNAME, 74);
define_syscall!(SETRLIMIT, 75);
define_syscall!(GETRLIMIT, 76);
define_syscall!(GETRUSAGE, 77);
define_syscall!(GETTIMEOFDAY, 78);
define_syscall!(SETTIMEOFDAY, 79);
define_syscall!(GETGROUPS, 80);
define_syscall!(SETGROUPS, 81);
define_syscall!(RESERVED82, 82);
define_syscall!(SYMLINK, 83);
define_syscall!(UNUSED84, 84);
define_syscall!(READLINK, 85);
define_syscall!(USELIB, 86);
define_syscall!(SWAPON, 87);
define_syscall!(REBOOT, 88);
define_syscall!(READDIR, 89);
define_syscall!(MMAP, 90);
define_syscall!(MUNMAP, 91);
define_syscall!(TRUNCATE, 92);
define_syscall!(FTRUNCATE, 93);
define_syscall!(FCHMOD, 94);
define_syscall!(FCHOWN, 95);
define_syscall!(GETPRIORITY, 96);
define_syscall!(SETPRIORITY, 97);
define_syscall!(PROFIL, 98);
define_syscall!(STATFS, 99);
define_syscall!(FSTATFS, 100);
define_syscall!(IOPERM, 101);
define_syscall!(SOCKETCALL, 102);
define_syscall!(SYSLOG, 103);
define_syscall!(SETITIMER, 104);
define_syscall!(GETITIMER, 105);
define_syscall!(STAT, 106);
define_syscall!(LSTAT, 107);
define_syscall!(FSTAT, 108);
define_syscall!(UNUSED109, 109);
define_syscall!(IOPL, 110);
define_syscall!(VHANGUP, 111);
define_syscall!(IDLE, 112);
define_syscall!(VM86, 113);
define_syscall!(WAIT4, 114);
define_syscall!(SWAPOFF, 115);
define_syscall!(SYSINFO, 116);
define_syscall!(IPC, 117);
define_syscall!(FSYNC, 118);
define_syscall!(SIGRETURN, 119);
define_syscall!(CLONE, 120);
define_syscall!(SETDOMAINNAME, 121);
define_syscall!(UNAME, 122);
define_syscall!(MODIFY_LDT, 123);
define_syscall!(ADJTIMEX, 124);
define_syscall!(MPROTECT, 125);
define_syscall!(SIGPROCMASK, 126);
define_syscall!(CREATE_MODULE, 127);
define_syscall!(INIT_MODULE, 128);
define_syscall!(DELETE_MODULE, 129);
define_syscall!(GET_KERNEL_SYMS, 130);
define_syscall!(QUOTACTL, 131);
define_syscall!(GETPGID, 132);
define_syscall!(FCHDIR, 133);
define_syscall!(BDFLUSH, 134);
define_syscall!(SYSFS, 135);
define_syscall!(PERSONALITY, 136);
define_syscall!(AFS_SYSCALL, 137);
define_syscall!(SETFSUID, 138);
define_syscall!(SETFSGID, 139);
define_syscall!(_LLSEEK, 140);
define_syscall!(GETDENTS, 141);
define_syscall!(_NEWSELECT, 142);
define_syscall!(FLOCK, 143);
define_syscall!(MSYNC, 144);
define_syscall!(READV, 145);
define_syscall!(WRITEV, 146);
define_syscall!(CACHEFLUSH, 147);
define_syscall!(CACHECTL, 148);
define_syscall!(SYSMIPS, 149);
define_syscall!(UNUSED150, 150);
define_syscall!(GETSID, 151);
define_syscall!(FDATASYNC, 152);
define_syscall!(_SYSCTL, 153);
define_syscall!(MLOCK, 154);
define_syscall!(MUNLOCK, 155);
define_syscall!(MLOCKALL, 156);
define_syscall!(MUNLOCKALL, 157);
define_syscall!(SCHED_SETPARAM, 158);
define_syscall!(SCHED_GETPARAM, 159);
define_syscall!(SCHED_SETSCHEDULER, 160);
define_syscall!(SCHED_GETSCHEDULER, 161);
define_syscall!(SCHED_YIELD, 162);
define_syscall!(SCHED_GET_PRIORITY_MAX, 163);
define_syscall!(SCHED_GET_PRIORITY_MIN, 164);
define_syscall!(SCHED_RR_GET_INTERVAL, 165);
define_syscall!(NANOSLEEP, 166);
define_syscall!(MREMAP, 167);
define_syscall!(ACCEPT, 168);
define_syscall!(BIND, 169);
define_syscall!(CONNECT, 170);
define_syscall!(GETPEERNAME, 171);
define_syscall!(GETSOCKNAME, 172);
define_syscall!(GETSOCKOPT, 173);
define_syscall!(LISTEN, 174);
define_syscall!(RECV, 175);
define_syscall!(RECVFROM, 176);
define_syscall!(RECVMSG, 177);
define_syscall!(SEND, 178);
define_syscall!(SENDMSG, 179);
define_syscall!(SENDTO, 180);
define_syscall!(SETSOCKOPT, 181);
define_syscall!(SHUTDOWN, 182);
define_syscall!(SOCKET, 183);
define_syscall!(SOCKETPAIR, 184);
define_syscall!(SETRESUID, 185);
define_syscall!(GETRESUID, 186);
define_syscall!(QUERY_MODULE, 187);
define_syscall!(POLL, 188);
define_syscall!(NFSSERVCTL, 189);
define_syscall!(SETRESGID, 190);
define_syscall!(GETRESGID, 191);
define_syscall!(PRCTL, 192);
define_syscall!(RT_SIGRETURN, 193);
define_syscall!(RT_SIGACTION, 194);
define_syscall!(RT_SIGPROCMASK, 195);
define_syscall!(RT_SIGPENDING, 196);
define_syscall!(RT_SIGTIMEDWAIT, 197);
define_syscall!(RT_SIGQUEUEINFO, 198);
define_syscall!(RT_SIGSUSPEND, 199);
define_syscall!(PREAD64, 200);
define_syscall!(PWRITE64, 201);
define_syscall!(CHOWN, 202);
define_syscall!(GETCWD, 203);
define_syscall!(CAPGET, 204);
define_syscall!(CAPSET, 205);
define_syscall!(SIGALTSTACK, 206);
define_syscall!(SENDFILE, 207);
define_syscall!(GETPMSG, 208);
define_syscall!(PUTPMSG, 209);
define_syscall!(MMAP2, 210);
define_syscall!(TRUNCATE64, 211);
define_syscall!(FTRUNCATE64, 212);
define_syscall!(STAT64, 213);
define_syscall!(LSTAT64, 214);
define_syscall!(FSTAT64, 215);
define_syscall!(PIVOT_ROOT, 216);
define_syscall!(MINCORE, 217);
define_syscall!(MADVISE, 218);
define_syscall!(GETDENTS64, 219);
define_syscall!(FCNTL64, 220);
define_syscall!(RESERVED221, 221);
define_syscall!(GETTID, 222);
define_syscall!(READAHEAD, 223);
define_syscall!(SETXATTR, 224);
define_syscall!(LSETXATTR, 225);
define_syscall!(FSETXATTR, 226);
define_syscall!(GETXATTR, 227);
define_syscall!(LGETXATTR, 228);
define_syscall!(FGETXATTR, 229);
define_syscall!(LISTXATTR, 230);
define_syscall!(LLISTXATTR, 231);
define_syscall!(FLISTXATTR, 232);
define_syscall!(REMOVEXATTR, 233);
define_syscall!(LREMOVEXATTR, 234);
define_syscall!(FREMOVEXATTR, 235);
define_syscall!(TKILL, 236);
define_syscall!(SENDFILE64, 237);
define_syscall!(FUTEX, 238);
define_syscall!(SCHED_SETAFFINITY, 239);
define_syscall!(SCHED_GETAFFINITY, 240);
define_syscall!(IO_SETUP, 241);
define_syscall!(IO_DESTROY, 242);
define_syscall!(IO_GETEVENTS, 243);
define_syscall!(IO_SUBMIT, 244);
define_syscall!(IO_CANCEL, 245);
define_syscall!(EXIT_GROUP, 246);
define_syscall!(LOOKUP_DCOOKIE, 247);
define_syscall!(EPOLL_CREATE, 248);
define_syscall!(EPOLL_CTL, 249);
define_syscall!(EPOLL_WAIT, 250);
define_syscall!(REMAP_FILE_PAGES, 251);
define_syscall!(SET_TID_ADDRESS, 252);
define_syscall!(RESTART_SYSCALL, 253);
define_syscall!(FADVISE64, 254);
define_syscall!(STATFS64, 255);
define_syscall!(FSTATFS64, 256);
define_syscall!(TIMER_CREATE, 257);
define_syscall!(TIMER_SETTIME, 258);
define_syscall!(TIMER_GETTIME, 259);
define_syscall!(TIMER_GETOVERRUN, 260);
define_syscall!(TIMER_DELETE, 261);
define_syscall!(CLOCK_SETTIME, 262);
define_syscall!(CLOCK_GETTIME, 263);
define_syscall!(CLOCK_GETRES, 264);
define_syscall!(CLOCK_NANOSLEEP, 265);
define_syscall!(TGKILL, 266);
define_syscall!(UTIMES, 267);
define_syscall!(MBIND, 268);
define_syscall!(GET_MEMPOLICY, 269);
define_syscall!(SET_MEMPOLICY, 270);
define_syscall!(MQ_OPEN, 271);
define_syscall!(MQ_UNLINK, 272);
define_syscall!(MQ_TIMEDSEND, 273);
define_syscall!(MQ_TIMEDRECEIVE, 274);
define_syscall!(MQ_NOTIFY, 275);
define_syscall!(MQ_GETSETATTR, 276);
define_syscall!(VSERVER, 277);
define_syscall!(WAITID, 278);
define_syscall!(SYS_SETALTROOT, 279);
define_syscall!(ADD_KEY, 280);
define_syscall!(REQUEST_KEY, 281);
define_syscall!(KEYCTL, 282);
define_syscall!(SET_THREAD_AREA, 283);
define_syscall!(INOTIFY_INIT, 284);
define_syscall!(INOTIFY_ADD_WATCH, 285);
define_syscall!(INOTIFY_RM_WATCH, 286);
define_syscall!(MIGRATE_PAGES, 287);
define_syscall!(OPENAT, 288);
define_syscall!(MKDIRAT, 289);
define_syscall!(MKNODAT, 290);
define_syscall!(FCHOWNAT, 291);
define_syscall!(FUTIMESAT, 292);
define_syscall!(FSTATAT64, 293);
define_syscall!(UNLINKAT, 294);
define_syscall!(RENAMEAT, 295);
define_syscall!(LINKAT, 296);
define_syscall!(SYMLINKAT, 297);
define_syscall!(READLINKAT, 298);
define_syscall!(FCHMODAT, 299);
define_syscall!(FACCESSAT, 300);
define_syscall!(PSELECT6, 301);
define_syscall!(PPOLL, 302);
define_syscall!(UNSHARE, 303);
define_syscall!(SPLICE, 304);
define_syscall!(SYNC_FILE_RANGE, 305);
define_syscall!(TEE, 306);
define_syscall!(VMSPLICE, 307);
define_syscall!(MOVE_PAGES, 308);
define_syscall!(SET_ROBUST_LIST, 309);
define_syscall!(GET_ROBUST_LIST, 310);
define_syscall!(KEXEC_LOAD, 311);
define_syscall!(GETCPU, 312);
define_syscall!(EPOLL_PWAIT, 313);
define_syscall!(IOPRIO_SET, 314);
define_syscall!(IOPRIO_GET, 315);
define_syscall!(UTIMENSAT, 316);
define_syscall!(SIGNALFD, 317);
define_syscall!(TIMERFD, 318);
define_syscall!(EVENTFD, 319);
define_syscall!(FALLOCATE, 320);
define_syscall!(TIMERFD_CREATE, 321);
define_syscall!(TIMERFD_GETTIME, 322);
define_syscall!(TIMERFD_SETTIME, 323);
define_syscall!(SIGNALFD4, 324);
define_syscall!(EVENTFD2, 325);
define_syscall!(EPOLL_CREATE1, 326);
define_syscall!(DUP3, 327);
define_syscall!(PIPE2, 328);
define_syscall!(INOTIFY_INIT1, 329);
define_syscall!(PREADV, 330);
define_syscall!(PWRITEV, 331);
define_syscall!(RT_TGSIGQUEUEINFO, 332);
define_syscall!(PERF_EVENT_OPEN, 333);
define_syscall!(ACCEPT4, 334);
define_syscall!(RECVMMSG, 335);
define_syscall!(FANOTIFY_INIT, 336);
define_syscall!(FANOTIFY_MARK, 337);
define_syscall!(PRLIMIT64, 338);
define_syscall!(NAME_TO_HANDLE_AT, 339);
define_syscall!(OPEN_BY_HANDLE_AT, 340);
define_syscall!(CLOCK_ADJTIME, 341);
define_syscall!(SYNCFS, 342);
define_syscall!(SENDMMSG, 343);
define_syscall!(SETNS, 344);
define_syscall!(PROCESS_VM_READV, 345);
define_syscall!(PROCESS_VM_WRITEV, 346);
define_syscall!(KCMP, 347);
define_syscall!(FINIT_MODULE, 348);
define_syscall!(SCHED_SETATTR, 349);
define_syscall!(SCHED_GETATTR, 350);
define_syscall!(RENAMEAT2, 351);
define_syscall!(SECCOMP, 352);
define_syscall!(GETRANDOM, 353);
define_syscall!(MEMFD_CREATE, 354);
define_syscall!(BPF, 355);
define_syscall!(EXECVEAT, 356);
define_syscall!(USERFAULTFD, 357);
define_syscall!(MEMBARRIER, 358);
define_syscall!(MLOCK2, 359);
define_syscall!(COPY_FILE_RANGE, 360);
define_syscall!(PREADV2, 361);
define_syscall!(PWRITEV2, 362);
define_syscall!(PKEY_MPROTECT, 363);
define_syscall!(PKEY_ALLOC, 364);
define_syscall!(PKEY_FREE, 365);
define_syscall!(STATX, 366);
define_syscall!(RSEQ, 367);
define_syscall!(IO_PGETEVENTS, 368);
// non-existent syscalls, will not be called or matched
pub const SYS_NEWFSTATAT: usize = 0;
// custom temporary syscall
pub const SYS_MAP_PCI_DEVICE: usize = 999;
pub const SYS_GET_PADDR: usize = 998;

@ -0,0 +1,24 @@
use log::*;
use mips::registers::cp0;
pub fn read_epoch() -> u64 {
// TODO: support RTC
0
}
/// Enable timer interrupt
pub fn init() {
// Enable supervisor timer interrupt
cp0::status::enable_hard_int5(); // IP(7), timer interrupt
cp0::count::write_u32(0);
set_next();
info!("timer: init end");
}
/// Set the next timer interrupt
pub fn set_next() {
// 100Hz @ QEMU
let timebase = 250000;
cp0::count::write_u32(0);
cp0::compare::write_u32(timebase);
}

@ -22,6 +22,11 @@ pub fn fp() -> usize {
unsafe { unsafe {
asm!("mov %rbp, $0" : "=r"(ptr)); asm!("mov %rbp, $0" : "=r"(ptr));
} }
#[cfg(any(target_arch = "mips"))]
unsafe {
// read $sp
asm!("ori $0, $$29, 0" : "=r"(ptr));
}
ptr ptr
} }
@ -43,6 +48,11 @@ pub fn lr() -> usize {
asm!("movq 8(%rbp), $0" : "=r"(ptr)); asm!("movq 8(%rbp), $0" : "=r"(ptr));
} }
#[cfg(target_arch = "mips")]
unsafe {
asm!("ori $0, $$31, 0" : "=r"(ptr));
}
ptr ptr
} }
@ -52,16 +62,41 @@ pub fn backtrace() {
let mut current_pc = lr(); let mut current_pc = lr();
let mut current_fp = fp(); let mut current_fp = fp();
let mut stack_num = 0; let mut stack_num = 0;
// adjust sp to the top address of backtrace() function
#[cfg(target_arch = "mips")]
{
let func_base = backtrace as *const isize;
let sp_offset = (*func_base << 16) >> 16;
current_fp = ((current_fp as isize) - sp_offset) as usize;
}
println!("=== BEGIN rCore stack trace ===");
while current_pc >= stext as usize while current_pc >= stext as usize
&& current_pc <= etext as usize && current_pc <= etext as usize
&& current_fp as usize != 0 && current_fp as usize != 0
{ {
// print current backtrace
match size_of::<usize>() {
4 => {
println!(
"#{:02} PC: {:#010X} FP: {:#010X}",
stack_num,
current_pc - size_of::<usize>(),
current_fp
);
}
_ => {
println!( println!(
"#{} {:#018X} fp {:#018X}", "#{:02} PC: {:#018X} FP: {:#018X}",
stack_num, stack_num,
current_pc - size_of::<usize>(), current_pc - size_of::<usize>(),
current_fp current_fp
); );
}
}
stack_num = stack_num + 1; stack_num = stack_num + 1;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
{ {
@ -78,6 +113,53 @@ pub fn backtrace() {
current_pc = *(current_fp as *const usize).offset(1); current_pc = *(current_fp as *const usize).offset(1);
} }
} }
#[cfg(target_arch = "mips")]
{
// the prologue of function is always like:
// main+0: 27bd____ addiu sp, sp, -____
// main+4: afbf____ sw ra, ____(sp)
let mut code_ptr = current_pc as *const isize;
code_ptr = code_ptr.offset(-1);
// get the stack size of last function
while (*code_ptr as usize >> 16) != 0x27bd {
code_ptr = code_ptr.offset(-1);
}
let sp_offset = (*code_ptr << 16) >> 16;
trace!(
"Found addiu sp @ {:08X}({:08x}) with sp offset {}",
code_ptr as usize,
*code_ptr,
sp_offset
);
// get the return address offset of last function
let mut last_fun_found = false;
while (code_ptr as usize) < current_pc {
if (*code_ptr as usize >> 16) == 0xafbf {
last_fun_found = true;
break;
}
code_ptr = code_ptr.offset(1);
}
if last_fun_found {
// unwind stack
let ra_offset = (*code_ptr << 16) >> 16;
trace!(
"Found sw ra @ {:08X}({:08x}) with ra offset {}",
code_ptr as usize,
*code_ptr,
ra_offset
);
current_pc = *(((current_fp as isize) + ra_offset) as *const usize);
current_fp = ((current_fp as isize) - sp_offset) as usize;
trace!("New PC {:08X} FP {:08X}", current_pc, current_fp);
continue;
} else {
trace!("No sw ra found, probably due to optimizations.");
break;
}
}
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
{ {
// Kernel stack at 0x0000_57ac_0000_0000 (defined in bootloader crate) // Kernel stack at 0x0000_57ac_0000_0000 (defined in bootloader crate)
@ -91,5 +173,6 @@ pub fn backtrace() {
current_pc = *(current_fp as *const usize).offset(1); current_pc = *(current_fp as *const usize).offset(1);
} }
} }
println!("=== END rCore stack trace ===");
} }
} }

@ -1,3 +1,3 @@
#[cfg(target_arch = "x86_64")] #[cfg(any(target_arch = "x86_64", target_arch = "mips"))]
pub mod pci; pub mod pci;
pub mod virtio_mmio; pub mod virtio_mmio;

@ -9,7 +9,6 @@ use core::cmp::Ordering;
use pci::*; use pci::*;
use rcore_memory::{paging::PageTable, PAGE_SIZE}; use rcore_memory::{paging::PageTable, PAGE_SIZE};
use spin::Mutex; use spin::Mutex;
use x86_64::instructions::port::Port;
const PCI_COMMAND: u16 = 0x04; const PCI_COMMAND: u16 = 0x04;
const PCI_CAP_PTR: u16 = 0x34; const PCI_CAP_PTR: u16 = 0x34;
@ -25,6 +24,10 @@ const PCI_CAP_ID_MSI: u8 = 0x05;
struct PortOpsImpl; struct PortOpsImpl;
#[cfg(target_arch = "x86_64")]
use x86_64::instructions::port::Port;
#[cfg(target_arch = "x86_64")]
impl PortOps for PortOpsImpl { impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 { unsafe fn read8(&self, port: u16) -> u8 {
Port::new(port).read() Port::new(port).read()
@ -46,6 +49,33 @@ impl PortOps for PortOpsImpl {
} }
} }
#[cfg(target_arch = "mips")]
use crate::util::{read, write};
#[cfg(feature = "board_malta")]
const PCI_BASE: usize = 0xbbe00000;
#[cfg(target_arch = "mips")]
impl PortOps for PortOpsImpl {
unsafe fn read8(&self, port: u16) -> u8 {
read(PCI_BASE + port as usize)
}
unsafe fn read16(&self, port: u16) -> u16 {
read(PCI_BASE + port as usize)
}
unsafe fn read32(&self, port: u16) -> u32 {
read(PCI_BASE + port as usize)
}
unsafe fn write8(&self, port: u16, val: u8) {
write(PCI_BASE + port as usize, val);
}
unsafe fn write16(&self, port: u16, val: u16) {
write(PCI_BASE + port as usize, val);
}
unsafe fn write32(&self, port: u16, val: u32) {
write(PCI_BASE + port as usize, val);
}
}
/// Enable the pci device and its interrupt /// Enable the pci device and its interrupt
/// Return assigned MSI interrupt number when applicable /// Return assigned MSI interrupt number when applicable
unsafe fn enable(loc: Location) -> Option<u32> { unsafe fn enable(loc: Location) -> Option<u32> {

@ -2,12 +2,10 @@
use crate::util::color::ConsoleColor; use crate::util::color::ConsoleColor;
pub trait FramebufferColor { use super::ColorConfig;
/// pack as 16-bit integer
fn pack16(&self) -> u16;
/// pack as 32-bit integer pub trait FramebufferColor {
fn pack32(&self) -> u32; fn pack32(&self, config: ColorConfig) -> u32;
} }
#[repr(C)] #[repr(C)]
@ -43,28 +41,32 @@ impl From<ConsoleColor> for RgbColor {
impl FramebufferColor for RgbColor { impl FramebufferColor for RgbColor {
#[inline] #[inline]
fn pack16(&self) -> u16 { fn pack32(&self, config: ColorConfig) -> u32 {
// BGR565 match config {
((self.0 as u16 & 0xF8) << 8) | ((self.1 as u16 & 0xFC) << 3) | (self.2 as u16 >> 3) ColorConfig::RGB332 => {
(((self.0 >> 5) << 5) | ((self.1 >> 5) << 2) | (self.2 >> 6)) as u32
}
ColorConfig::RGB565 => {
(((self.0 as u16 & 0xF8) << 8)
| ((self.1 as u16 & 0xFC) << 3)
| (self.2 as u16 >> 3)) as u32
} }
#[inline]
fn pack32(&self) -> u32 {
// BGRA8888
// FIXME: qemu and low version RPi use RGBA order for 24/32-bit color depth, // FIXME: qemu and low version RPi use RGBA order for 24/32-bit color depth,
// but RPi3 B+ uses BGRA order for 24/32-bit color depth. // but RPi3 B+ uses BGRA order for 24/32-bit color depth.
ColorConfig::BGRA8888 => {
((self.0 as u32) << 16) | ((self.1 as u32) << 8) | (self.2 as u32) ((self.0 as u32) << 16) | ((self.1 as u32) << 8) | (self.2 as u32)
} }
_ => unimplemented!(),
}
}
} }
impl FramebufferColor for ConsoleColor { impl FramebufferColor for ConsoleColor {
#[inline] #[inline]
fn pack16(&self) -> u16 { fn pack32(&self, config: ColorConfig) -> u32 {
RgbColor::from(*self).pack16() match config {
ColorConfig::VgaPalette => *self as u32,
_ => RgbColor::from(*self).pack32(config),
} }
#[inline]
fn pack32(&self) -> u32 {
RgbColor::from(*self).pack32()
} }
} }

@ -10,7 +10,7 @@ use spin::Mutex;
use crate::util::escape_parser::{CharacterAttribute, EscapeParser}; use crate::util::escape_parser::{CharacterAttribute, EscapeParser};
use super::fb::{ColorDepth::*, FramebufferInfo, FRAME_BUFFER}; use super::fb::{ColorConfig, ColorDepth::*, FramebufferInfo, FRAME_BUFFER};
use self::color::FramebufferColor; use self::color::FramebufferColor;
use self::fonts::{Font, Font8x16}; use self::fonts::{Font, Font8x16};
@ -62,13 +62,10 @@ impl<F: Font> ConsoleBuffer<F> {
let off_x = col * F::WIDTH; let off_x = col * F::WIDTH;
let off_y = row * F::HEIGHT; let off_y = row * F::HEIGHT;
if let Some(fb) = FRAME_BUFFER.lock().as_mut() { if let Some(fb) = FRAME_BUFFER.lock().as_mut() {
let (mut foreground, mut background) = match fb.color_depth { let (mut foreground, mut background) = (
ColorDepth16 => ( ch.attr.foreground.pack32(fb.color_config),
ch.attr.foreground.pack16() as u32, ch.attr.background.pack32(fb.color_config),
ch.attr.background.pack16() as u32, );
),
ColorDepth32 => (ch.attr.foreground.pack32(), ch.attr.background.pack32()),
};
if ch.attr.reverse { if ch.attr.reverse {
core::mem::swap(&mut foreground, &mut background); core::mem::swap(&mut foreground, &mut background);
} }

@ -14,6 +14,7 @@ fn walk_dt_node(dt: &Node) {
if compatible == "virtio,mmio" { if compatible == "virtio,mmio" {
virtio_probe(dt); virtio_probe(dt);
} }
// TODO: initial other devices (16650, etc.)
} }
if let Ok(bootargs) = dt.prop_str("bootargs") { if let Ok(bootargs) = dt.prop_str("bootargs") {
if bootargs.len() > 0 { if bootargs.len() > 0 {

@ -1,6 +1,5 @@
//! Framebuffer //! Framebuffer
use super::mailbox;
use alloc::string::String; use alloc::string::String;
use core::fmt; use core::fmt;
use lazy_static::lazy_static; use lazy_static::lazy_static;
@ -40,14 +39,28 @@ pub struct FramebufferInfo {
#[repr(u32)] #[repr(u32)]
#[derive(Debug, Clone, Copy)] #[derive(Debug, Clone, Copy)]
pub enum ColorDepth { pub enum ColorDepth {
ColorDepth8 = 8,
ColorDepth16 = 16, ColorDepth16 = 16,
ColorDepth32 = 32, ColorDepth32 = 32,
} }
use self::ColorDepth::*; use self::ColorDepth::*;
#[repr(u32)]
#[derive(Debug, Clone, Copy)]
pub enum ColorConfig {
RGB332,
RGB565,
BGRA8888,
VgaPalette,
}
use self::ColorConfig::*;
pub type FramebufferResult = Result<(FramebufferInfo, ColorConfig, usize), String>;
#[repr(C)] #[repr(C)]
union ColorBuffer { union ColorBuffer {
base_addr: usize, base_addr: usize,
buf8: &'static mut [u8],
buf16: &'static mut [u16], buf16: &'static mut [u16],
buf32: &'static mut [u32], buf32: &'static mut [u32],
} }
@ -56,6 +69,9 @@ impl ColorBuffer {
fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer { fn new(color_depth: ColorDepth, base_addr: usize, size: usize) -> ColorBuffer {
unsafe { unsafe {
match color_depth { match color_depth {
ColorDepth8 => ColorBuffer {
buf8: core::slice::from_raw_parts_mut(base_addr as *mut u8, size),
},
ColorDepth16 => ColorBuffer { ColorDepth16 => ColorBuffer {
buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2), buf16: core::slice::from_raw_parts_mut(base_addr as *mut u16, size / 2),
}, },
@ -66,6 +82,11 @@ impl ColorBuffer {
} }
} }
#[inline]
fn read8(&self, index: u32) -> u8 {
unsafe { self.buf8[index as usize] }
}
#[inline] #[inline]
fn read16(&self, index: u32) -> u16 { fn read16(&self, index: u32) -> u16 {
unsafe { self.buf16[index as usize] } unsafe { self.buf16[index as usize] }
@ -76,6 +97,11 @@ impl ColorBuffer {
unsafe { self.buf32[index as usize] } unsafe { self.buf32[index as usize] }
} }
#[inline]
fn write8(&mut self, index: u32, pixel: u8) {
unsafe { self.buf8[index as usize] = pixel }
}
#[inline] #[inline]
fn write16(&mut self, index: u32, pixel: u16) { fn write16(&mut self, index: u32, pixel: u16) {
unsafe { self.buf16[index as usize] = pixel } unsafe { self.buf16[index as usize] = pixel }
@ -91,6 +117,7 @@ impl ColorBuffer {
pub struct Framebuffer { pub struct Framebuffer {
pub fb_info: FramebufferInfo, pub fb_info: FramebufferInfo,
pub color_depth: ColorDepth, pub color_depth: ColorDepth,
pub color_config: ColorConfig,
buf: ColorBuffer, buf: ColorBuffer,
} }
@ -99,6 +126,7 @@ impl fmt::Debug for Framebuffer {
let mut f = f.debug_struct("Framebuffer"); let mut f = f.debug_struct("Framebuffer");
f.field("fb_info", &self.fb_info); f.field("fb_info", &self.fb_info);
f.field("color_depth", &self.color_depth); f.field("color_depth", &self.color_depth);
f.field("color_config", &self.color_config);
f.field("base_addr", unsafe { &self.buf.base_addr }); f.field("base_addr", unsafe { &self.buf.base_addr });
f.finish() f.finish()
} }
@ -108,50 +136,26 @@ impl Framebuffer {
fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> { fn new(width: u32, height: u32, depth: u32) -> Result<Framebuffer, String> {
assert_has_not_been_called!("Framebuffer::new must be called only once"); assert_has_not_been_called!("Framebuffer::new must be called only once");
let (width, height) = if width == 0 || height == 0 { let probed_info = super::probe_fb_info(width, height, depth);
mailbox::framebuffer_get_physical_size()?
} else {
(width, height)
};
let depth = if depth == 0 {
mailbox::framebuffer_get_depth()?
} else {
depth
};
let info = mailbox::framebuffer_alloc(width, height, depth)?; match probed_info {
Ok((info, config, addr)) => {
let color_depth = match info.depth { let color_depth = match info.depth {
8 => ColorDepth8,
16 => ColorDepth16, 16 => ColorDepth16,
32 => ColorDepth32, 32 => ColorDepth32,
_ => Err(format!("unsupported color depth {}", info.depth))?, _ => Err(format!("unsupported color depth {}", info.depth))?,
}; };
if info.bus_addr == 0 || info.screen_size == 0 {
Err(format!("mailbox call returned an invalid address/size"))?;
}
if info.pitch == 0 || info.pitch != info.xres * info.depth / 8 {
Err(format!(
"mailbox call returned an invalid pitch value {}",
info.pitch
))?;
}
use crate::arch::memory;
let paddr = info.bus_addr & !0xC0000000;
let vaddr = memory::ioremap(paddr as usize, info.screen_size as usize, "fb");
if vaddr == 0 {
Err(format!(
"cannot remap memory range [{:#x?}..{:#x?}]",
paddr,
paddr + info.screen_size
))?;
}
Ok(Framebuffer { Ok(Framebuffer {
buf: ColorBuffer::new(color_depth, vaddr, info.screen_size as usize), buf: ColorBuffer::new(color_depth, addr, info.screen_size as usize),
color_config: config,
color_depth, color_depth,
fb_info: info, fb_info: info,
}) })
} }
Err(e) => Err(e)?,
}
}
#[inline] #[inline]
pub fn base_addr(&self) -> usize { pub fn base_addr(&self) -> usize {
@ -162,6 +166,7 @@ impl Framebuffer {
#[inline] #[inline]
pub fn read(&self, x: u32, y: u32) -> u32 { pub fn read(&self, x: u32, y: u32) -> u32 {
match self.color_depth { match self.color_depth {
ColorDepth8 => self.buf.read8(y * self.fb_info.xres + x) as u32,
ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32, ColorDepth16 => self.buf.read16(y * self.fb_info.xres + x) as u32,
ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x), ColorDepth32 => self.buf.read32(y * self.fb_info.xres + x),
} }
@ -171,6 +176,7 @@ impl Framebuffer {
#[inline] #[inline]
pub fn write(&mut self, x: u32, y: u32, pixel: u32) { pub fn write(&mut self, x: u32, y: u32, pixel: u32) {
match self.color_depth { match self.color_depth {
ColorDepth8 => self.buf.write8(y * self.fb_info.xres + x, pixel as u8),
ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16), ColorDepth16 => self.buf.write16(y * self.fb_info.xres + x, pixel as u16),
ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel), ColorDepth32 => self.buf.write32(y * self.fb_info.xres + x, pixel),
} }

@ -0,0 +1,153 @@
//! driver for qemu stdvga (Cirrus)
use crate::util::{read, write};
const VGA_MMIO_OFFSET: usize = 0x400 - 0x3C0;
const VBE_MMIO_OFFSET: usize = 0x500;
const VGA_AR_ADDR: u16 = 0x3C0;
const VBE_DISPI_INDEX_XRES: u16 = 0x1;
const VBE_DISPI_INDEX_YRES: u16 = 0x2;
const VBE_DISPI_INDEX_BPP: u16 = 0x3;
const VBE_DISPI_INDEX_ENABLE: u16 = 0x4;
const VBE_DISPI_INDEX_BANK: u16 = 0x5;
const VBE_DISPI_INDEX_VIRT_WIDTH: u16 = 0x6;
const VBE_DISPI_INDEX_VIRT_HEIGHT: u16 = 0x7;
const VBE_DISPI_INDEX_X_OFFSET: u16 = 0x8;
const VBE_DISPI_INDEX_Y_OFFSET: u16 = 0x9;
const VBE_DISPI_INDEX_VIDEO_MEMORY_64K: u16 = 0xa;
const VGA_AR_PAS: u8 = 0x20;
const VBE_DISPI_ENABLED: u16 = 0x01;
const VBE_DISPI_8BIT_DAC: u16 = 0x20;
const VBE_DISPI_LFB_ENABLED: u16 = 0x40;
const PCI_COMMAND: u8 = 0x04;
const PCI_COMMAND_IO: u32 = 0x1;
const PCI_COMMAND_MEMORY: u32 = 0x2;
const PCI_COMMAND_MASTER: u32 = 0x4;
const PCI_COMMAND_SPECIAL: u32 = 0x8;
const PCI_COMMAND_SERR: u32 = 0x100;
fn pci_read_config(pci_base: usize, bus: u8, slot: u8, func: u8, offset: u8) -> u32 {
// write config address
let address = (1 << 31)
| ((bus as u32) << 16)
| ((slot as u32) << 11)
| ((func as u32) << 8)
| (offset as u32);
write(pci_base + 0xcf8, address);
// do the actual work
let value = read(pci_base + 0xcfc);
debug!(
"Read {:08x} from PCI address: {:02x}:{:02x}.{:02x} @ 0x{:02x}",
value, bus, slot, func, offset
);
value
}
fn pci_write_config(pci_base: usize, bus: u8, slot: u8, func: u8, offset: u8, value: u32) {
// write config address
let address = (1 << 31)
| ((bus as u32) << 16)
| ((slot as u32) << 11)
| ((func as u32) << 8)
| (offset as u32);
debug!(
"Write {:08x} to PCI address: {:02x}:{:02x}.{:02x} @ 0x{:02x}",
value, bus, slot, func, offset
);
write(pci_base + 0xcf8, address);
// do the actual work
write(pci_base + 0xcfc, value)
}
pub fn init(pci_base: usize, vga_base: usize, x_res: u16, y_res: u16) {
debug!(
"PCI Controller Base: {:08x}",
pci_read_config(pci_base, 0x00, 0x00, 0x00, 0x20)
);
let controller = pci_read_config(pci_base, 0x00, 0x00, 0x00, PCI_COMMAND);
pci_write_config(
pci_base,
0x00,
0x00,
0x00,
PCI_COMMAND,
controller | PCI_COMMAND_MASTER | PCI_COMMAND_IO | PCI_COMMAND_MEMORY | PCI_COMMAND_SERR,
);
let pci_vendor = pci_read_config(pci_base, 0x00, 0x12, 0x00, 0x0);
debug!("VGA PCI Device ID: {:08x}", pci_vendor);
// enable port and MMIO for vga card
pci_write_config(
pci_base,
0x00,
0x12,
0x00,
PCI_COMMAND,
pci_read_config(pci_base, 0x00, 0x12, 0x00, PCI_COMMAND) | PCI_COMMAND_MEMORY,
);
// bar 0
pci_write_config(pci_base, 0x00, 0x12, 0x00, 0x10, 0x10000000);
debug!(
"VGA PCI BAR 0: {:08x}",
pci_read_config(pci_base, 0x00, 0x12, 0x00, 0x10)
);
// bar 2
pci_write_config(pci_base, 0x00, 0x12, 0x00, 0x18, 0x12050000);
debug!(
"VGA PCI BAR 2: {:08x}",
pci_read_config(pci_base, 0x00, 0x12, 0x00, 0x18)
);
// vga operations
let vga_write_io = |offset: u16, value: u8| {
write(vga_base + VGA_MMIO_OFFSET + (offset as usize), value);
};
let vga_read_io = |offset: u16| -> u8 { read(vga_base + VGA_MMIO_OFFSET + (offset as usize)) };
let vga_write_vbe = |offset: u16, value: u16| {
write(vga_base + VBE_MMIO_OFFSET + (offset as usize) * 2, value);
};
let vga_read_vbe =
|offset: u16| -> u16 { read(vga_base + VBE_MMIO_OFFSET + (offset as usize) * 2) };
debug!("VGA Endianess: {:x}", read::<u32>(vga_base + 0x604));
// unblank vga output
vga_write_io(VGA_AR_ADDR, VGA_AR_PAS);
debug!("VGA AR: {}", vga_read_io(VGA_AR_ADDR));
vga_write_vbe(VBE_DISPI_INDEX_ENABLE, 0);
// set resolution and color depth
vga_write_vbe(VBE_DISPI_INDEX_XRES, x_res);
vga_write_vbe(VBE_DISPI_INDEX_YRES, y_res);
vga_write_vbe(VBE_DISPI_INDEX_VIRT_WIDTH, x_res);
vga_write_vbe(VBE_DISPI_INDEX_VIRT_HEIGHT, y_res);
vga_write_vbe(VBE_DISPI_INDEX_BANK, 0);
vga_write_vbe(VBE_DISPI_INDEX_X_OFFSET, 0);
vga_write_vbe(VBE_DISPI_INDEX_Y_OFFSET, 0);
vga_write_vbe(VBE_DISPI_INDEX_BPP, 8);
debug!(
"VGA Resolution: {}*{}@{}bit",
vga_read_vbe(VBE_DISPI_INDEX_XRES),
vga_read_vbe(VBE_DISPI_INDEX_YRES),
vga_read_vbe(VBE_DISPI_INDEX_BPP)
);
// enable vbe
let vbe_enable = vga_read_vbe(VBE_DISPI_INDEX_ENABLE);
vga_write_vbe(
VBE_DISPI_INDEX_ENABLE,
vbe_enable | VBE_DISPI_ENABLED | VBE_DISPI_LFB_ENABLED | VBE_DISPI_8BIT_DAC,
);
debug!("VBE Status: {:04x}", vga_read_vbe(VBE_DISPI_INDEX_ENABLE));
info!("QEMU STDVGA driver initialized @ {:x}", vga_base);
}

@ -115,7 +115,7 @@ lazy_static! {
pub static ref SOCKET_ACTIVITY: Condvar = Condvar::new(); pub static ref SOCKET_ACTIVITY: Condvar = Condvar::new();
} }
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "mips"))]
pub fn init(dtb: usize) { pub fn init(dtb: usize) {
device_tree::init(dtb); device_tree::init(dtb);
} }

@ -0,0 +1,109 @@
//! 16550 serial adapter driver for malta board
#![allow(dead_code)]
use crate::util::{read, write};
use core::fmt::{Arguments, Result, Write};
use spin::Mutex;
pub struct SerialPort {
base: usize,
}
impl SerialPort {
fn new() -> SerialPort {
SerialPort { base: 0 }
}
pub fn init(&mut self, base: usize) {
self.base = base;
// Turn off the FIFO
write(self.base + COM_FCR, 0 as u8);
// Set speed; requires DLAB latch
write(self.base + COM_LCR, COM_LCR_DLAB);
write(self.base + COM_DLL, (115200 / 9600) as u8);
write(self.base + COM_DLM, 0 as u8);
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
// No modem controls
write(self.base + COM_MCR, 0 as u8);
// Enable rcv interrupts
write(self.base + COM_IER, COM_IER_RDI);
}
/// non-blocking version of putchar()
pub fn putchar(&mut self, c: u8) {
write(self.base + COM_TX, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> char {
loop {
if (read::<u8>(self.base + COM_LSR) & COM_LSR_DATA) == 0 {
break;
}
}
let c = read::<u8>(self.base + COM_RX);
match c {
255 => '\0', // null
c => c as char,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&mut self) -> Option<char> {
match read::<u8>(self.base + COM_LSR) & COM_LSR_DATA {
0 => None,
_ => Some(read::<u8>(self.base + COM_RX) as u8 as char),
}
}
pub fn putfmt(&mut self, fmt: Arguments) {
self.write_fmt(fmt).unwrap();
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
self.putchar(c);
}
}
Ok(())
}
}
const COM_RX: usize = 0; // In: Receive buffer (DLAB=0)
const COM_TX: usize = 0; // Out: Transmit buffer (DLAB=0)
const COM_DLL: usize = 0; // Out: Divisor Latch Low (DLAB=1)
const COM_DLM: usize = 1; // Out: Divisor Latch High (DLAB=1)
const COM_IER: usize = 1; // Out: Interrupt Enable Register
const COM_IER_RDI: u8 = 0x01; // Enable receiver data interrupt
const COM_IIR: usize = 2; // In: Interrupt ID Register
const COM_FCR: usize = 2; // Out: FIFO Control Register
const COM_LCR: usize = 3; // Out: Line Control Register
const COM_LCR_DLAB: u8 = 0x80; // Divisor latch access bit
const COM_LCR_WLEN8: u8 = 0x03; // Wordlength: 8 bits
const COM_MCR: usize = 4; // Out: Modem Control Register
const COM_MCR_RTS: u8 = 0x02; // RTS complement
const COM_MCR_DTR: u8 = 0x01; // DTR complement
const COM_MCR_OUT2: u8 = 0x08; // Out2 complement
const COM_LSR: usize = 5; // In: Line Status Register
const COM_LSR_DATA: u8 = 0x01; // Data available
const COM_LSR_TXRDY: u8 = 0x20; // Transmit buffer avail
const COM_LSR_TSRE: u8 = 0x40; // Transmitter off
lazy_static! {
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
}
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
}

@ -0,0 +1,79 @@
//! naive serial adapter driver for thinpad
use crate::util::{read, write};
use core::fmt::{Arguments, Result, Write};
#[derive(Debug, Clone, Copy)]
pub struct SerialPort {
base: usize,
}
const UART_STATUS: usize = 0x0;
const UART_DATA: usize = 0x4;
const UART_STATUS_CTS: u8 = 0x1; // clear to send signal
const UART_STATUS_DR: u8 = 0x2; // data ready signal
impl SerialPort {
pub fn init(&mut self, base: usize) {
self.base = base;
}
/// non-blocking version of putchar()
pub fn putchar(&mut self, c: u8) {
write(self.base + UART_DATA, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> char {
loop {
if (read::<u8>(self.base + UART_STATUS) & UART_STATUS_DR) == 0 {
break;
}
}
let c = read::<u8>(self.base + UART_DATA);
match c {
255 => '\0', // null
c => c as char,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&mut self) -> Option<char> {
match read::<u8>(self.base + UART_STATUS) & UART_STATUS_DR {
0 => None,
_ => Some(read::<u8>(self.base + UART_DATA) as u8 as char),
}
}
pub fn putfmt(&mut self, fmt: Arguments) {
self.write_fmt(fmt).unwrap();
}
pub fn lock(&self) -> SerialPort {
self.clone()
}
pub fn force_unlock(&self) {}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
self.putchar(c);
}
}
Ok(())
}
}
pub static SERIAL_PORT: SerialPort = SerialPort { base: 0 };
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
}

@ -0,0 +1,95 @@
//! TI 16c550c serial adapter driver for malta board
#![allow(dead_code)]
use crate::util::{read, write};
use core::fmt::{Arguments, Result, Write};
use spin::Mutex;
pub struct SerialPort {
base: usize,
}
impl SerialPort {
fn new() -> SerialPort {
SerialPort { base: 0 }
}
pub fn init(&mut self, base: usize) {
self.base = base;
// Turn off the FIFO
// write(self.base + COM_FCR, 0 as u8);
// Set speed; requires DLAB latch
// write(self.base + COM_LCR, COM_LCR_DLAB);
// write(self.base + COM_DLL, (115200 / 9600) as u8);
// write(self.base + COM_DLM, 0 as u8);
// 8 data bits, 1 stop bit, parity off; turn off DLAB latch
// write(self.base + COM_LCR, COM_LCR_WLEN8 & !COM_LCR_DLAB);
// No modem controls
// write(self.base + COM_MCR, 0 as u8);
// Enable rcv interrupts
write(self.base + COM_INT_EN, 0x1);
}
/// non-blocking version of putchar()
pub fn putchar(&mut self, c: u8) {
write(self.base + COM_TX, c);
}
/// blocking version of getchar()
pub fn getchar(&mut self) -> char {
loop {
if (read::<u8>(self.base + COM_LSR) & 0x01) == 0 {
break;
}
}
let c = read::<u8>(self.base + COM_RX);
match c {
255 => '\0', // null
c => c as char,
}
}
/// non-blocking version of getchar()
pub fn getchar_option(&mut self) -> Option<char> {
match read::<u8>(self.base + COM_LSR) & 0x01 {
0 => None,
_ => Some(read::<u8>(self.base + COM_RX) as u8 as char),
}
}
pub fn putfmt(&mut self, fmt: Arguments) {
self.write_fmt(fmt).unwrap();
}
}
impl Write for SerialPort {
fn write_str(&mut self, s: &str) -> Result {
for c in s.bytes() {
if c == 127 {
self.putchar(8);
self.putchar(b' ');
self.putchar(8);
} else {
self.putchar(c);
}
}
Ok(())
}
}
const COM_RX: usize = 0x00; // In: Receive buffer (DLAB=0)
const COM_TX: usize = 0x00; // Out: Transmit buffer (DLAB=0)
const COM_INT_EN: usize = 0x08; // In: Interrupt enable
const COM_INT_ID: usize = 0x10; // Out: Interrupt identification
const COM_LSR: usize = 0x28; // In: Line status register
lazy_static! {
pub static ref SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
}
pub fn init(base: usize) {
SERIAL_PORT.lock().init(base);
}

@ -21,7 +21,7 @@ mod stdio;
#[cfg(feature = "link_user")] #[cfg(feature = "link_user")]
global_asm!(concat!( global_asm!(concat!(
r#" r#"
.section .data .section .data.img
.global _user_img_start .global _user_img_start
.global _user_img_end .global _user_img_end
_user_img_start: _user_img_start:
@ -54,6 +54,7 @@ lazy_static! {
fn _user_img_start(); fn _user_img_start();
fn _user_img_end(); fn _user_img_end();
} }
info!("SFS linked to kernel, from {:08x} to {:08x}", _user_img_start as usize, _user_img_end as usize);
Arc::new(unsafe { device::MemBuf::new(_user_img_start, _user_img_end) }) Arc::new(unsafe { device::MemBuf::new(_user_img_start, _user_img_end) })
}; };

@ -42,6 +42,10 @@ mod trap;
#[path = "arch/x86_64/mod.rs"] #[path = "arch/x86_64/mod.rs"]
pub mod arch; pub mod arch;
#[cfg(target_arch = "mips")]
#[path = "arch/mipsel/mod.rs"]
pub mod arch;
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))]
#[path = "arch/riscv32/mod.rs"] #[path = "arch/riscv32/mod.rs"]
pub mod arch; pub mod arch;

@ -21,7 +21,7 @@ pub type FrameAlloc = bitmap_allocator::BitAlloc16M;
pub type FrameAlloc = bitmap_allocator::BitAlloc4K; pub type FrameAlloc = bitmap_allocator::BitAlloc4K;
// Raspberry Pi 3 has 1G memory // Raspberry Pi 3 has 1G memory
#[cfg(target_arch = "aarch64")] #[cfg(any(target_arch = "aarch64", target_arch = "mips"))]
pub type FrameAlloc = bitmap_allocator::BitAlloc1M; pub type FrameAlloc = bitmap_allocator::BitAlloc1M;
lazy_static! { lazy_static! {

@ -216,7 +216,7 @@ impl MutexSupport for Spin {
unsafe { unsafe {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
asm!("pause" :::: "volatile"); asm!("pause" :::: "volatile");
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "mips"))]
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
asm!("yield" :::: "volatile"); asm!("yield" :::: "volatile");
@ -254,7 +254,7 @@ impl MutexSupport for SpinNoIrq {
unsafe { unsafe {
#[cfg(target_arch = "x86_64")] #[cfg(target_arch = "x86_64")]
asm!("pause" :::: "volatile"); asm!("pause" :::: "volatile");
#[cfg(any(target_arch = "riscv32", target_arch = "riscv64"))] #[cfg(any(target_arch = "riscv32", target_arch = "riscv64", target_arch = "mips"))]
asm!("nop" :::: "volatile"); asm!("nop" :::: "volatile");
#[cfg(target_arch = "aarch64")] #[cfg(target_arch = "aarch64")]
asm!("yield" :::: "volatile"); asm!("yield" :::: "volatile");

@ -44,7 +44,7 @@ pub fn syscall(id: usize, args: [usize; 6], tf: &mut TrapFrame) -> isize {
debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id); debug!("{}:{}:{} syscall id {} begin", cid, pid, tid, id);
} }
// use syscall numbers in Linux x86_64 // use platform-specific syscal numbers
// See https://filippo.io/linux-syscall-table/ // See https://filippo.io/linux-syscall-table/
// And https://fedora.juszkiewicz.com.pl/syscalls.html. // And https://fedora.juszkiewicz.com.pl/syscalls.html.
let ret = match id { let ret = match id {

@ -1,3 +1,5 @@
use core::ptr::{read_volatile, write_volatile};
pub mod color; pub mod color;
pub mod escape_parser; pub mod escape_parser;
@ -68,3 +70,17 @@ macro_rules! enum_with_unknown {
} }
} }
} }
#[inline(always)]
pub fn write<T>(addr: usize, content: T) {
let cell = (addr) as *mut T;
unsafe {
write_volatile(cell, content);
}
}
#[inline(always)]
pub fn read<T>(addr: usize) -> T {
let cell = (addr) as *const T;
unsafe { read_volatile(cell) }
}

@ -0,0 +1,36 @@
{
"arch": "mips",
"cpu": "mips32r2",
"llvm-target": "mipsel-unknown-none",
"data-layout": "e-m:m-p:32:32-i8:8:32-i16:16:32-i64:64-n32-S64",
"target-endian": "little",
"target-pointer-width": "32",
"target-c-int-width": "32",
"os": "none",
"features": "+mips32r2,+soft-float",
"max-atomic-width": "32",
"linker": "rust-lld",
"linker-flavor": "ld.lld",
"pre-link-args": {
"ld.lld": [
"-Tsrc/arch/mipsel/boot/linker.ld"
]
},
"executables": true,
"panic-strategy": "abort",
"relocation-model": "static",
"abi-blacklist": [
"cdecl",
"stdcall",
"fastcall",
"vectorcall",
"thiscall",
"aapcs",
"win64",
"sysv64",
"ptx-kernel",
"msp430-interrupt",
"x86-interrupt"
],
"eliminate-frame-pointer": false
}

@ -1 +1 @@
Subproject commit b09e4e24ad1cfe3b6eae2b40231f389070cdb9e2 Subproject commit aeea2b569efe90e38b39d3c72edb4bc015837d14
Loading…
Cancel
Save