1
0
mirror of https://github.com/rcore-os/rCore.git synced 2024-11-25 17:33:28 +04:00

Merge branch 'master' into user-img

This commit is contained in:
Wang Runji 2018-12-02 22:39:59 +08:00 committed by GitHub
commit 3f2beab52d
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
111 changed files with 1124 additions and 15961 deletions

3
.gitmodules vendored Normal file
View File

@ -0,0 +1,3 @@
[submodule "riscv-pk"]
path = riscv-pk
url = https://github.com/riscv-and-rust-and-decaf/riscv-pk.git

View File

@ -1,34 +1,50 @@
sudo: required
sudo: false
language: rust
rust: nightly
os:
- linux
- osx
cache:
cargo: true
directories:
- $HOME/Library/Caches/Homebrew
addons:
apt:
packages:
- qemu
homebrew:
packages:
- qemu
env:
matrix:
- ARCH="riscv32"
- ARCH="riscv32" OPTS="m_mode=1"
- ARCH="x86_64"
- ARCH="aarch64"
install:
- if [ $ARCH = riscv32 ]; then
export FILE="riscv64-unknown-elf-gcc-20181030-x86_64-linux-ubuntu14";
wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz;
tar xf $FILE.tar.gz;
export PATH=$PATH:$PWD/$FILE/bin;
[ $TRAVIS_OS_NAME = linux ] && export FILE="riscv64-unknown-elf-gcc-20181127-x86_64-linux-ubuntu14";
[ $TRAVIS_OS_NAME = osx ] && export FILE="riscv64-unknown-elf-gcc-20181127-x86_64-apple-darwin";
wget https://static.dev.sifive.com/dev-tools/$FILE.tar.gz;
tar xf $FILE.tar.gz;
export PATH=$PATH:$PWD/$FILE/bin;
fi
- if [ $ARCH = aarch64 ]; then
wget https://web.stanford.edu/class/cs140e/files/aarch64-none-elf-linux-x64.tar.gz;
tar -xzvf aarch64-none-elf-linux-x64.tar.gz;
export PATH=$PATH:$PWD/aarch64-none-elf/bin;
if [ $TRAVIS_OS_NAME = linux ]; then
wget https://web.stanford.edu/class/cs140e/files/aarch64-none-elf-linux-x64.tar.gz;
tar -xzvf aarch64-none-elf-linux-x64.tar.gz;
export PATH=$PATH:$PWD/aarch64-none-elf/bin;
elif [ $TRAVIS_OS_NAME = osx ]; then
brew tap SergioBenitez/osxct;
brew install aarch64-none-elf;
fi;
fi
@ -38,4 +54,5 @@ before_script:
- (test -x $HOME/.cargo/bin/bootimage || cargo install bootimage)
script:
- cd kernel && make build arch=$ARCH
- cd kernel && make build arch=$ARCH $OPTS && cd ..
- cd user && make arch=$ARCH

21
LICENSE Normal file
View File

@ -0,0 +1,21 @@
MIT License
Copyright (c) 2018
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@ -6,7 +6,9 @@ Rust version of THU [uCore OS](https://github.com/chyyuu/ucore_os_lab/).
Going to be the next generation teaching operating system.
Support arch: x86_64, RISCV32I, AArch64 (WIP).
Supported architectures: x86_64, RISCV32IMA(S/M), AArch64
Tested boards: QEMU, Raspberry Pi 3B+
[Dev docs](https://rucore.gitbook.io/rust-os-docs/) (in Chinese)
@ -46,7 +48,7 @@ cargo install cargo-xbuild bootimage
```
```bash
git clone https://github.com/wangrunji0408/RustOS.git
git clone https://github.com/wangrunji0408/RustOS.git --recursive
cd RustOS/kernel
rustup override set nightly
make run arch=riscv32|x86_64|aarch64

View File

@ -12,5 +12,6 @@ pub mod cow;
pub mod swap;
pub mod memory_set;
mod addr;
pub mod no_mmu;
pub use crate::addr::*;

View File

@ -166,22 +166,17 @@ impl MemoryArea {
}
}
None => {
info!("map delayed!");
for page in Page::range_of(self.start_addr, self.end_addr) {
let addr = page.start_address();
//let target = T::alloc_frame().expect("failed to allocate frame");
//self.flags.apply(pt.map(addr, target));
let target = T::alloc_frame().expect("failed to allocate frame");
self.flags.apply(pt.map(addr, target));
// for frame delayed allocation
{
let entry = pt.map(addr,0);
self.flags.apply(entry);
}
let entry = pt.get_entry(addr).expect("fail to get entry");
entry.set_present(false);
entry.update();
// let entry = pt.map(addr,0);
// self.flags.apply(entry);
// let entry = pt.get_entry(addr).expect("fail to get entry");
// entry.set_present(false);
// entry.update();
}
info!("finish map delayed!");
}
};
}
@ -227,6 +222,7 @@ pub struct MemoryAttr {
user: bool,
readonly: bool,
execute: bool,
mmio: bool,
hide: bool,
}
@ -255,6 +251,10 @@ impl MemoryAttr {
self.execute = true;
self
}
pub fn mmio(mut self) -> Self {
self.mmio = true;
self
}
/*
** @brief set the memory attribute's hide bit
** @retval MemoryAttr the memory attribute itself
@ -273,8 +273,9 @@ impl MemoryAttr {
if self.user { entry.set_user(true); }
if self.readonly { entry.set_writable(false); }
if self.execute { entry.set_execute(true); }
if self.mmio { entry.set_mmio(true); }
if self.hide { entry.set_present(false); }
if self.user || self.readonly || self.execute || self.hide { entry.update(); }
if self.user || self.readonly || self.execute || self.mmio || self.hide { entry.update(); }
}
}
@ -330,6 +331,9 @@ impl<T: InactivePageTable> MemorySet<T> {
pub fn iter(&self) -> impl Iterator<Item=&MemoryArea> {
self.areas.iter()
}
pub fn edit(&mut self, f: impl FnOnce(&mut T::Active)) {
self.page_table.edit(f);
}
/*
** @brief execute function with the associated page table
** @param f: impl FnOnce() the function to be executed

View File

@ -0,0 +1,66 @@
use alloc::vec::Vec;
use alloc::alloc::{Layout, GlobalAlloc};
use core::marker::PhantomData;
pub trait NoMMUSupport {
type Alloc: GlobalAlloc;
fn allocator() -> &'static Self::Alloc;
}
#[derive(Clone, Debug)]
pub struct MemorySet<S: NoMMUSupport> {
areas: Vec<MemoryArea<S>>,
support: PhantomData<S>,
}
impl<S: NoMMUSupport> MemorySet<S> {
pub fn new() -> Self {
Self {
areas: Vec::new(),
support: PhantomData,
}
}
/// Allocate `size` bytes space. Return the slice.
pub fn push(&mut self, size: usize) -> &'static mut [u8] {
let area = MemoryArea::new(size);
let slice = unsafe { area.as_buf() };
self.areas.push(area);
slice
}
// empty impls
pub fn with<T>(&self, f: impl FnOnce() -> T) -> T { f() }
pub fn token(&self) -> usize { 0 }
pub unsafe fn activate(&self) {}
}
#[derive(Debug)]
struct MemoryArea<S: NoMMUSupport> {
ptr: usize,
layout: Layout,
support: PhantomData<S>,
}
impl<S: NoMMUSupport> MemoryArea<S> {
fn new(size: usize) -> Self {
let layout = Layout::from_size_align(size, 1).unwrap();
let ptr = unsafe { S::allocator().alloc(layout) } as usize;
MemoryArea { ptr, layout, support: PhantomData }
}
unsafe fn as_buf(&self) -> &'static mut [u8] {
core::slice::from_raw_parts_mut(self.ptr as *mut u8, self.layout.size())
}
}
impl<S: NoMMUSupport> Clone for MemoryArea<S> {
fn clone(&self) -> Self {
let new_area = MemoryArea::new(self.layout.size());
unsafe { new_area.as_buf().copy_from_slice(self.as_buf()) }
new_area
}
}
impl<S: NoMMUSupport> Drop for MemoryArea<S> {
fn drop(&mut self) {
unsafe { S::allocator().dealloc(self.ptr as *mut u8, self.layout) }
}
}

View File

@ -195,4 +195,6 @@ pub trait Entry {
** @retval none
*/
fn set_execute(&mut self, value: bool);
fn mmio(&self) -> bool;
fn set_mmio(&mut self, value: bool);
}

View File

@ -6,14 +6,6 @@ pub unsafe fn disable_and_store() -> usize {
rflags & (1 << 9)
}
#[inline(always)]
#[cfg(target_arch = "riscv32")]
pub unsafe fn disable_and_store() -> usize {
let sstatus: usize;
asm!("csrrci $0, 0x100, 1" : "=r"(sstatus));
sstatus & 1
}
#[inline(always)]
#[cfg(target_arch = "x86_64")]
pub unsafe fn restore(flags: usize) {
@ -22,10 +14,28 @@ pub unsafe fn restore(flags: usize) {
}
}
#[inline(always)]
#[cfg(target_arch = "riscv32")]
pub unsafe fn disable_and_store() -> usize {
if option_env!("m_mode").is_some() {
let mstatus: usize;
asm!("csrrci $0, 0x300, 1 << 3" : "=r"(mstatus));
mstatus & (1 << 3)
} else {
let sstatus: usize;
asm!("csrrci $0, 0x100, 1 << 1" : "=r"(sstatus));
sstatus & (1 << 1)
}
}
#[inline(always)]
#[cfg(target_arch = "riscv32")]
pub unsafe fn restore(flags: usize) {
asm!("csrs 0x100, $0" :: "r"(flags));
if option_env!("m_mode").is_some() {
asm!("csrs 0x300, $0" :: "r"(flags));
} else {
asm!("csrs 0x100, $0" :: "r"(flags));
}
}
#[inline(always)]

View File

@ -92,7 +92,10 @@ impl Processor {
}
pub fn tick(&self) {
let flags = unsafe { interrupt::disable_and_store() };
let need_reschedule = self.manager().tick(self.pid());
unsafe { interrupt::restore(flags); }
if need_reschedule {
self.yield_now();
}

35
kernel/Cargo.lock generated
View File

@ -1,3 +1,17 @@
[[package]]
name = "aarch64"
version = "2.2.2"
source = "git+https://github.com/equation314/aarch64#47bf5439f5a1379f0fef6272853cf684207a4e45"
dependencies = [
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"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)",
"os_bootinfo 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"register 0.2.1 (registry+https://github.com/rust-lang/crates.io-index)",
"usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
name = "apic"
version = "0.1.0"
@ -37,7 +51,7 @@ name = "bcm2837"
version = "0.1.0"
dependencies = [
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
]
[[package]]
@ -65,7 +79,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "bootloader"
version = "0.3.4"
source = "git+https://github.com/wangrunji0408/bootloader#dd5723c3d7d50856073a5003e0a355ea0fc3d46c"
source = "git+https://github.com/wangrunji0408/bootloader#24bdcafc302e7d2659ac126049a45571462907d9"
dependencies = [
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
"fixedvec 0.2.3 (registry+https://github.com/rust-lang/crates.io-index)",
@ -132,7 +146,7 @@ dependencies = [
[[package]]
name = "libc"
version = "0.2.43"
version = "0.2.44"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -185,7 +199,7 @@ version = "0.4.3"
source = "registry+https://github.com/rust-lang/crates.io-index"
dependencies = [
"fuchsia-zircon 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)",
"libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)",
"winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -218,7 +232,7 @@ dependencies = [
[[package]]
name = "riscv"
version = "0.3.0"
source = "git+https://github.com/riscv-and-rust-and-decaf/riscv#f358204af01f2374ab6ed6ea059f724cd5f2fe6f"
source = "git+https://github.com/riscv-and-rust-and-decaf/riscv#966eb26d5e8d77677f645d5e32877c678dcee572"
dependencies = [
"bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bit_field 0.9.0 (registry+https://github.com/rust-lang/crates.io-index)",
@ -302,6 +316,7 @@ dependencies = [
name = "ucore"
version = "0.1.0"
dependencies = [
"aarch64 2.2.2 (git+https://github.com/equation314/aarch64)",
"apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)",
"atags 0.1.0",
"bbl 0.1.0",
@ -311,7 +326,6 @@ dependencies = [
"bitflags 1.0.4 (registry+https://github.com/rust-lang/crates.io-index)",
"bootloader 0.3.4 (git+https://github.com/wangrunji0408/bootloader)",
"cc 1.0.25 (registry+https://github.com/rust-lang/crates.io-index)",
"cortex-a 2.2.2 (registry+https://github.com/rust-lang/crates.io-index)",
"lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)",
"linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)",
"log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)",
@ -324,7 +338,7 @@ dependencies = [
"uart_16550 0.1.0 (registry+https://github.com/rust-lang/crates.io-index)",
"ucore-memory 0.1.0",
"ucore-process 0.1.0",
"volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)",
"volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)",
"x86_64 0.3.4 (registry+https://github.com/rust-lang/crates.io-index)",
"xmas-elf 0.6.2 (registry+https://github.com/rust-lang/crates.io-index)",
]
@ -361,7 +375,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
name = "volatile"
version = "0.2.4"
version = "0.2.5"
source = "registry+https://github.com/rust-lang/crates.io-index"
[[package]]
@ -431,6 +445,7 @@ version = "0.1.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
[metadata]
"checksum aarch64 2.2.2 (git+https://github.com/equation314/aarch64)" = "<none>"
"checksum apic 0.1.0 (git+https://github.com/wangrunji0408/APIC-Rust)" = "<none>"
"checksum array-init 0.0.4 (registry+https://github.com/rust-lang/crates.io-index)" = "23589ecb866b460d3a0f1278834750268c607e8e28a1b982c907219f3178cd72"
"checksum bare-metal 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "a3caf393d93b2d453e80638d0674597020cef3382ada454faacd43d1a55a735a"
@ -446,7 +461,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum fuchsia-zircon-sys 0.3.3 (registry+https://github.com/rust-lang/crates.io-index)" = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
"checksum getopts 0.2.18 (registry+https://github.com/rust-lang/crates.io-index)" = "0a7292d30132fb5424b354f5dc02512a86e4c516fe544bb7a25e7f266951b797"
"checksum lazy_static 1.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "a374c89b9db55895453a74c1e38861d9deec0b01b405a82516e9d5de4820dea1"
"checksum libc 0.2.43 (registry+https://github.com/rust-lang/crates.io-index)" = "76e3a3ef172f1a0b9a9ff0dd1491ae5e6c948b94479a3021819ba7d860c8645d"
"checksum libc 0.2.44 (registry+https://github.com/rust-lang/crates.io-index)" = "10923947f84a519a45c8fefb7dd1b3e8c08747993381adee176d7a82b4195311"
"checksum linked_list_allocator 0.6.3 (registry+https://github.com/rust-lang/crates.io-index)" = "655d57c71827fe0891ce72231b6aa5e14033dae3f604609e6a6f807267c1678d"
"checksum log 0.4.6 (registry+https://github.com/rust-lang/crates.io-index)" = "c84ec4b527950aa83a329754b01dbe3f58361d1c5efacd1f6d68c494d08a17c6"
"checksum nodrop 0.1.13 (registry+https://github.com/rust-lang/crates.io-index)" = "2f9667ddcc6cc8a43afc9b7917599d7216aa09c463919ea32c59ed6cac8bc945"
@ -472,7 +487,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
"checksum unicode-width 0.1.5 (registry+https://github.com/rust-lang/crates.io-index)" = "882386231c45df4700b275c7ff55b6f3698780a650026380e72dabe76fa46526"
"checksum usize_conversions 0.2.0 (registry+https://github.com/rust-lang/crates.io-index)" = "f70329e2cbe45d6c97a5112daad40c34cd9a4e18edb5a2a18fefeb584d8d25e5"
"checksum ux 0.1.2 (registry+https://github.com/rust-lang/crates.io-index)" = "53d8df5dd8d07fedccd202de1887d94481fadaea3db70479f459e8163a1fab41"
"checksum volatile 0.2.4 (registry+https://github.com/rust-lang/crates.io-index)" = "54d4343a2df2d65144a874f95950754ee7b7e8594f6027aae8c7d0f4858a3fe8"
"checksum volatile 0.2.5 (registry+https://github.com/rust-lang/crates.io-index)" = "d9ca391c55768e479d5c2f8beb40c136df09257292a809ea514e82cfdfc15d00"
"checksum winapi 0.3.6 (registry+https://github.com/rust-lang/crates.io-index)" = "92c1eb33641e276cfa214a0522acad57be5c56b10cb348b3c5117db75f3ac4b0"
"checksum winapi-i686-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
"checksum winapi-x86_64-pc-windows-gnu 0.4.0 (registry+https://github.com/rust-lang/crates.io-index)" = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"

View File

@ -5,8 +5,13 @@ authors = ["Runji Wang <wangrunji0408@163.com>"]
edition = "2018"
[features]
link_user_program = []
# Without BBL (for riscv32 FPGA board)
no_bbl = []
# Disable paging (for riscv32)
no_mmu = []
# Kernel in M-mode (for riscv32)
m_mode = ["no_mmu"]
# (for aarch64 RaspberryPi3)
board_raspi3 = []
[profile.dev]
@ -46,7 +51,7 @@ riscv = { git = "https://github.com/riscv-and-rust-and-decaf/riscv" }
bbl = { path = "../crate/bbl" }
[target.'cfg(target_arch = "aarch64")'.dependencies]
cortex-a = "2.2.1"
aarch64 = { git = "https://github.com/equation314/aarch64" }
atags = { path = "../crate/atags" }
bcm2837 = { path = "../crate/bcm2837", features = ["use_generic_timer"] }
@ -58,7 +63,7 @@ minimum-image-size = 0 # The minimum output file size (in MiB)
# (the "{}" will be replaced with the path to the bootable disk image)
run-command = ["qemu-system-x86_64",
"-drive", "format=raw,file={}",
"-drive", "format=raw,file=../user/ucore32.img,media=disk,cache=writeback",
"-drive", "format=raw,file=../user/img/ucore-i386-pic.img,media=disk,cache=writeback",
"-serial", "mon:stdio",
"-device", "isa-debug-exit",
"-smp", "4"

View File

@ -13,15 +13,19 @@
# mode = debug | release
# LOG = off | error | warn | info | debug | trace
# SFSIMG = SFS image path of user programs
# smp SMP core number
# smp = 1 | 2 | ... SMP core number
# board = fpga Only available on riscv32, build without bbl, run on board
# | raspi3 Only available on aarch64, run on Raspberry Pi 3 Model B/B+
# m_mode Only available on riscv32, build for M-Mode, without MMU
arch ?= riscv32
board ?= raspi3
mode ?= debug
LOG ?= debug
smp ?= 4
# NOTE: crate 'process' use this name 'm_mode' as an environment
# to set interrupt (MIE or SIE)
m_mode ?=
target := $(arch)-blog_os
kernel := target/$(target)/$(mode)/ucore
@ -37,50 +41,53 @@ export ARCH = $(arch)
export SFSIMG = $(user_dir)/build/user-$(arch).img
### qemu options ###
ifeq ($(arch), x86_64)
qemu_opts := \
-drive format=raw,file=$(bootimage) \
-drive format=raw,file=$(SFSIMG),media=disk,cache=writeback \
-smp cores=$(smp) \
-serial mon:stdio \
-device isa-debug-exit \
-nographic
ifeq ($(arch), x86_64)
qemu_opts += \
-drive format=raw,file=$(bootimage) \
-drive format=raw,file="../user/img/ucore-i386-pic.img",media=disk,cache=writeback \
-serial mon:stdio \
-device isa-debug-exit
else ifeq ($(arch), riscv32)
qemu_opts := \
qemu_opts += \
-machine virt \
-kernel $(bin) \
-nographic \
-smp cores=$(smp)
-kernel $(bin)
ifdef m_mode
qemu_opts += -cpu rv32imacu-nommu
endif
else ifeq ($(arch), aarch64)
qemu_opts := \
qemu_opts += \
-machine $(board) \
-serial null -serial mon:stdio \
-nographic \
-kernel $(bin)
endif
ifdef d
qemu_opts := $(qemu_opts) -d $(d)
qemu_opts += -d $(d)
endif
### build args ###
ifeq ($(arch), riscv32)
ifeq ($(board), fpga)
features := $(features) no_bbl
features += no_bbl
endif
endif
# Link user binaries at ../user
ifdef link_user
features := $(features) link_user_program
assembly_object_files := $(assembly_object_files) $(user_obj)
ifdef m_mode
features += no_mmu m_mode
bbl_m_mode := --enable-boot-machine
endif
features := $(features) board_$(board)
features += board_$(board)
build_args := --target $(target).json --features "$(features)"
ifeq ($(mode), release)
build_args := $(build_args) --release
build_args += --release
endif
@ -149,8 +156,8 @@ else
mkdir -p build && \
cd build && \
../configure \
--enable-32bit \
--enable-logo \
$(bbl_m_mode) \
--with-arch=rv32imac \
--disable-fp-emulation \
--host=riscv64-unknown-elf \
--with-payload=$(abspath $(kernel)) && \
@ -175,7 +182,6 @@ endif
endif
### user programs ###
sfsimg:
@cd $(user_dir) && make sfsimg
@ -186,7 +192,6 @@ $(user_obj): $(user_bins)
$(ld) -o $(abspath $@) $(patsubst %, -b binary %, $(notdir $(user_bins)))
### install ###
ifeq ($(board), raspi3)
sd_card ?=

View File

@ -1,16 +1,18 @@
//! Raspberry PI 3 Model B/B+
use once::*;
pub mod irq;
pub mod timer;
pub mod serial;
pub fn init() {
// FIXME
// assert_has_not_been_called!("board::init must be called only once");
pub const IO_REMAP_BASE: usize = bcm2837::IO_BASE;
pub const IO_REMAP_END: usize = 0x40001000;
unsafe {
serial::SERIAL_PORT.init();
}
pub fn init() {
assert_has_not_been_called!("board::init must be called only once");
serial::SERIAL_PORT.lock().init();
println!("Hello Raspberry Pi!");
}

View File

@ -1,6 +1,7 @@
use bcm2837::mini_uart::MiniUart;
use core::fmt;
use spin::Mutex;
use once::*;
/// Struct to get a global SerialPort interface
pub struct SerialPort {
@ -19,8 +20,7 @@ impl SerialPort {
/// Init a newly created SerialPort, can only be called once.
pub fn init(&mut self) {
// FIXME
// assert_has_not_been_called!("SerialPort::init must be called only once");
assert_has_not_been_called!("SerialPort::init must be called only once");
self.mu = Some(MiniUart::new());
}
@ -70,7 +70,4 @@ impl fmt::Write for SerialPort {
}
}
// FIXME
// pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());
pub static mut SERIAL_PORT: SerialPort = SerialPort::new();
pub static SERIAL_PORT: Mutex<SerialPort> = Mutex::new(SerialPort::new());

View File

@ -2,8 +2,7 @@
.section .text.boot
.global _start
_start:
boot:
# read cpu affinity, start core 0, halt rest
mrs x1, mpidr_el1
and x1, x1, #3
@ -16,7 +15,7 @@ halt:
setup:
# store the desired EL1 stack pointer in x1
adr x1, _start
ldr x1, =_start
# use SP_ELx for Exception level ELx
msr SPsel, #1
@ -94,17 +93,22 @@ set_stack:
zero_bss:
# load the start address and number of bytes in BSS section
ldr x1, =__bss_start
ldr x1, =sbss
ldr x2, =__bss_length
zero_bss_loop:
# zero out the BSS section, 64-bits at a time
cbz x2, go_kmain
cbz x2, zero_bss_loop_end
str xzr, [x1], #8
sub x2, x2, #8
cbnz x2, zero_bss_loop
go_kmain:
zero_bss_loop_end:
b _start
.section .text.entry
.globl _start
_start:
# jump to rust_main, which shouldn't return. halt if it does
bl rust_main
b halt

View File

@ -3,36 +3,49 @@ ENTRY(_start)
SECTIONS {
. = 0x80000; /* Raspbery Pi 3 Aarch64 (kernel8.img) load address */
/* start of the binary */
_start = .;
.boot : {
KEEP(*(.text.boot)) /* from boot.S */
}
. = 0x100000; /* Load the kernel at this address. It's also kernel stack top address */
bootstacktop = .;
.text : {
KEEP(*(.text.boot)) /* from boot.S */
stext = .;
*(.text.entry)
*(.text .text.* .gnu.linkonce.t*)
. = ALIGN(4K);
etext = .;
}
.rodata : {
srodata = .;
*(.rodata .rodata.* .gnu.linkonce.r*)
. = ALIGN(4K);
erodata = .;
}
.data : {
sdata = .;
*(.data .data.* .gnu.linkonce.d*)
. = ALIGN(4K);
edata = .;
}
.bss (NOLOAD) : {
. = ALIGN(32);
__bss_start = .;
sbss = .;
*(.bss .bss.*)
*(COMMON)
. = ALIGN(8);
__bss_end = .;
. = ALIGN(4K);
ebss = .;
}
/* end of the binary */
_end = ALIGN(8);
/* number of bytes in BSS section and complete binary */
__bss_length = (__bss_end - __bss_start);
__bss_length = (ebss - sbss);
__binary_length = (_end - _start);
/DISCARD/ : { *(.comment) *(.gnu*) *(.note*) *(.eh_frame*) }

View File

@ -1,11 +1,8 @@
//! TODO: replace unmiplemented consts with real value
const UNIMPLEMENTED: usize = 0;
pub const KERNEL_OFFSET: usize = UNIMPLEMENTED;
pub const KERNEL_PML4: usize = UNIMPLEMENTED;
pub const KERNEL_HEAP_OFFSET: usize = UNIMPLEMENTED;
pub const RECURSIVE_INDEX: usize = 0o777;
pub const KERNEL_OFFSET: usize = 0;
pub const KERNEL_PML4: usize = 0;
pub const KERNEL_HEAP_SIZE: usize = 8 * 1024 * 1024;
pub const MEMORY_OFFSET: usize = UNIMPLEMENTED;
pub const MEMORY_END: usize = UNIMPLEMENTED;
pub const USER_STACK_OFFSET: usize = UNIMPLEMENTED;
pub const USER_STACK_SIZE: usize = UNIMPLEMENTED;
pub const USER32_STACK_OFFSET: usize = UNIMPLEMENTED;
pub const MEMORY_OFFSET: usize = 0;
pub const USER_STACK_OFFSET: usize = 0xffff_8000_0000_0000;
pub const USER_STACK_SIZE: usize = 1 * 1024 * 1024;
pub const USER32_STACK_OFFSET: usize = USER_STACK_OFFSET;

View File

@ -1,12 +1,19 @@
//! TrapFrame and context definitions for aarch64.
use spin::Mutex;
use lazy_static::lazy_static;
use aarch64::barrier;
use aarch64::addr::PhysAddr;
use aarch64::paging::PhysFrame;
use aarch64::asm::{tlb_invalidate_all, ttbr_el1_write_asid};
#[repr(C)]
#[derive(Default, Debug, Copy, Clone)]
pub struct TrapFrame {
pub elr: usize,
pub spsr: usize,
pub sp: usize,
pub tpidr: usize,
pub tpidr: usize, // currently unused
// pub q0to31: [u128; 32], // disable SIMD/FP registers
pub x1to29: [usize; 29],
pub __reserved: usize,
@ -47,10 +54,14 @@ pub struct InitStack {
}
impl InitStack {
unsafe fn push_at(self, stack_top: usize) -> Context {
unsafe fn push_at(self, stack_top: usize, ttbr: usize) -> Context {
let ptr = (stack_top as *mut Self).offset(-1);
*ptr = self;
Context(ptr as usize)
Context {
stack_top: ptr as usize,
ttbr: PhysFrame::containing_address(PhysAddr::new(ttbr as u64)),
asid: Asid::default(),
}
}
}
@ -63,18 +74,20 @@ extern {
struct ContextData {
x19to29: [usize; 11],
lr: usize,
ttbr0: usize,
}
impl ContextData {
fn new(ttbr0: usize) -> Self {
ContextData { lr: __trapret as usize, ttbr0, ..ContextData::default() }
fn new() -> Self {
ContextData { lr: __trapret as usize, ..ContextData::default() }
}
}
#[derive(Debug)]
pub struct Context(usize);
pub struct Context {
stack_top: usize,
ttbr: PhysFrame,
asid: Asid,
}
impl Context {
/// Switch to another kernel thread.
@ -86,10 +99,10 @@ impl Context {
/// Pop all callee-saved registers, then return to the target.
#[naked]
#[inline(never)]
pub unsafe extern fn switch(&mut self, target: &mut Self) {
unsafe extern fn __switch(self_stack: &mut usize, target_stack: &mut usize) {
asm!(
"
mov x10, #-(13 * 8)
mov x10, #-(12 * 8)
add x8, sp, x10
str x8, [x0]
stp x19, x20, [x8], #16 // store callee-saved registers
@ -98,8 +111,6 @@ impl Context {
stp x25, x26, [x8], #16
stp x27, x28, [x8], #16
stp x29, lr, [x8], #16
mrs x9, ttbr0_el1
str x9, [x8], #8
ldr x8, [x1]
ldp x19, x20, [x8], #16 // restore callee-saved registers
@ -108,50 +119,94 @@ impl Context {
ldp x25, x26, [x8], #16
ldp x27, x28, [x8], #16
ldp x29, lr, [x8], #16
ldr x9, [x8], #8
mov sp, x8
msr ttbr0_el1, x9 // set new page directory
dsb ishst // ensure write has completed
tlbi vmalle1is // invalidate the TLB entry for the entry that changes
dsb ish // ensure TLB invalidation is complete
isb // synchronize context on this processor
str xzr, [x1]
ret"
: : : : "volatile" );
}
pub unsafe fn null() -> Self {
Context(0)
pub unsafe fn switch(&mut self, target: &mut Self) {
target.asid = ASID_ALLOCATOR.lock().alloc(target.asid);
// with ASID we needn't flush TLB frequently
ttbr_el1_write_asid(1, target.asid.value, target.ttbr);
barrier::dsb(barrier::ISH);
Self::__switch(&mut self.stack_top, &mut target.stack_top);
}
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, ttbr0: usize) -> Self {
pub unsafe fn null() -> Self {
Context {
stack_top: 0,
ttbr: PhysFrame::containing_address(PhysAddr::new(0)),
asid: Asid::default(),
}
}
pub unsafe fn new_kernel_thread(entry: extern fn(usize) -> !, arg: usize, kstack_top: usize, ttbr: usize) -> Self {
InitStack {
context: ContextData::new(ttbr0),
context: ContextData::new(),
tf: TrapFrame::new_kernel_thread(entry, arg, kstack_top),
}.push_at(kstack_top)
}.push_at(kstack_top, ttbr)
}
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, ttbr0: usize) -> Self {
pub unsafe fn new_user_thread(entry_addr: usize, ustack_top: usize, kstack_top: usize, is32: bool, ttbr: usize) -> Self {
InitStack {
context: ContextData::new(ttbr0),
context: ContextData::new(),
tf: TrapFrame::new_user_thread(entry_addr, ustack_top),
}.push_at(kstack_top)
}.push_at(kstack_top, ttbr)
}
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, ttbr0: usize) -> Self {
pub unsafe fn new_fork(tf: &TrapFrame, kstack_top: usize, ttbr: usize) -> Self {
InitStack {
context: ContextData::new(ttbr0),
context: ContextData::new(),
tf: {
let mut tf = tf.clone();
tf.x0 = 0;
tf
},
}.push_at(kstack_top)
}.push_at(kstack_top, ttbr)
}
/// Called at a new user context
/// To get the init TrapFrame in sys_exec
pub unsafe fn get_init_tf(&self) -> TrapFrame {
(*(self.0 as *const InitStack)).tf.clone()
(*(self.stack_top as *const InitStack)).tf.clone()
}
}
const ASID_MASK: u16 = 0xffff;
#[derive(Debug, Copy, Clone, Default)]
#[repr(C)]
struct Asid {
value: u16,
generation: u16,
}
struct AsidAllocator(Asid);
impl AsidAllocator {
fn new() -> Self {
AsidAllocator(Asid { value: 0, generation: 1 })
}
fn alloc(&mut self, old_asid: Asid) -> Asid {
if self.0.generation == old_asid.generation {
return old_asid;
}
if self.0.value == ASID_MASK {
self.0.value = 0;
self.0.generation = self.0.generation.wrapping_add(1);
if self.0.generation == 0 {
self.0.generation += 1;
}
tlb_invalidate_all();
}
self.0.value += 1;
return self.0;
}
}
lazy_static! {
static ref ASID_ALLOCATOR: Mutex<AsidAllocator> = Mutex::new(AsidAllocator::new());
}

View File

@ -2,7 +2,9 @@
use crate::arch::board::irq::handle_irq;
use super::context::TrapFrame;
use super::syndrome::Syndrome;
use super::syndrome::{Fault, Syndrome};
use aarch64::regs::*;
use log::*;
global_asm!(include_str!("trap.S"));
@ -39,14 +41,22 @@ pub struct Info {
/// the trap frame for the exception.
#[no_mangle]
pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) {
let syndrome = Syndrome::from(esr);
trace!("Interrupt: {:?} from: {:?}", syndrome, info);
trace!("Interrupt: {:?}, ELR: {:#x?}", info, tf.elr);
match info.kind {
Kind::Synchronous => {
let syndrome = Syndrome::from(esr);
trace!("ESR: {:#x?}, Syndrome: {:?}", esr, syndrome);
// syndrome is only valid with sync
match syndrome {
Syndrome::Brk(brk) => handle_break(brk, tf),
Syndrome::Svc(_) => handle_syscall(tf),
Syndrome::Svc(svc) => handle_syscall(svc, tf),
Syndrome::DataAbort { kind, level: _ }
| Syndrome::InstructionAbort { kind, level: _ } => match kind {
Fault::Translation | Fault::AccessFlag | Fault::Permission => {
handle_page_fault(tf)
}
_ => crate::trap::error(tf),
},
_ => crate::trap::error(tf),
}
}
@ -56,12 +66,16 @@ pub extern "C" fn rust_trap(info: Info, esr: u32, tf: &mut TrapFrame) {
trace!("Interrupt end");
}
fn handle_break(num: u16, tf: &mut TrapFrame) {
fn handle_break(_num: u16, tf: &mut TrapFrame) {
// Skip the current brk instruction (ref: J1.1.2, page 6147)
tf.elr += 4;
}
fn handle_syscall(tf: &mut TrapFrame) {
fn handle_syscall(num: u16, tf: &mut TrapFrame) {
if num != 0 {
crate::trap::error(tf);
}
// svc instruction has been skipped in syscall (ref: J1.1.2, page 6152)
let ret = crate::syscall::syscall(
tf.x1to29[7] as usize,
@ -77,3 +91,10 @@ fn handle_syscall(tf: &mut TrapFrame) {
);
tf.x0 = ret as usize;
}
fn handle_page_fault(tf: &mut TrapFrame) {
let addr = FAR_EL1.get();
error!("\nEXCEPTION: Page Fault @ {:#x}", addr);
crate::trap::error(tf);
}

View File

@ -4,7 +4,8 @@ mod handler;
mod context;
mod syndrome;
use cortex_a::regs::*;
use aarch64::regs::*;
pub use self::context::*;
pub use self::handler::*;

View File

@ -4,15 +4,11 @@ use core::fmt::{Arguments, Write};
use super::board::serial::{SerialRead, SERIAL_PORT};
pub fn getchar() -> char {
// FIXME
unsafe {
SERIAL_PORT.receive() as char
}
unsafe { SERIAL_PORT.force_unlock(); }
SERIAL_PORT.lock().receive() as char
}
pub fn putfmt(fmt: Arguments) {
// FIXME
unsafe {
SERIAL_PORT.write_fmt(fmt).unwrap()
}
unsafe { SERIAL_PORT.force_unlock(); }
SERIAL_PORT.lock().write_fmt(fmt).unwrap()
}

View File

@ -1,29 +1,125 @@
//! Memory initialization for aarch64.
use log::*;
use ucore_memory::PAGE_SIZE;
use atags::atags::Atags;
use crate::HEAP_ALLOCATOR;
use log::*;
use aarch64::{barrier, regs::*, addr::*};
use aarch64::paging::{PhysFrame as Frame, memory_attribute::*};
use crate::memory::{FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet};
/// Memory initialization.
pub fn init() {
let (start, end) = memory_map().expect("failed to find memory map");
unsafe {
HEAP_ALLOCATOR.lock().init(start, end - start);
}
init_frame_allocator();
init_heap();
remap_the_kernel();
info!("memory: init end");
}
extern "C" {
static _end: u8;
/// initialize temporary paging and enable mmu immediately after boot. Serial port is disabled at this time.
pub fn init_mmu_early() {
#[repr(align(4096))]
struct PageData([u8; PAGE_SIZE]);
static PAGE_TABLE_LVL4: PageData = PageData([0; PAGE_SIZE]);
static PAGE_TABLE_LVL3: PageData = PageData([0; PAGE_SIZE]);
static PAGE_TABLE_LVL2: PageData = PageData([0; PAGE_SIZE]);
let frame_lvl4 = Frame::containing_address(PhysAddr::new(&PAGE_TABLE_LVL4 as *const _ as u64));
let frame_lvl3 = Frame::containing_address(PhysAddr::new(&PAGE_TABLE_LVL3 as *const _ as u64));
let frame_lvl2 = Frame::containing_address(PhysAddr::new(&PAGE_TABLE_LVL2 as *const _ as u64));
super::paging::setup_temp_page_table(frame_lvl4, frame_lvl3, frame_lvl2);
// device.
MAIR_EL1.write(
MAIR_EL1::Attr0.val(MairDevice::config_value()) +
MAIR_EL1::Attr1.val(MairNormal::config_value()) +
MAIR_EL1::Attr2.val(MairNormalNonCacheable::config_value()),
);
// Configure various settings of stage 1 of the EL1 translation regime.
let ips = ID_AA64MMFR0_EL1.read(ID_AA64MMFR0_EL1::PARange);
TCR_EL1.write(
TCR_EL1::TBI1::Ignored +
TCR_EL1::TBI0::Ignored +
TCR_EL1::AS::Bits_16 +
TCR_EL1::IPS.val(ips) +
TCR_EL1::TG1::KiB_4 +
TCR_EL1::SH1::Inner +
TCR_EL1::ORGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::IRGN1::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::EPD1::EnableTTBR1Walks +
TCR_EL1::A1::UseTTBR1ASID +
TCR_EL1::T1SZ.val(16) +
TCR_EL1::TG0::KiB_4 +
TCR_EL1::SH0::Inner +
TCR_EL1::ORGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::IRGN0::WriteBack_ReadAlloc_WriteAlloc_Cacheable +
TCR_EL1::EPD0::EnableTTBR0Walks +
TCR_EL1::T0SZ.val(16),
);
// Switch the MMU on.
//
// First, force all previous changes to be seen before the MMU is enabled.
unsafe { barrier::isb(barrier::SY); }
// Enable the MMU and turn on data and instruction caching.
SCTLR_EL1.modify(SCTLR_EL1::M::Enable + SCTLR_EL1::C::Cacheable + SCTLR_EL1::I::Cacheable);
// Force MMU init to complete before next instruction
unsafe { barrier::isb(barrier::SY); }
}
fn init_frame_allocator() {
use bit_allocator::BitAlloc;
use core::ops::Range;
use crate::consts::MEMORY_OFFSET;
let (start, end) = memory_map().expect("failed to find memory map");
let mut ba = FRAME_ALLOCATOR.lock();
ba.insert(to_range(start, end));
info!("FrameAllocator init end");
/*
* @param:
* start: start address
* end: end address
* @brief:
* transform the memory address to the page number
* @retval:
* the page number range from start address to end address
*/
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;
page_start..page_end
}
}
/// remap kernel page table after all initialization.
fn remap_the_kernel() {
let mut ms = unsafe { MemorySet::new_bare() };
ms.push(MemoryArea::new_identity(0, bootstacktop as usize, MemoryAttr::default(), "kstack"));
ms.push(MemoryArea::new_identity(stext as usize, etext as usize, MemoryAttr::default().execute().readonly(), "text"));
ms.push(MemoryArea::new_identity(sdata as usize, edata as usize, MemoryAttr::default(), "data"));
ms.push(MemoryArea::new_identity(srodata as usize, erodata as usize, MemoryAttr::default().readonly(), "rodata"));
ms.push(MemoryArea::new_identity(sbss as usize, ebss as usize, MemoryAttr::default(), "bss"));
use super::board::{IO_REMAP_BASE, IO_REMAP_END};
ms.push(MemoryArea::new_identity(IO_REMAP_BASE, IO_REMAP_END, MemoryAttr::default().mmio(), "io_remap"));
unsafe { ms.get_page_table_mut().activate_as_kernel(); }
::core::mem::forget(ms);
info!("kernel remap end");
}
/// Returns the (start address, end address) of the available memory on this
/// system if it can be determined. If it cannot, `None` is returned.
///
/// This function is expected to return `Some` under all normal cirumstances.
pub fn memory_map() -> Option<(usize, usize)> {
let binary_end = unsafe { (&_end as *const u8) as u32 };
fn memory_map() -> Option<(usize, usize)> {
let binary_end = _end as u32;
let mut atags: Atags = Atags::get();
while let Some(atag) = atags.next() {
@ -34,3 +130,17 @@ pub fn memory_map() -> Option<(usize, usize)> {
None
}
extern {
fn bootstacktop();
fn stext();
fn etext();
fn sdata();
fn edata();
fn srodata();
fn erodata();
fn sbss();
fn ebss();
fn _start();
fn _end();
}

View File

@ -18,31 +18,23 @@ global_asm!(include_str!("boot/boot.S"));
/// The entry point of kernel
#[no_mangle] // don't mangle the name of this function
pub extern "C" fn rust_main() -> ! {
// Enable mmu and paging
memory::init_mmu_early();
// Init board to enable serial port.
board::init();
crate::logging::init(); // FIXME
println!("{}", LOGO);
crate::logging::init();
interrupt::init();
memory::init();
timer::init();
use crate::process::{processor, ContextImpl};
crate::process::init();
processor().manager().add(ContextImpl::new_kernel(kernel_proc2, 2333), 0);
processor().manager().add(ContextImpl::new_user_test(kernel_proc3), 0);
crate::kmain();
}
extern fn kernel_proc2(arg: usize) -> ! {
use alloc::format;
test_shell(&format!("proc2-{}>> ", arg));
}
extern fn kernel_proc3(arg: usize) -> ! {
use alloc::format;
test_shell(&format!("proc3-{}$ ", arg));
}
const LOGO: &str = r#"
____ __ ____ _____
/ __ \ __ __ _____ / /_ / __ \/ ___/
@ -50,50 +42,3 @@ const LOGO: &str = r#"
/ _, _// /_/ /(__ )/ /_ / /_/ /___/ /
/_/ |_| \__,_//____/ \__/ \____//____/
"#;
pub fn show_logo() {
println!("{}", LOGO);
}
#[inline(always)]
fn sys_call(id: usize, arg0: usize, arg1: usize, arg2: usize, arg3: usize, arg4: usize, arg5: usize) -> i32 {
let ret: i32;
unsafe {
asm!("svc 0"
: "={x0}" (ret)
: "{x8}" (id), "{x0}" (arg0), "{x1}" (arg1), "{x2}" (arg2), "{x3}" (arg3), "{x4}" (arg4), "{x5}" (arg5)
: "memory"
: "volatile");
}
ret
}
pub fn test_shell(prefix: &str) -> ! {
show_logo();
loop {
print!("{}", prefix);
loop {
let c = io::getchar();
match c {
'\u{7f}' => {
print!("\u{7f}");
}
'c' => unsafe {
print!("sys_putc: ");
sys_call(30, 'A' as usize, 0, 0, 0, 0, 0);
},
't' => unsafe {
println!("sys_get_time: {}", sys_call(17, 0, 0, 0, 0, 0, 0));
},
' '...'\u{7e}' => {
print!("{}", c);
}
'\n' | '\r' => {
print!("\n");
break;
}
_ => {}
}
}
}
}

View File

@ -1,222 +1,310 @@
//! Page table implementations for aarch64.
use ucore_memory::memory_set::*;
use ucore_memory::PAGE_SIZE;
use ucore_memory::paging::*;
type VirtAddr = usize;
type PhysAddr = usize;
use alloc::alloc::{alloc, Layout};
use aarch64::asm::{tlb_invalidate, tlb_invalidate_all, flush_icache_all, ttbr_el1_read, ttbr_el1_write};
use aarch64::{PhysAddr, VirtAddr};
use aarch64::paging::{Mapper, PageTable as Aarch64PageTable, PageTableEntry, PageTableFlags as EF, RecursivePageTable};
use aarch64::paging::{FrameAllocator, FrameDeallocator, Page, PhysFrame as Frame, Size4KiB, Size2MiB, Size1GiB};
use aarch64::paging::memory_attribute::*;
use log::*;
// Depends on kernel
use crate::consts::{KERNEL_PML4, RECURSIVE_INDEX};
use crate::memory::{active_table, alloc_frame, dealloc_frame};
/// TODO
pub struct ActivePageTable {
// TODO
}
// need 3 page
pub fn setup_temp_page_table(frame_lvl4: Frame, frame_lvl3: Frame, frame_lvl2: Frame) {
let p4 = unsafe { &mut *(frame_lvl4.start_address().as_u64() as *mut Aarch64PageTable) };
let p3 = unsafe { &mut *(frame_lvl3.start_address().as_u64() as *mut Aarch64PageTable) };
let p2 = unsafe { &mut *(frame_lvl2.start_address().as_u64() as *mut Aarch64PageTable) };
p4.zero();
p3.zero();
p2.zero();
impl ActivePageTable {
/// TODO
pub unsafe fn new() -> Self {
unimplemented!()
let (start_addr, end_addr) = (0, 0x40000000);
let block_flags = EF::VALID | EF::AF | EF::WRITE | EF::XN;
for page in Page::<Size2MiB>::range_of(start_addr, end_addr) {
let paddr = PhysAddr::new(page.start_address().as_u64());
use super::board::IO_REMAP_BASE;
if paddr.as_u64() >= IO_REMAP_BASE as u64 {
p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags | EF::PXN, MairDevice::attr_value());
} else {
p2[page.p2_index()].set_block::<Size2MiB>(paddr, block_flags, MairNormal::attr_value());
}
}
pub fn token() -> usize {
unimplemented!()
}
p3[0].set_frame(frame_lvl2, EF::default(), MairNormal::attr_value());
p3[1].set_block::<Size1GiB>(PhysAddr::new(0x40000000), block_flags | EF::PXN, MairDevice::attr_value());
p4[0].set_frame(frame_lvl3, EF::default(), MairNormal::attr_value());
p4[RECURSIVE_INDEX].set_frame(frame_lvl4, EF::default(), MairNormal::attr_value());
ttbr_el1_write(0, frame_lvl4);
tlb_invalidate_all();
}
pub struct ActivePageTable(RecursivePageTable<'static>);
pub struct PageEntry(PageTableEntry);
impl PageTable for ActivePageTable {
type Entry = PageEntry;
fn map(&mut self, addr: VirtAddr, target: PhysAddr) -> &mut Self::Entry {
unimplemented!()
}
fn unmap(&mut self, addr: VirtAddr) {
unimplemented!()
fn map(&mut self, addr: usize, target: usize) -> &mut PageEntry {
let flags = EF::default();
let attr = MairNormal::attr_value();
self.0.map_to(Page::of_addr(addr), Frame::of_addr(target), flags, attr, &mut FrameAllocatorForAarch64)
.unwrap().flush();
self.get_entry(addr).expect("fail to get entry")
}
fn get_entry(&mut self, addr: VirtAddr) -> Option<&mut Self::Entry> {
unimplemented!()
fn unmap(&mut self, addr: usize) {
let (frame, flush) = self.0.unmap(Page::of_addr(addr)).unwrap();
flush.flush();
}
// For testing with mock
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: VirtAddr) -> &'b mut [u8] {
unimplemented!()
fn get_entry(&mut self, addr: usize) -> Option<&mut PageEntry> {
let entry_addr = ((addr >> 9) & 0o777_777_777_7770) | (RECURSIVE_INDEX << 39);
Some(unsafe { &mut *(entry_addr as *mut PageEntry) })
}
fn read(&mut self, addr: VirtAddr) -> u8 {
unimplemented!()
fn get_page_slice_mut<'a, 'b>(&'a mut self, addr: usize) -> &'b mut [u8] {
use core::slice;
unsafe { slice::from_raw_parts_mut((addr & !0xfffusize) as *mut u8, PAGE_SIZE) }
}
fn write(&mut self, addr: VirtAddr, data: u8) {
unimplemented!()
fn read(&mut self, addr: usize) -> u8 {
unsafe { *(addr as *const u8) }
}
fn write(&mut self, addr: usize, data: u8) {
unsafe { *(addr as *mut u8) = data; }
}
}
/// TODO
pub struct PageEntry {
// TODO
const ROOT_PAGE_TABLE: *mut Aarch64PageTable =
((RECURSIVE_INDEX << 39) | (RECURSIVE_INDEX << 30) | (RECURSIVE_INDEX << 21) | (RECURSIVE_INDEX << 12)) as *mut Aarch64PageTable;
impl ActivePageTable {
pub unsafe fn new() -> Self {
ActivePageTable(RecursivePageTable::new(&mut *(ROOT_PAGE_TABLE as *mut _)).unwrap())
}
fn with_temporary_map(&mut self, frame: &Frame, f: impl FnOnce(&mut ActivePageTable, &mut Aarch64PageTable)) {
// Create a temporary page
let page = Page::of_addr(0xcafebabe);
assert!(self.0.translate_page(page).is_none(), "temporary page is already mapped");
// Map it to table
self.map(page.start_address().as_u64() as usize, frame.start_address().as_u64() as usize);
// Call f
let table = unsafe { &mut *page.start_address().as_mut_ptr() };
f(self, table);
// Unmap the page
self.unmap(0xcafebabe);
}
}
impl Entry for PageEntry {
/// IMPORTANT!
/// This must be called after any change to ensure it become effective.
/// Usually this will make a flush to TLB/MMU.
fn update(&mut self) {
unimplemented!()
let addr = VirtAddr::new_unchecked((self as *const _ as u64) << 9);
tlb_invalidate(addr);
}
/// Will be set when accessed
fn accessed(&self) -> bool {
unimplemented!()
}
fn present(&self) -> bool { self.0.flags().contains(EF::VALID) }
fn accessed(&self) -> bool { self.0.flags().contains(EF::AF) }
fn writable(&self) -> bool { self.0.flags().contains(EF::WRITE) }
fn dirty(&self) -> bool { self.hw_dirty() && self.sw_dirty() }
/// Will be set when written
fn dirty(&self) -> bool {
unimplemented!()
fn clear_accessed(&mut self) { self.as_flags().remove(EF::AF); }
fn clear_dirty(&mut self)
{
self.as_flags().remove(EF::DIRTY);
self.as_flags().insert(EF::AP_RO);
}
/// Will PageFault when try to write page where writable=0
fn writable(&self) -> bool {
unimplemented!()
fn set_writable(&mut self, value: bool)
{
self.as_flags().set(EF::AP_RO, !value);
self.as_flags().set(EF::WRITE, value);
}
/// Will PageFault when try to access page where present=0
fn present(&self) -> bool {
unimplemented!()
fn set_present(&mut self, value: bool) { self.as_flags().set(EF::VALID, value); }
fn target(&self) -> usize { self.0.addr().as_u64() as usize }
fn set_target(&mut self, target: usize) {
self.0.modify_addr(PhysAddr::new(target as u64));
}
fn clear_accessed(&mut self) {
unimplemented!()
}
fn clear_dirty(&mut self) {
unimplemented!()
}
fn set_writable(&mut self, value: bool) {
unimplemented!()
}
fn set_present(&mut self, value: bool) {
unimplemented!()
}
fn target(&self) -> PhysAddr {
unimplemented!()
}
fn set_target(&mut self, target: PhysAddr) {
unimplemented!()
}
// For Copy-on-write extension
fn writable_shared(&self) -> bool {
unimplemented!()
}
fn readonly_shared(&self) -> bool {
unimplemented!()
}
fn writable_shared(&self) -> bool { self.0.flags().contains(EF::WRITABLE_SHARED) }
fn readonly_shared(&self) -> bool { self.0.flags().contains(EF::READONLY_SHARED) }
fn set_shared(&mut self, writable: bool) {
unimplemented!()
let flags = self.as_flags();
flags.set(EF::WRITABLE_SHARED, writable);
flags.set(EF::READONLY_SHARED, !writable);
}
fn clear_shared(&mut self) {
unimplemented!()
}
// For Swap extension
fn swapped(&self) -> bool {
unimplemented!()
}
fn set_swapped(&mut self, value: bool) {
unimplemented!()
}
fn user(&self) -> bool {
unimplemented!()
}
fn clear_shared(&mut self) { self.as_flags().remove(EF::WRITABLE_SHARED | EF::READONLY_SHARED); }
fn user(&self) -> bool { self.0.flags().contains(EF::AP_EL0) }
fn swapped(&self) -> bool { self.0.flags().contains(EF::SWAPPED) }
fn set_swapped(&mut self, value: bool) { self.as_flags().set(EF::SWAPPED, value); }
fn set_user(&mut self, value: bool) {
unimplemented!()
self.as_flags().set(EF::AP_EL0, value);
self.as_flags().set(EF::nG, value); // set non-global to use ASID
}
fn execute(&self) -> bool {
unimplemented!()
if self.user() {
!self.0.flags().contains(EF::XN)
} else {
!self.0.flags().contains(EF::PXN)
}
}
fn set_execute(&mut self, value: bool) {
unimplemented!()
if self.user() {
self.as_flags().set(EF::XN, !value)
} else {
self.as_flags().set(EF::PXN, !value)
}
}
fn mmio(&self) -> bool {
self.0.attr().value == MairDevice::attr_value().value
}
fn set_mmio(&mut self, value: bool) {
if value {
self.0.modify_attr(MairDevice::attr_value())
} else {
self.0.modify_attr(MairNormal::attr_value())
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord)]
pub struct MockFrame(PhysAddr);
impl MockFrame {
pub fn of_addr(addr: PhysAddr) -> Self {
MockFrame(addr)
}
pub fn start_address(&self) -> PhysAddr {
unimplemented!()
}
pub fn p2_index(&self) -> usize {
unimplemented!()
}
pub fn p1_index(&self) -> usize {
unimplemented!()
}
pub fn number(&self) -> usize {
unimplemented!()
impl PageEntry {
fn read_only(&self) -> bool { self.0.flags().contains(EF::AP_RO) }
fn hw_dirty(&self) -> bool { self.writable() && !self.read_only() }
fn sw_dirty(&self) -> bool { self.0.flags().contains(EF::DIRTY) }
fn as_flags(&mut self) -> &mut EF {
unsafe { &mut *(self as *mut _ as *mut EF) }
}
}
/// TODO
#[derive(Debug)]
pub struct InactivePageTable0 {
p4_frame: MockFrame,
p4_frame: Frame,
}
/// TODO
impl InactivePageTable for InactivePageTable0 {
type Active = ActivePageTable;
fn new() -> Self {
unsafe {
let layout = Layout::new::<u64>();
let ptr = alloc(layout);
let frame = MockFrame::of_addr(*ptr as usize);
InactivePageTable0 { p4_frame: frame }
}
// When the new InactivePageTable is created for the user MemorySet, it's use ttbr1 as the
// TTBR. And the kernel TTBR ttbr0 will never changed, so we needn't call map_kernel()
Self::new_bare()
}
fn new_bare() -> Self {
unimplemented!()
let frame = Self::alloc_frame().map(|target| Frame::of_addr(target))
.expect("failed to allocate frame");
active_table().with_temporary_map(&frame, |_, table: &mut Aarch64PageTable| {
table.zero();
// set up recursive mapping for the table
table[RECURSIVE_INDEX].set_frame(frame.clone(), EF::default(), MairNormal::attr_value());
});
InactivePageTable0 { p4_frame: frame }
}
fn edit(&mut self, f: impl FnOnce(&mut Self::Active)) {
unimplemented!()
active_table().with_temporary_map(&ttbr_el1_read(0), |active_table, p4_table: &mut Aarch64PageTable| {
let backup = p4_table[RECURSIVE_INDEX].clone();
// overwrite recursive mapping
p4_table[RECURSIVE_INDEX].set_frame(self.p4_frame.clone(), EF::default(), MairNormal::attr_value());
tlb_invalidate_all();
// execute f in the new context
f(active_table);
// restore recursive mapping to original p4 table
p4_table[RECURSIVE_INDEX] = backup;
tlb_invalidate_all();
});
}
unsafe fn activate(&self) {
unimplemented!()
let old_frame = ttbr_el1_read(1);
let new_frame = self.p4_frame.clone();
debug!("switch TTBR1 {:?} -> {:?}", old_frame, new_frame);
if old_frame != new_frame {
ttbr_el1_write(1, new_frame);
tlb_invalidate_all();
}
}
unsafe fn with<T>(&self, f: impl FnOnce() -> T) -> T {
unimplemented!()
// Just need to switch the user TTBR
let old_frame = ttbr_el1_read(1);
let new_frame = self.p4_frame.clone();
debug!("switch TTBR1 {:?} -> {:?}", old_frame, new_frame);
if old_frame != new_frame {
ttbr_el1_write(1, new_frame);
tlb_invalidate_all();
}
let ret = f();
debug!("switch TTBR1 {:?} -> {:?}", new_frame, old_frame);
if old_frame != new_frame {
ttbr_el1_write(1, old_frame);
tlb_invalidate_all();
flush_icache_all();
}
ret
}
fn token(&self) -> usize {
0
self.p4_frame.start_address().as_u64() as usize // as TTBRx_EL1
}
fn alloc_frame() -> Option<PhysAddr> {
fn alloc_frame() -> Option<usize> {
alloc_frame()
}
fn dealloc_frame(target: PhysAddr) {
fn dealloc_frame(target: usize) {
dealloc_frame(target)
}
}
impl InactivePageTable0 {
fn map_kernel(&mut self) {
let table = unsafe { &mut *ROOT_PAGE_TABLE };
let e0 = table[KERNEL_PML4].clone();
assert!(!e0.is_unused());
self.edit(|_| {
table[KERNEL_PML4].set_frame(Frame::containing_address(e0.addr()), EF::default(), MairNormal::attr_value());
});
}
/// Activate as kernel page table (TTBR0).
/// Used in `arch::memory::remap_the_kernel()`.
pub unsafe fn activate_as_kernel(&self) {
let old_frame = ttbr_el1_read(0);
let new_frame = self.p4_frame.clone();
debug!("switch TTBR0 {:?} -> {:?}", old_frame, new_frame);
if old_frame != new_frame {
ttbr_el1_write(0, new_frame);
tlb_invalidate_all();
}
}
}
impl Drop for InactivePageTable0 {
fn drop(&mut self) {
info!("PageTable dropping: {:?}", self);
Self::dealloc_frame(self.p4_frame.start_address().as_u64() as usize);
}
}
struct FrameAllocatorForAarch64;
impl FrameAllocator<Size4KiB> for FrameAllocatorForAarch64 {
fn alloc(&mut self) -> Option<Frame> {
alloc_frame().map(|addr| Frame::of_addr(addr))
}
}
impl FrameDeallocator<Size4KiB> for FrameAllocatorForAarch64 {
fn dealloc(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_u64() as usize);
}
}

View File

@ -1,11 +1,19 @@
# Constants / Macros defined in Rust code:
# xscratch
# xstatus
# xepc
# xcause
# xtval
# XRET
.macro SAVE_ALL
# If coming from userspace, preserve the user stack pointer and load
# the kernel stack pointer. If we came from the kernel, sscratch
# will contain 0, and we should continue on the current stack.
csrrw sp, 0x140, sp # sscratch
csrrw sp, (xscratch), sp
bnez sp, _save_context
_restore_kernel_sp:
csrr sp, 0x140 # sscratch
csrr sp, (xscratch)
# sscratch = previous-sp, sp = kernel-sp
_save_context:
# provide room for trap frame
@ -45,11 +53,11 @@ _save_context:
# get sp, sstatus, sepc, stval, scause
# set sscratch = 0
csrrw s0, 0x140, x0 # sscratch
csrr s1, 0x100 # sstatus
csrr s2, 0x141 # sepc
csrr s3, 0x143 # stval
csrr s4, 0x142 # scause
csrrw s0, (xscratch), x0
csrr s1, (xstatus)
csrr s2, (xepc)
csrr s3, (xtval)
csrr s4, (xcause)
# store sp, sstatus, sepc, sbadvaddr, scause
sw s0, 2*4(sp)
sw s1, 32*4(sp)
@ -65,11 +73,11 @@ _save_context:
bnez s0, _restore_context # back to S-mode? (sstatus.SPP = 1)
_save_kernel_sp:
addi s0, sp, 36*4
csrw 0x140, s0 # sscratch = kernel-sp
csrw (xscratch), s0 # sscratch = kernel-sp
_restore_context:
# restore sstatus, sepc
csrw 0x100, s1
csrw 0x141, s2
csrw (xstatus), s1
csrw (xepc), s2
# restore x registers except x2 (sp)
lw x1, 1*4(sp)
@ -116,4 +124,4 @@ __alltraps:
__trapret:
RESTORE_ALL
# return from supervisor call
sret
XRET

View File

@ -1,13 +1,24 @@
use riscv::register::*;
#[cfg(feature = "m_mode")]
use riscv::register::{
mstatus as xstatus,
mstatus::Mstatus as Xstatus,
mcause::Mcause,
};
#[cfg(not(feature = "m_mode"))]
use riscv::register::{
sstatus as xstatus,
sstatus::Sstatus as Xstatus,
mcause::Mcause,
};
#[derive(Clone)]
#[repr(C)]
pub struct TrapFrame {
pub x: [usize; 32], // general registers
pub sstatus: sstatus::Sstatus, // Supervisor Status Register
pub sstatus: Xstatus, // Supervisor Status Register
pub sepc: usize, // Supervisor exception program counter, save the trap virtual address (here is used to save the process program entry addr?)
pub sbadaddr: usize, // Supervisor bad address
pub scause: scause::Scause, // scause register: record the cause of exception/interrupt/trap
pub stval: usize, // Supervisor trap value
pub scause: Mcause, // scause register: record the cause of exception/interrupt/trap
}
/// Generate the trapframe for building new thread in kernel
@ -28,13 +39,13 @@ impl TrapFrame {
tf.x[10] = arg; // a0
tf.x[2] = sp;
tf.sepc = entry as usize;
tf.sstatus = sstatus::read();
// Supervisor Previous Interrupt Enable
tf.sstatus.set_spie(true);
// Supervisor Interrupt Disable
tf.sstatus.set_sie(false);
// Supervisor Previous Privilege Mode is Supervisor
tf.sstatus.set_spp(sstatus::SPP::Supervisor);
tf.sstatus = xstatus::read();
tf.sstatus.set_xpie(true);
tf.sstatus.set_xie(false);
#[cfg(feature = "m_mode")]
tf.sstatus.set_mpp(xstatus::MPP::Machine);
#[cfg(not(feature = "m_mode"))]
tf.sstatus.set_spp(xstatus::SPP::Supervisor);
tf
}
@ -52,10 +63,13 @@ impl TrapFrame {
let mut tf: Self = unsafe { zeroed() };
tf.x[2] = sp;
tf.sepc = entry_addr;
tf.sstatus = sstatus::read();
tf.sstatus.set_spie(true);
tf.sstatus.set_sie(false);
tf.sstatus.set_spp(sstatus::SPP::User);
tf.sstatus = xstatus::read();
tf.sstatus.set_xpie(true);
tf.sstatus.set_xie(false);
#[cfg(feature = "m_mode")]
tf.sstatus.set_mpp(xstatus::MPP::User);
#[cfg(not(feature = "m_mode"))]
tf.sstatus.set_spp(xstatus::SPP::User);
tf
}
}
@ -78,7 +92,7 @@ impl Debug for TrapFrame {
.field("regs", &Regs(&self.x))
.field("sstatus", &self.sstatus)
.field("sepc", &self.sepc)
.field("sbadaddr", &self.sbadaddr)
.field("stval", &self.stval)
.field("scause", &self.scause)
.finish()
}

View File

@ -1,6 +1,18 @@
use riscv::register::*;
#[cfg(feature = "m_mode")]
use riscv::register::{
mstatus as xstatus,
mscratch as xscratch,
mtvec as xtvec,
};
#[cfg(not(feature = "m_mode"))]
use riscv::register::{
sstatus as xstatus,
sscratch as xscratch,
stvec as xtvec,
};
use riscv::register::{mcause, mepc, sie};
pub use self::context::*;
use crate::memory::{MemorySet, InactivePageTable0, memory_set_record};
use crate::memory::{MemorySet, InactivePageTable0};
use log::*;
#[path = "context.rs"]
@ -17,13 +29,16 @@ pub fn init() {
unsafe {
// Set sscratch register to 0, indicating to exception vector that we are
// presently executing in the kernel
sscratch::write(0);
xscratch::write(0);
// Set the exception vector address
stvec::write(__alltraps as usize, stvec::TrapMode::Direct);
xtvec::write(__alltraps as usize, xtvec::TrapMode::Direct);
// Enable IPI
sie::set_ssoft();
// Enable serial interrupt
sie::set_sext();
// NOTE: In M-mode: mie.MSIE is set by BBL.
// mie.MEIE can not be set in QEMU v3.0
// (seems like a bug)
}
info!("interrupt: init end");
}
@ -34,7 +49,7 @@ pub fn init() {
*/
#[inline(always)]
pub unsafe fn enable() {
sstatus::set_sie();
xstatus::set_xie();
}
/*
@ -45,8 +60,8 @@ pub unsafe fn enable() {
*/
#[inline(always)]
pub unsafe fn disable_and_store() -> usize {
let e = sstatus::read().sie() as usize;
sstatus::clear_sie();
let e = xstatus::read().xie() as usize;
xstatus::clear_xie();
e
}
@ -59,7 +74,7 @@ pub unsafe fn disable_and_store() -> usize {
#[inline(always)]
pub unsafe fn restore(flags: usize) {
if flags != 0 {
sstatus::set_sie();
xstatus::set_xie();
}
}
@ -71,9 +86,15 @@ pub unsafe fn restore(flags: usize) {
*/
#[no_mangle]
pub extern fn rust_trap(tf: &mut TrapFrame) {
use riscv::register::scause::{Trap, Interrupt as I, Exception as E};
use self::mcause::{Trap, Interrupt as I, Exception as E};
trace!("Interrupt @ CPU{}: {:?} ", super::cpu::id(), tf.scause.cause());
match tf.scause.cause() {
// M-mode only
Trap::Interrupt(I::MachineExternal) => serial(),
Trap::Interrupt(I::MachineSoft) => ipi(),
Trap::Interrupt(I::MachineTimer) => timer(),
Trap::Exception(E::MachineEnvCall) => sbi(tf),
Trap::Interrupt(I::SupervisorExternal) => serial(),
Trap::Interrupt(I::SupervisorSoft) => ipi(),
Trap::Interrupt(I::SupervisorTimer) => timer(),
@ -87,6 +108,12 @@ pub extern fn rust_trap(tf: &mut TrapFrame) {
trace!("Interrupt end");
}
/// Call BBL SBI functions for M-mode kernel
fn sbi(tf: &mut TrapFrame) {
(super::BBL.mcall_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc);
tf.sepc += 4;
}
fn serial() {
crate::trap::serial(super::io::getchar());
}
@ -101,8 +128,8 @@ fn ipi() {
* process timer interrupt
*/
fn timer() {
crate::trap::timer();
super::timer::set_next();
crate::trap::timer();
}
/*
@ -124,9 +151,8 @@ fn syscall(tf: &mut TrapFrame) {
* process IllegalInstruction exception
*/
fn illegal_inst(tf: &mut TrapFrame) {
if !emulate_mul_div(tf) {
crate::trap::error(tf);
}
(super::BBL.illegal_insn_trap)(tf.x.as_ptr(), tf.scause.bits(), tf.sepc);
tf.sepc = mepc::read();
}
/*
@ -136,73 +162,10 @@ fn illegal_inst(tf: &mut TrapFrame) {
* process page fault exception
*/
fn page_fault(tf: &mut TrapFrame) {
let addr = stval::read();
let addr = tf.stval;
trace!("\nEXCEPTION: Page Fault @ {:#x}", addr);
if !crate::memory::page_fault_handler(addr) {
crate::trap::error(tf);
}
}
/// Migrate from riscv-pk
/*
* @param:
* TrapFrame: the Trapframe for the illegal inst exception
* @brief:
* emulate the multiply and divide operation (if not this kind of operation return false)
* @retval:
* a bool indicates whether emulate the multiply and divide operation successfully
*/
fn emulate_mul_div(tf: &mut TrapFrame) -> bool {
let insn = unsafe { *(tf.sepc as *const usize) };
let rs1 = tf.x[get_reg(insn, RS1)];
let rs2 = tf.x[get_reg(insn, RS2)];
let rd = if (insn & MASK_MUL) == MATCH_MUL {
rs1 * rs2
} else if (insn & MASK_DIV) == MATCH_DIV {
((rs1 as i32) / (rs2 as i32)) as usize
} else if (insn & MASK_DIVU) == MATCH_DIVU {
rs1 / rs2
} else if (insn & MASK_REM) == MATCH_REM {
((rs1 as i32) % (rs2 as i32)) as usize
} else if (insn & MASK_REMU) == MATCH_REMU {
rs1 % rs2
} else if (insn & MASK_MULH) == MATCH_MULH {
(((rs1 as i32 as i64) * (rs2 as i32 as i64)) >> 32) as usize
} else if (insn & MASK_MULHU) == MATCH_MULHU {
(((rs1 as i64) * (rs2 as i64)) >> 32) as usize
} else if (insn & MASK_MULHSU) == MATCH_MULHSU {
(((rs1 as i32 as i64) * (rs2 as i64)) >> 32) as usize
} else {
return false;
};
tf.x[get_reg(insn, RD)] = rd;
tf.sepc += 4; // jump to next instruction
return true;
fn get_reg(inst: usize, offset: usize) -> usize {
(inst >> offset) & 0x1f
}
const RS1: usize = 15;
const RS2: usize = 20;
const RD: usize = 7;
const MATCH_MUL: usize = 0x2000033;
const MASK_MUL: usize = 0xfe00707f;
const MATCH_MULH: usize = 0x2001033;
const MASK_MULH: usize = 0xfe00707f;
const MATCH_MULHSU: usize = 0x2002033;
const MASK_MULHSU: usize = 0xfe00707f;
const MATCH_MULHU: usize = 0x2003033;
const MASK_MULHU: usize = 0xfe00707f;
const MATCH_DIV: usize = 0x2004033;
const MASK_DIV: usize = 0xfe00707f;
const MATCH_DIVU: usize = 0x2005033;
const MASK_DIVU: usize = 0xfe00707f;
const MATCH_REM: usize = 0x2006033;
const MASK_REM: usize = 0xfe00707f;
const MATCH_REMU: usize = 0x2007033;
const MASK_REMU: usize = 0xfe00707f;
}

View File

@ -20,23 +20,29 @@ impl Write for SerialPort {
}
fn putchar(c: u8) {
#[cfg(feature = "no_bbl")]
unsafe {
while read_volatile(STATUS) & CAN_WRITE == 0 {}
write_volatile(DATA, c as u8);
if cfg!(feature = "no_bbl") {
unsafe {
while read_volatile(STATUS) & CAN_WRITE == 0 {}
write_volatile(DATA, c as u8);
}
} else if cfg!(feature = "m_mode") {
(super::BBL.mcall_console_putchar)(c);
} else {
sbi::console_putchar(c as usize);
}
#[cfg(not(feature = "no_bbl"))]
sbi::console_putchar(c as usize);
}
pub fn getchar() -> char {
#[cfg(feature = "no_bbl")]
let c = unsafe {
while read_volatile(STATUS) & CAN_READ == 0 {}
read_volatile(DATA)
let c = if cfg!(feature = "no_bbl") {
unsafe {
// while read_volatile(STATUS) & CAN_READ == 0 {}
read_volatile(DATA)
}
} else if cfg!(feature = "m_mode") {
(super::BBL.mcall_console_getchar)() as u8
} else {
sbi::console_getchar() as u8
};
#[cfg(not(feature = "no_bbl"))]
let c = sbi::console_getchar() as u8;
match c {
255 => '\0', // null

View File

@ -2,12 +2,24 @@ use core::{slice, mem};
use riscv::{addr::*, register::sstatus};
use ucore_memory::PAGE_SIZE;
use log::*;
use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet};
use crate::memory::{active_table, FRAME_ALLOCATOR, init_heap, MemoryArea, MemoryAttr, MemorySet, MEMORY_ALLOCATOR};
use crate::consts::{MEMORY_OFFSET, MEMORY_END};
#[cfg(feature = "no_mmu")]
pub fn init() {
init_heap();
let heap_bottom = end as usize;
let heap_size = MEMORY_END - heap_bottom;
unsafe { MEMORY_ALLOCATOR.lock().init(heap_bottom, heap_size); }
info!("available memory: [{:#x}, {:#x})", heap_bottom, MEMORY_END);
}
/*
* @brief:
* Init the mermory management module, allow memory access and set up page table and init heap and frame allocator
*/
#[cfg(not(feature = "no_mmu"))]
pub fn init() {
#[repr(align(4096))] // align the PageData struct to 4096 bytes
struct PageData([u8; PAGE_SIZE]);
@ -37,7 +49,6 @@ pub fn init_other() {
fn init_frame_allocator() {
use bit_allocator::BitAlloc;
use core::ops::Range;
use crate::consts::{MEMORY_OFFSET, MEMORY_END};
let mut ba = FRAME_ALLOCATOR.lock();
ba.insert(to_range(end as usize + PAGE_SIZE, MEMORY_END));
@ -63,6 +74,7 @@ fn init_frame_allocator() {
* @brief:
* remmap the kernel memory address with 4K page recorded in p1 page table
*/
#[cfg(not(feature = "no_mmu"))]
fn remap_the_kernel() {
let mut ms = MemorySet::new_bare();
#[cfg(feature = "no_bbl")]

View File

@ -8,9 +8,10 @@ pub mod consts;
pub mod cpu;
#[no_mangle]
pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize) -> ! {
pub extern fn rust_main(hartid: usize, dtb: usize, hart_mask: usize, functions: usize) -> ! {
unsafe { cpu::set_cpu_id(hartid); }
println!("Hello RISCV! in hart {}, {}, {}", hartid, dtb, hart_mask);
unsafe { BBL_FUNCTIONS_PTR = functions as *const _; }
println!("Hello RISCV! in hart {}, dtb @ {:#x}, functions @ {:#x}", hartid, dtb, functions);
if hartid != 0 {
while unsafe { !cpu::has_started(hartid) } { }
@ -35,7 +36,46 @@ fn others_main() -> ! {
crate::kmain();
}
/// Constant & Macro for `trap.asm`
#[cfg(feature = "m_mode")]
global_asm!("
.equ xstatus, 0x300
.equ xscratch, 0x340
.equ xepc, 0x341
.equ xcause, 0x342
.equ xtval, 0x343
.macro XRET\n mret\n .endm
");
#[cfg(not(feature = "m_mode"))]
global_asm!("
.equ xstatus, 0x100
.equ xscratch, 0x140
.equ xepc, 0x141
.equ xcause, 0x142
.equ xtval, 0x143
.macro XRET\n sret\n .endm
");
#[cfg(feature = "no_bbl")]
global_asm!(include_str!("boot/boot.asm"));
global_asm!(include_str!("boot/entry.asm"));
global_asm!(include_str!("boot/trap.asm"));
global_asm!(include_str!("boot/trap.asm"));
/// Some symbols passed from BBL.
/// Used in M-mode kernel.
#[repr(C)]
struct BBLFunctions {
mcall_trap: BBLTrapHandler,
illegal_insn_trap: BBLTrapHandler,
mcall_console_putchar: extern fn(u8),
mcall_console_getchar: extern fn() -> usize,
}
type BBLTrapHandler = extern fn(regs: *const usize, mcause: usize, mepc: usize);
static mut BBL_FUNCTIONS_PTR: *const BBLFunctions = ::core::ptr::null();
use lazy_static::lazy_static;
lazy_static! {
static ref BBL: BBLFunctions = unsafe { BBL_FUNCTIONS_PTR.read() };
}

View File

@ -161,10 +161,6 @@ impl ActivePageTable {
// Unmap the page
self.unmap(0xcafebabe);
}
pub fn token() -> usize {
satp::read().frame().number() | (1 << 31)
}
}
/// implementation for the Entry trait in /crate/memory/src/paging/mod.rs
impl Entry for PageEntry {
@ -200,6 +196,8 @@ impl Entry for PageEntry {
fn set_user(&mut self, value: bool) { self.as_flags().set(EF::USER, value); }
fn execute(&self) -> bool { self.0.flags().contains(EF::EXECUTABLE) }
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::EXECUTABLE, value); }
fn mmio(&self) -> bool { unimplemented!() }
fn set_mmio(&mut self, value: bool) { unimplemented!() }
}
impl PageEntry {

View File

@ -33,6 +33,9 @@ pub fn get_cycle() -> u64 {
*/
pub fn init() {
// Enable supervisor timer interrupt
#[cfg(feature = "m_mode")]
unsafe { mie::set_mtimer(); }
#[cfg(not(feature = "m_mode"))]
unsafe { sie::set_stimer(); }
set_next();

View File

@ -1,15 +1,10 @@
use core::ptr::Unique;
use core::fmt;
use spin::Mutex;
use volatile::Volatile;
use lazy_static::lazy_static;
use x86_64::instructions::port::Port;
use crate::logging::Color;
use crate::consts::KERNEL_OFFSET;
use lazy_static::lazy_static;
pub const VGA_BUFFER: Unique<VgaBuffer> = unsafe {
Unique::new_unchecked((KERNEL_OFFSET + 0xb8000) as *mut _)
};
#[derive(Debug, Clone, Copy)]
struct ColorCode(u8);
@ -73,8 +68,7 @@ impl VgaBuffer {
lazy_static! {
pub static ref VGA_WRITER: Mutex<VgaWriter> = Mutex::new(
// It is the only user of VGA_BUFFER. So it's safe.
VgaWriter::new(unsafe{ &mut *VGA_BUFFER.as_ptr() })
VgaWriter::new(unsafe{ &mut *((KERNEL_OFFSET + 0xb8000) as *mut VgaBuffer) })
);
}

View File

@ -96,9 +96,6 @@ impl ActivePageTable {
// Unmap the page
self.unmap(0xcafebabe);
}
pub fn token() -> usize {
Cr3::read().0.start_address().as_u64() as usize
}
}
impl Entry for PageEntry {
@ -145,6 +142,8 @@ impl Entry for PageEntry {
}
fn execute(&self) -> bool { !self.0.flags().contains(EF::NO_EXECUTE) }
fn set_execute(&mut self, value: bool) { self.as_flags().set(EF::NO_EXECUTE, !value); }
fn mmio(&self) -> bool { unimplemented!() }
fn set_mmio(&mut self, value: bool) { unimplemented!() }
}
fn get_entry_ptr(addr: usize, level: u8) -> *mut PageEntry {
@ -271,4 +270,4 @@ impl FrameDeallocator<Size4KiB> for FrameAllocatorForX86 {
fn dealloc(&mut self, frame: Frame) {
dealloc_frame(frame.start_address().as_u64() as usize);
}
}
}

View File

@ -3,8 +3,6 @@ use alloc::{boxed::Box, sync::Arc, string::String, collections::VecDeque, vec::V
use core::any::Any;
use core::slice;
use lazy_static::lazy_static;
use crate::memory::{MemorySet, InactivePageTable0, memory_set_record};
use crate::process::context::memory_set_map_swappable;
#[cfg(target_arch = "x86_64")]
use crate::arch::driver::ide;
use crate::sync::Condvar;
@ -77,6 +75,15 @@ impl Stdin {
self.pushed.notify_one();
}
pub fn pop(&self) -> char {
// QEMU v3.0 don't support M-mode external interrupt (bug?)
// So we have to use polling.
// TODO: serial interrupt on aarch64
#[cfg(any(feature = "m_mode", target_arch = "aarch64"))]
loop {
let c = crate::arch::io::getchar();
if c != '\0' { return c; }
}
#[cfg(not(any(feature = "m_mode", target_arch = "aarch64")))]
loop {
let ret = self.buf.lock().pop_front();
match ret {

View File

@ -1,16 +1,10 @@
#![feature(ptr_internals)]
#![feature(lang_items)]
#![feature(const_fn)]
#![feature(alloc)]
#![feature(naked_functions)]
#![feature(asm)]
#![feature(optin_builtin_traits)]
#![feature(panic_info_message)]
#![feature(global_asm)]
#![feature(compiler_builtins_lib)]
#![feature(raw)]
#![feature(vec_resize_default)]
#![feature(extern_crate_item_prelude)]
#![no_std]
// just keep it ...
@ -48,12 +42,6 @@ pub mod arch;
pub fn kmain() -> ! {
processor().run();
// thread::test::local_key();
// thread::test::unpack();
// sync::test::philosopher_using_mutex();
// sync::test::philosopher_using_monitor();
// sync::mpsc::test::test_all();
}
/// Global heap allocator

View File

@ -1,6 +1,6 @@
use core::fmt;
use log::{self, Level, LevelFilter, Log, Metadata, Record};
use spin::Mutex;
use crate::sync::SpinNoIrqLock as Mutex;
use lazy_static::lazy_static;
lazy_static! {

View File

@ -1,19 +1,23 @@
pub use crate::arch::paging::*;
use bit_allocator::{BitAlloc, BitAlloc4K, BitAlloc64K};
use bit_allocator::{BitAlloc, BitAlloc4K, BitAlloc64K, BitAlloc1M};
use crate::consts::MEMORY_OFFSET;
use super::HEAP_ALLOCATOR;
use ucore_memory::{*, paging::PageTable};
use ucore_memory::cow::CowExt;
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, MemorySet as MemorySet_, InactivePageTable};
pub use ucore_memory::memory_set::{MemoryArea, MemoryAttr, InactivePageTable};
use ucore_memory::swap::*;
use crate::process::{process};
use crate::sync::{SpinNoIrqLock, SpinNoIrq, MutexGuard};
use alloc::collections::VecDeque;
use lazy_static::*;
use log::*;
use linked_list_allocator::LockedHeap;
#[cfg(not(feature = "no_mmu"))]
pub type MemorySet = ucore_memory::memory_set::MemorySet<InactivePageTable0>;
pub type MemorySet = MemorySet_<InactivePageTable0>;
#[cfg(feature = "no_mmu")]
pub type MemorySet = ucore_memory::no_mmu::MemorySet<NoMMUSupportImpl>;
// x86_64 support up to 256M memory
#[cfg(target_arch = "x86_64")]
@ -25,20 +29,11 @@ pub type FrameAlloc = BitAlloc4K;
// Raspberry Pi 3 has 1G memory
#[cfg(target_arch = "aarch64")]
pub type FrameAlloc = BitAlloc64K;
pub type FrameAlloc = BitAlloc1M;
lazy_static! {
pub static ref FRAME_ALLOCATOR: SpinNoIrqLock<FrameAlloc> = SpinNoIrqLock::new(FrameAlloc::default());
}
// record the user memory set for pagefault function (swap in/out and frame delayed allocate) temporarily when page fault in new_user() or fork() function
// after the process is set we can use use crate::processor() to get the inactive page table
lazy_static! {
pub static ref MEMORY_SET_RECORD: SpinNoIrqLock<VecDeque<usize>> = SpinNoIrqLock::new(VecDeque::default());
}
pub fn memory_set_record() -> MutexGuard<'static, VecDeque<usize>, SpinNoIrq> {
MEMORY_SET_RECORD.lock()
}
lazy_static! {
static ref ACTIVE_TABLE: SpinNoIrqLock<CowExt<ActivePageTable>> = SpinNoIrqLock::new(unsafe {
@ -110,48 +105,25 @@ impl Drop for KernelStack {
* @retval:
* Return true to continue, false to halt
*/
#[cfg(not(feature = "no_mmu"))]
pub fn page_fault_handler(addr: usize) -> bool {
info!("start handling swap in/out page fault");
//unsafe { ACTIVE_TABLE_SWAP.force_unlock(); }
info!("active page table token in pg fault is {:x?}", ActivePageTable::token());
let mmset_record = memory_set_record();
let id = mmset_record.iter()
.position(|x| unsafe{(*(x.clone() as *mut MemorySet)).get_page_table_mut().token() == ActivePageTable::token()});
/*LAB3 EXERCISE 1: YOUR STUDENT NUMBER
* handle the frame deallocated
*/
match id {
Some(targetid) => {
info!("get id from memroy set recorder.");
let mmset_ptr = mmset_record.get(targetid).expect("fail to get mmset_ptr").clone();
// get current mmset
let current_mmset = unsafe{&mut *(mmset_ptr as *mut MemorySet)};
//check whether the vma is legal
if current_mmset.find_area(addr).is_none(){
return false;
}
info!("get pt from processor()");
if process().memory_set.find_area(addr).is_none(){
return false;
}
let pt = current_mmset.get_page_table_mut();
info!("pt got!");
if active_table_swap().page_fault_handler(pt as *mut InactivePageTable0, addr, false, || alloc_frame().expect("fail to alloc frame")){
return true;
}
},
None => {
info!("get pt from processor()");
if process().get_memory_set_mut().find_area(addr).is_none(){
return false;
}
let pt = process().get_memory_set_mut().get_page_table_mut();
info!("pt got");
if active_table_swap().page_fault_handler(pt as *mut InactivePageTable0, addr, true, || alloc_frame().expect("fail to alloc frame")){
return true;
}
},
};
let pt = process().memory_set.get_page_table_mut();
info!("pt got");
if active_table_swap().page_fault_handler(pt as *mut InactivePageTable0, addr, true, || alloc_frame().expect("fail to alloc frame")){
return true;
}
//////////////////////////////////////////////////////////////////////////////
@ -172,10 +144,29 @@ pub fn init_heap() {
info!("heap init end");
}
/// Allocator for the rest memory space on NO-MMU case.
pub static MEMORY_ALLOCATOR: LockedHeap = LockedHeap::empty();
#[derive(Debug, Clone, Copy)]
pub struct NoMMUSupportImpl;
impl ucore_memory::no_mmu::NoMMUSupport for NoMMUSupportImpl {
type Alloc = LockedHeap;
fn allocator() -> &'static Self::Alloc {
&MEMORY_ALLOCATOR
}
}
#[cfg(feature = "no_mmu")]
pub fn page_fault_handler(_addr: usize) -> bool {
unreachable!()
}
//pub mod test {
// pub fn cow() {
// use super::*;
// use ucore_memory::cow::test::test_with;
// test_with(&mut active_table());
// }
//}
//}

View File

@ -1,6 +1,6 @@
use crate::arch::interrupt::{TrapFrame, Context as ArchContext};
use crate::memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap, alloc_frame, InactivePageTable0, memory_set_record};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type}};
use crate::memory::{MemoryArea, MemoryAttr, MemorySet, KernelStack, active_table_swap, alloc_frame, InactivePageTable0};
use xmas_elf::{ElfFile, header, program::{Flags, ProgramHeader, Type, SegmentData}};
use core::fmt::{Debug, Error, Formatter};
use alloc::{boxed::Box, collections::BTreeMap, vec::Vec, sync::Arc, string::String};
use ucore_memory::{Page};
@ -51,29 +51,7 @@ impl ContextImpl {
})
}
/// Temp for aarch64
pub fn new_user_test(entry: extern fn(usize) -> !) -> Box<Context> {
let memory_set = MemorySet::new();
let kstack = KernelStack::new();
let ustack = KernelStack::new();
Box::new(ContextImpl {
arch: unsafe { ArchContext::new_user_thread(entry as usize, ustack.top(), kstack.top(), false, memory_set.token()) },
memory_set,
kstack,
files: BTreeMap::default(),
cwd: String::new(),
})
}
/// Make a new user thread from ELF data
/*
* @param:
* data: the ELF data stream
* @brief:
* make a new thread from ELF data
* @retval:
* the new user thread Context
*/
pub fn new_user<'a, Iter>(data: &[u8], args: Iter) -> Box<ContextImpl>
where Iter: Iterator<Item=&'a str>
{
@ -83,61 +61,45 @@ impl ContextImpl {
header::HeaderPt2::Header32(_) => true,
header::HeaderPt2::Header64(_) => false,
};
assert_eq!(elf.header.pt2.type_().as_type(), header::Type::Executable, "ELF is not executable");
match elf.header.pt2.type_().as_type() {
header::Type::Executable => {
// #[cfg(feature = "no_mmu")]
// panic!("ELF is not shared object");
},
header::Type::SharedObject => {},
_ => panic!("ELF is not executable or shared object"),
}
// Make page table
let (mut memory_set, entry_addr) = memory_set_from(&elf);
// User stack
use crate::consts::{USER_STACK_OFFSET, USER_STACK_SIZE, USER32_STACK_OFFSET};
let (ustack_buttom, mut ustack_top) = match is32 {
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
#[cfg(not(feature = "no_mmu"))]
let mut ustack_top = {
let (ustack_buttom, ustack_top) = match is32 {
true => (USER32_STACK_OFFSET, USER32_STACK_OFFSET + USER_STACK_SIZE),
false => (USER_STACK_OFFSET, USER_STACK_OFFSET + USER_STACK_SIZE),
};
memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack"));
ustack_top
};
#[cfg(feature = "no_mmu")]
let mut ustack_top = memory_set.push(USER_STACK_SIZE).as_ptr() as usize + USER_STACK_SIZE;
// Make page table
let mut memory_set = memory_set_from(&elf);
unsafe {
memory_set.with(|| { ustack_top = push_args_at_stack(args, ustack_top) });
}
// add the new memory set to the recorder
let mmset_ptr = ((&mut memory_set) as * mut MemorySet) as usize;
memory_set_record().push_back(mmset_ptr);
//let id = memory_set_record().iter()
// .position(|x| unsafe { info!("current memory set record include {:x?}, {:x?}", x, (*(x.clone() as *mut MemorySet)).get_page_table_mut().token()); false });
memory_set.push(MemoryArea::new(ustack_buttom, ustack_top, MemoryAttr::default().user(), "user_stack"));
trace!("{:#x?}", memory_set);
let entry_addr = elf.header.pt2.entry_point() as usize;
// Temporary switch to it, in order to copy data
unsafe {
memory_set.with(|| {
for ph in elf.program_iter() {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let virt_addr = ph.virtual_addr() as usize;
let offset = ph.offset() as usize;
let file_size = ph.file_size() as usize;
let mem_size = ph.mem_size() as usize;
let target = unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) };
if file_size != 0 {
target[..file_size].copy_from_slice(&data[offset..offset + file_size]);
}
target[file_size..].iter_mut().for_each(|x| *x = 0);
}
ustack_top = push_args_at_stack(args, ustack_top);
});
}
let kstack = KernelStack::new();
{
let mut mmset_record = memory_set_record();
let id = mmset_record.iter()
.position(|x| x.clone() == mmset_ptr).expect("id not exist");
mmset_record.remove(id);
}
let mut ret = Box::new(ContextImpl {
//set the user Memory pages in the memory set swappable
memory_set_map_swappable(&mut memory_set);
Box::new(ContextImpl {
arch: unsafe {
ArchContext::new_user_thread(
entry_addr, ustack_top, kstack.top(), is32, memory_set.token())
@ -146,10 +108,7 @@ impl ContextImpl {
kstack,
files: BTreeMap::default(),
cwd: String::new(),
});
//set the user Memory pages in the memory set swappable
memory_set_map_swappable(ret.get_memory_set_mut());
ret
})
}
/// Fork
@ -158,61 +117,36 @@ impl ContextImpl {
// Clone memory set, make a new page table
let mut memory_set = self.memory_set.clone();
info!("finish mmset clone in fork!");
// add the new memory set to the recorder
info!("fork! new page table token: {:x?}", memory_set.token());
let mmset_ptr = ((&mut memory_set) as * mut MemorySet) as usize;
memory_set_record().push_back(mmset_ptr);
info!("before copy data to temp space");
// Copy data to temp space
use alloc::vec::Vec;
let datas: Vec<Vec<u8>> = memory_set.iter().map(|area| {
Vec::from(unsafe { area.as_slice() })
}).collect();
info!("Finish copy data to temp space.");
// Temporarily switch to it, in order to copy data
unsafe {
memory_set.with(|| {
for (area, data) in memory_set.iter().zip(datas.iter()) {
area.as_slice_mut().copy_from_slice(data.as_slice())
}
});
// MMU: copy data to the new space
// NoMMU: coping data has been done in `memory_set.clone()`
#[cfg(not(feature = "no_mmu"))]
for area in memory_set.iter() {
let data = Vec::<u8>::from(unsafe { area.as_slice() });
unsafe { memory_set.with(|| {
area.as_slice_mut().copy_from_slice(data.as_slice())
}) }
}
info!("temporary copy data!");
let kstack = KernelStack::new();
// remove the raw pointer for the memory set in memory_set_record
{
let mut mmset_record = memory_set_record();
let id = mmset_record.iter()
.position(|x| x.clone() == mmset_ptr).expect("id not exist");
mmset_record.remove(id);
}
memory_set_map_swappable(&mut memory_set);
info!("FORK() finsihed!");
let mut ret = Box::new(ContextImpl {
Box::new(ContextImpl {
arch: unsafe { ArchContext::new_fork(tf, kstack.top(), memory_set.token()) },
memory_set,
kstack,
files: BTreeMap::default(),
cwd: String::new(),
});
memory_set_map_swappable(ret.get_memory_set_mut());
info!("FORK() finsihed!");
ret
})
}
pub fn get_memory_set_mut(&mut self) -> &mut MemorySet {
&mut self.memory_set
}
}
impl Drop for ContextImpl{
#[cfg(not(feature = "no_mmu"))]
#[cfg(not(target_arch = "aarch64"))]
impl Drop for ContextImpl {
fn drop(&mut self){
info!("come in to drop for ContextImpl");
//set the user Memory pages in the memory set unswappable
@ -265,29 +199,48 @@ unsafe fn push_args_at_stack<'a, Iter>(args: Iter, stack_top: usize) -> usize
}
/*
* @param:
* elf: the source ELF file
* @brief:
* generate a memory set according to the elf file
* @retval:
* the new memory set
*/
fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> MemorySet {
/// Generate a MemorySet according to the ELF file.
/// Also return the real entry point address.
fn memory_set_from<'a>(elf: &'a ElfFile<'a>) -> (MemorySet, usize) {
debug!("come in to memory_set_from");
let mut set = MemorySet::new();
let mut ms = MemorySet::new();
let mut entry = None;
for ph in elf.program_iter() {
if ph.get_type() != Ok(Type::Load) {
continue;
}
let (virt_addr, mem_size, flags) = match ph {
ProgramHeader::Ph32(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
ProgramHeader::Ph64(ph) => (ph.virtual_addr as usize, ph.mem_size as usize, ph.flags),
};
set.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(flags), ""));
let virt_addr = ph.virtual_addr() as usize;
let offset = ph.offset() as usize;
let file_size = ph.file_size() as usize;
let mem_size = ph.mem_size() as usize;
#[cfg(target_arch = "aarch64")]
assert_eq!((virt_addr >> 48), 0xffff, "Segment Fault");
// Get target slice
#[cfg(feature = "no_mmu")]
let target = ms.push(mem_size);
#[cfg(not(feature = "no_mmu"))]
let target = {
ms.push(MemoryArea::new(virt_addr, virt_addr + mem_size, memory_attr_from(ph.flags()), ""));
unsafe { ::core::slice::from_raw_parts_mut(virt_addr as *mut u8, mem_size) }
};
// Copy data
unsafe {
ms.with(|| {
if file_size != 0 {
target[..file_size].copy_from_slice(&elf.input[offset..offset + file_size]);
}
target[file_size..].iter_mut().for_each(|x| *x = 0);
});
}
// Find real entry point
if ph.flags().is_execute() {
let origin_entry = elf.header.pt2.entry_point() as usize;
entry = Some(origin_entry - virt_addr + target.as_ptr() as usize);
}
}
set
(ms, entry.unwrap())
}
fn memory_attr_from(elf_flags: Flags) -> MemoryAttr {
@ -303,7 +256,8 @@ fn memory_attr_from(elf_flags: Flags) -> MemoryAttr {
* @brief:
* map the memory area in the memory_set swappalbe, specially for the user process
*/
pub fn memory_set_map_swappable(memory_set: &mut MemorySet){
#[cfg(not(any(feature = "no_mmu", target_arch = "aarch64")))]
pub fn memory_set_map_swappable(memory_set: &mut MemorySet) {
info!("COME INTO memory set map swappable!");
let pt = unsafe {
memory_set.get_page_table_mut() as *mut InactivePageTable0
@ -317,3 +271,8 @@ pub fn memory_set_map_swappable(memory_set: &mut MemorySet){
info!("Finishing setting pages swappable");
}
#[cfg(any(feature = "no_mmu", target_arch = "aarch64"))]
pub fn memory_set_map_swappable(memory_set: &mut MemorySet) {
// FIXME: Page Fault on aarch64
// NOTE: This function may disappear after refactor memory crate
}

View File

@ -27,7 +27,6 @@ pub fn init() {
for i in 0..4 {
manager.add(ContextImpl::new_kernel(idle, i), 0);
}
#[cfg(not(target_arch = "aarch64"))]
crate::shell::run_user_shell();
info!("process init end");

1
riscv-pk Submodule

@ -0,0 +1 @@
Subproject commit 71b2addd7ada2f07ca8e6f02787d706afa4fbe66

11
riscv-pk/.gitignore vendored
View File

@ -1,11 +0,0 @@
#=========================================================================
# Git Ignore Files
#=========================================================================
# We explicitly ignore a default build directory and the autoconf
# generated autom4te.cache directory. This makes it easy to do a clean
# build under the source directory and still have it appear clean to git.
build/
autom4te.cache/
*.swp
*~

View File

@ -1,24 +0,0 @@
Copyright (c) 2013, The Regents of the University of California (Regents).
All Rights Reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright
notice, this list of conditions and the following disclaimer in the
documentation and/or other materials provided with the distribution.
3. Neither the name of the Regents nor the
names of its contributors may be used to endorse or promote products
derived from this software without specific prior written permission.
IN NO EVENT SHALL REGENTS BE LIABLE TO ANY PARTY FOR DIRECT, INDIRECT,
SPECIAL, INCIDENTAL, OR CONSEQUENTIAL DAMAGES, INCLUDING LOST PROFITS, ARISING
OUT OF THE USE OF THIS SOFTWARE AND ITS DOCUMENTATION, EVEN IF REGENTS HAS
BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
REGENTS SPECIFICALLY DISCLAIMS ANY WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE. THE SOFTWARE AND ACCOMPANYING DOCUMENTATION, IF ANY, PROVIDED
HEREUNDER IS PROVIDED "AS IS". REGENTS HAS NO OBLIGATION TO PROVIDE
MAINTENANCE, SUPPORT, UPDATES, ENHANCEMENTS, OR MODIFICATIONS.

View File

@ -1,455 +0,0 @@
#=========================================================================
# Toplevel Makefile for the Modular C++ Build System
#=========================================================================
# Please read the documenation in 'mcppbs-doc.txt' for more details on
# how the Modular C++ Build System works. For most projects, a developer
# will not need to make any changes to this makefile. The key targets
# are as follows:
#
# - default : build all libraries and programs
# - check : build and run all unit tests
# - install : install headers, project library, and some programs
# - clean : remove all generated content (except autoconf files)
# - dist : make a source tarball
# - distcheck : make a source tarball, untar it, check it, clean it
# - distclean : remove everything
#
#-------------------------------------------------------------------------
# Basic setup
#-------------------------------------------------------------------------
# Remove all default implicit rules since they can cause subtle bugs
# and they just make things run slower
.SUFFIXES:
% : %,v
% : RCS/%,v
% : RCS/%
% : s.%
% : SCCS/s.%
# Default is to build the prereqs of the all target (defined at bottom)
default : all
.PHONY : default
project_name := @PACKAGE_TARNAME@
src_dir := @srcdir@
scripts_dir := $(src_dir)/scripts
# If the version information is not in the configure script, then we
# assume that we are in a working directory. We use the vcs-version.sh
# script in the scripts directory to generate an appropriate version
# string. Currently the way things are setup we have to run this script
# everytime we run make so the script needs to be as fast as possible.
ifeq (@PACKAGE_VERSION@,?)
project_ver:=$(shell $(scripts_dir)/vcs-version.sh $(src_dir))
else
project_ver:=@PACKAGE_VERSION@
endif
# Installation directories
prefix := @prefix@
enable_stow := @enable_stow@
ifeq ($(enable_stow),yes)
stow_pkg_dir := $(prefix)/pkgs
INSTALLDIR ?= $(DESTDIR)/$(stow_pkg_dir)/$(project_name)-$(project_ver)
else
INSTALLDIR ?= $(DESTDIR)/$(prefix)/@install_subdir@
endif
install_hdrs_dir := $(INSTALLDIR)/include/$(project_name)
install_libs_dir := $(INSTALLDIR)/lib/$(project_name)
install_exes_dir := $(INSTALLDIR)/bin
#-------------------------------------------------------------------------
# List of subprojects
#-------------------------------------------------------------------------
sprojs := @subprojects@
sprojs_enabled := @subprojects_enabled@
sprojs_include := -I. $(addprefix -I$(src_dir)/, $(sprojs_enabled))
VPATH := $(addprefix $(src_dir)/, $(sprojs_enabled))
#-------------------------------------------------------------------------
# Programs and flags
#-------------------------------------------------------------------------
# C++ compiler
# - CPPFLAGS : flags for the preprocessor (eg. -I,-D)
# - CXXFLAGS : flags for C++ compiler (eg. -Wall,-g,-O3)
CC := @CC@
READELF := @READELF@
OBJCOPY := @OBJCOPY@
CFLAGS := @CFLAGS@ $(CFLAGS) -DBBL_PAYLOAD=\"bbl_payload\" -DBBL_LOGO_FILE=\"bbl_logo_file\"
BBL_PAYLOAD := @BBL_PAYLOAD@
COMPILE := $(CC) -MMD -MP $(CFLAGS) \
$(sprojs_include)
# Linker
# - LDFLAGS : Flags for the linker (eg. -L)
# - LIBS : Library flags (eg. -l)
LD := $(CC)
LDFLAGS := @LDFLAGS@ -nostartfiles -nostdlib -static $(LDFLAGS)
LIBS := @LIBS@
LINK := $(LD) $(LDFLAGS)
# Library creation
AR := @AR@
RANLIB := @RANLIB@
# Host simulator
RUN := @RUN@
RUNFLAGS := @RUNFLAGS@
# Installation
MKINSTALLDIRS := $(scripts_dir)/mk-install-dirs.sh
INSTALL := @INSTALL@
INSTALL_HDR := $(INSTALL) -m 444
INSTALL_LIB := $(INSTALL) -m 644
INSTALL_EXE := $(INSTALL) -m 555
STOW := @stow@
#-------------------------------------------------------------------------
# Include subproject makefile fragments
#-------------------------------------------------------------------------
sprojs_mk = $(addsuffix .mk, $(sprojs_enabled))
-include $(sprojs_mk)
dist_junk += $(sprojs_mk)
#-------------------------------------------------------------------------
# Reverse list helper function
#-------------------------------------------------------------------------
# This function is used by the subproject template to reverse the list
# of dependencies. It uses recursion to perform the reversal.
#
# Arguments:
# $(1) : space separated input list
# retval : input list in reverse order
#
reverse_list = $(call reverse_list_h,$(1),)
define reverse_list_h
$(if $(strip $(1)), \
$(call reverse_list_h, \
$(wordlist 2,$(words $(1)),$(1)), \
$(firstword $(1)) $(2)), \
$(2))
endef
#-------------------------------------------------------------------------
# Template for per subproject rules
#-------------------------------------------------------------------------
# The template is instantiated for each of the subprojects. It relies on
# subprojects defining a certain set of make variables which are all
# prefixed with the subproject name. Since subproject names can have
# dashes in them (and the make variables are assumed to only use
# underscores) the template takes two arguments - one with the regular
# subproject name and one with dashes replaced with underscores.
#
# Arguments:
# $(1) : real subproject name (ie with dashes)
# $(2) : normalized subproject name (ie dashes replaced with underscores)
#
define subproject_template
# In some (rare) cases, a subproject might not have any actual object
# files. It might only include header files or program sources. To keep
# things consistent we still want a library for this subproject, so in
# this spectial case we create a dummy source file and thus the build
# system will create a library for this subproject with just the
# corresponding dummy object file.
ifeq ($$(strip $$($(2)_c_srcs)),)
$(2)_c_srcs += _$(1).c
$(2)_junk += _$(1).c
endif
_$(1).c :
echo "int _$(2)( int arg ) { return arg; }" > $$@
# Build the object files for this subproject
$(2)_c_objs := $$(patsubst %.c, %.o, $$($(2)_c_srcs))
$(2)_asm_objs := $$(patsubst %.S, %.o, $$($(2)_asm_srcs))
$(2)_c_deps := $$(patsubst %.o, %.d, $$($(2)_c_objs))
$$($(2)_c_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_asm_objs) : %.o : %.S
$(COMPILE) -c $$<
$(2)_junk += $$($(2)_c_objs) $$($(2)_c_deps) $$($(2)_asm_objs)
# Build a library for this subproject
lib$(1).a : $$($(2)_c_objs) $$($(2)_asm_objs)
$(AR) rcv $$@ $$^
$(RANLIB) $$@
$(2)_junk += lib$(1).a
# Reverse the dependency list so that a given subproject only depends on
# subprojects listed to its right. This is the correct order for linking
# the list of subproject libraries.
$(2)_reverse_deps := $$(call reverse_list,$$($(2)_subproject_deps))
# Build unit tests
$(2)_test_objs := $$(patsubst %.c, %.o, $$($(2)_test_srcs))
$(2)_test_deps := $$(patsubst %.o, %.d, $$($(2)_test_objs))
$(2)_test_exes := $$(patsubst %.t.c, %-utst, $$($(2)_test_srcs))
$(2)_test_outs := $$(patsubst %, %.out, $$($(2)_test_exes))
$(2)_test_libs := $(1) $$($(2)_reverse_deps) utst
$(2)_test_libnames := $$(patsubst %, lib%.a, $$($(2)_test_libs))
$(2)_test_libarg := -L. $$(patsubst %, -l%, $$($(2)_test_libs))
$$($(2)_test_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_test_exes) : %-utst : %.t.o $$($(2)_test_libnames)
$(LINK) -o $$@ $$< $$($(2)_test_libarg) $(LIBS)
$(2)_c_deps += $$($(2)_test_deps)
$(2)_junk += \
$$($(2)_test_objs) $$($(2)_test_deps) \
$$($(2)_test_exes) *.junk-dat
# Run unit tests
$$($(2)_test_outs) : %.out : %
$(RUN) $(RUNFLAGS) ./$$< default | tee $$@
$(2)_junk += $$($(2)_test_outs)
# Build programs
$(2)_prog_objs := $$(patsubst %.c, %.o, $$($(2)_prog_srcs))
$(2)_prog_deps := $$(patsubst %.o, %.d, $$($(2)_prog_objs))
$(2)_prog_exes := $$(patsubst %.c, %, $$($(2)_prog_srcs))
$(2)_prog_libs := $(1) $$($(2)_reverse_deps)
$(2)_prog_libnames := $$(patsubst %, lib%.a, $$($(2)_prog_libs))
$(2)_prog_libarg := -L. $$(patsubst %, -l%, $$($(2)_prog_libs))
$$($(2)_prog_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_prog_exes) : % : %.o $$($(2)_prog_libnames)
$(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS)
$(2)_c_deps += $$($(2)_prog_deps)
$(2)_junk += $$($(2)_prog_objs) $$($(2)_prog_deps) $$($(2)_prog_exes)
# Build programs which will be installed
$(2)_install_prog_objs := $$(patsubst %.c, %.o, $$($(2)_install_prog_srcs))
$(2)_install_prog_deps := $$(patsubst %.o, %.d, $$($(2)_install_prog_objs))
$(2)_install_prog_exes := $$(patsubst %.c, %, $$($(2)_install_prog_srcs))
$$($(2)_install_prog_objs) : %.o : %.c
$(COMPILE) -c $$<
$$($(2)_install_prog_exes) : % : %.o $$($(2)_prog_libnames)
$(LINK) -o $$@ $$< $$($(2)_prog_libarg) $(LIBS) -T $(src_dir)/$(2)/$(2).lds
$(2)_c_deps += $$($(2)_install_prog_deps)
$(2)_junk += \
$$($(2)_install_prog_objs) $$($(2)_install_prog_deps) \
$$($(2)_install_prog_exes)
# Subproject specific targets
all-$(1) : lib$(1).a $$($(2)_install_prog_exes)
check-$(1) : $$($(2)_test_outs)
echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $$^; echo
clean-$(1) :
rm -rf $$($(2)_junk)
.PHONY : all-$(1) check-$(1) clean-$(1)
# Update running variables
libs += lib$(1).a
objs += $$($(2)_c_objs)
srcs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_c_srcs))
hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs))
junk += $$($(2)_junk)
deps += $$($(2)_c_deps)
test_outs += $$($(2)_test_outs)
install_hdrs += $$(addprefix $(src_dir)/$(1)/, $$($(2)_hdrs))
install_libs += lib$(1).a
install_exes += $$($(2)_install_prog_exes)
endef
# Iterate over the subprojects and call the template for each one
$(foreach sproj,$(sprojs_enabled), \
$(eval $(call subproject_template,$(sproj),$(subst -,_,$(sproj)))))
#-------------------------------------------------------------------------
# Autodependency files
#-------------------------------------------------------------------------
-include $(deps)
deps : $(deps)
.PHONY : deps
#-------------------------------------------------------------------------
# Check
#-------------------------------------------------------------------------
check : $(test_outs)
echo; grep -h -e'Unit Tests' -e'FAILED' -e'Segementation' $^; echo
.PHONY : check
#-------------------------------------------------------------------------
# Installation
#-------------------------------------------------------------------------
install-hdrs : $(install_hdrs)
$(MKINSTALLDIRS) $(install_hdrs_dir)
for file in $(install_hdrs); \
do \
$(INSTALL_HDR) $$file $(install_hdrs_dir); \
done
install-libs : $(install_libs)
$(MKINSTALLDIRS) $(install_libs_dir)
for file in $(install_libs); \
do \
$(INSTALL_LIB) $$file $(install_libs_dir); \
done
install-exes : $(install_exes)
$(MKINSTALLDIRS) $(install_exes_dir)
for file in $(install_exes); \
do \
$(INSTALL_EXE) $$file $(install_exes_dir); \
done
install : install-hdrs install-libs install-exes
ifeq ($(enable_stow),yes)
$(MKINSTALLDIRS) $(stow_pkg_dir)
cd $(stow_pkg_dir) && \
$(STOW) --delete $(project_name)-* && \
$(STOW) $(project_name)-$(project_ver)
endif
.PHONY : install install-hdrs install-libs install-exes
#-------------------------------------------------------------------------
# Regenerate configure information
#-------------------------------------------------------------------------
config.status : $(src_dir)/configure
./config.status --recheck
sprojs_mk_in = \
$(join $(addprefix $(src_dir)/, $(sprojs_enabled)), \
$(patsubst %, /%.mk.in, $(sprojs_enabled)))
Makefile : $(src_dir)/Makefile.in $(sprojs_mk_in) config.status
./config.status
dist_junk += config.status config.h Makefile config.log
#-------------------------------------------------------------------------
# Distribution
#-------------------------------------------------------------------------
# The distribution tarball is named project-ver.tar.gz and it includes
# both enabled and disabled subprojects.
dist_files = \
$(sprojs) \
README \
style-guide.txt \
mcppbs-uguide.txt \
scripts \
configure.ac \
aclocal.m4 \
configure \
config.h.in \
Makefile.in \
dist_dir := $(project_name)-$(project_ver)
dist_tgz := $(project_name)-$(project_ver).tar.gz
# Notice that when we make the distribution we rewrite the configure.ac
# script with the current version and we rerun autoconf in the new
# source directory so that the distribution will have the proper version
# information. We also rewrite the "Version : " line in the README.
dist :
rm -rf $(dist_dir)
mkdir $(dist_dir)
tar -C $(src_dir) -cf - $(dist_files) | tar -C $(dist_dir) -xpf -
sed -i.bak 's/^\(# Version :\).*/\1 $(project_ver)/' $(dist_dir)/README
sed -i.bak 's/\( proj_version,\).*/\1 [$(project_ver)])/' $(dist_dir)/configure.ac
cd $(dist_dir) && \
autoconf && autoheader && \
rm -rf autom4te.cache configure.ac.bak README.bak
tar -czvf $(dist_tgz) $(dist_dir)
rm -rf $(dist_dir)
# You can use the distcheck target to try untarring the distribution and
# then running configure, make, make check, and make distclean. A
# "directory is not empty" error means distclean is not removing
# everything.
distcheck : dist
rm -rf $(dist_dir)
tar -xzvf $(dist_tgz)
mkdir -p $(dist_dir)/build
cd $(dist_dir)/build; ../configure; make; make check; make distclean
rm -rf $(dist_dir)
junk += $(project_name)-*.tar.gz
.PHONY : dist distcheck
#-------------------------------------------------------------------------
# Default
#-------------------------------------------------------------------------
all : $(install_hdrs) $(install_libs) $(install_exes)
.PHONY : all
#-------------------------------------------------------------------------
# Makefile debugging
#-------------------------------------------------------------------------
# This handy rule will display the contents of any make variable by
# using the target debug-<varname>. So for example, make debug-junk will
# display the contents of the junk variable.
debug-% :
@echo $* = $($*)
#-------------------------------------------------------------------------
# Clean up junk
#-------------------------------------------------------------------------
clean :
rm -rf *~ \#* $(junk)
distclean :
rm -rf *~ \#* $(junk) $(dist_junk)
.PHONY : clean distclean

View File

@ -1,40 +0,0 @@
RISC-V Proxy Kernel and Boot Loader
=====================================
About
---------
The RISC-V Proxy Kernel, `pk`, is a lightweight application execution
environment that can host statically-linked RISC-V ELF binaries. It is
designed to support tethered RISC-V implementations with limited I/O
capability and and thus handles I/O-related system calls by proxying them to
a host computer.
This package also contains the Berkeley Boot Loader, `bbl`, which is a
supervisor execution environment for tethered RISC-V systems. It is
designed to host the RISC-V Linux port.
Build Steps
---------------
We assume that the RISCV environment variable is set to the RISC-V tools
install path, and that the riscv-gnu-toolchain package is installed.
Please note that building the binaries directly inside the source
directory is not supported; you need to use a separate build directory.
$ mkdir build
$ cd build
$ ../configure --prefix=$RISCV --host=riscv64-unknown-elf
$ make
$ make install
Alternatively, the GNU/Linux toolchain may be used to build this package,
by setting `--host=riscv64-unknown-linux-gnu`.
By default, 64-bit (RV64) versions of `pk` and `bbl` are built. To
built 32-bit (RV32) versions, supply a `--enable-32bit` flag to the
configure command.
The `install` step installs 64-bit build products into
`$RISCV/riscv64-unknown-elf`, and 32-bit versions into
`$RISCV/riscv32-unknown-elf`.

333
riscv-pk/aclocal.m4 vendored
View File

@ -1,333 +0,0 @@
#=========================================================================
# Local Autoconf Macros
#=========================================================================
# This file contains the macros for the Modular C++ Build System and
# additional autoconf macros which developers can use in their
# configure.ac scripts. Please read the documentation in
# 'mcppbs-doc.txt' for more details on how the Modular C++ Build System
# works. The documenation for each macro should include information
# about the author, date, and copyright.
#-------------------------------------------------------------------------
# MCPPBS_PROG_INSTALL
#-------------------------------------------------------------------------
# This macro will add an --enable-stow command line option to the
# configure script. When enabled, this macro will first check to see if
# the stow program is available and if so it will set the $stow shell
# variable to the binary name and the $enable_stow shell variable to
# "yes". These variables can be used in a makefile to conditionally use
# stow for installation.
#
# This macro uses two environment variables to help setup default stow
# locations. The $STOW_PREFIX is used for stowing native built packages.
# The packages are staged in $STOW_PREFIX/pkgs and then symlinks are
# created from within $STOW_PREFIX into the pkgs subdirectory. If you
# only do native builds then this is all you need to set. If you don't
# set $STOW_PREFIX then the default is just the normal default prefix
# which is almost always /usr/local.
#
# For non-native builds we probably want to install the packages in a
# different location which includes the host architecture name as part
# of the prefix. For these kind of builds, we can specify the $STOW_ROOT
# environment variable and the effective prefix will be
# $STOW_ROOT/${host_alias} where ${host_alias} is specified on the
# configure command line with "--host".
#
# Here is an example setup:
#
# STOW_ROOT="$HOME/install"
# STOW_ARCH="i386-macosx10.4"
# STOW_PREFIX="${STOW_ROOT}/${STOW_ARCH}"
#
AC_DEFUN([MCPPBS_PROG_INSTALL],
[
# Configure command line option
AC_ARG_ENABLE(stow,
AS_HELP_STRING(--enable-stow,[Enable stow-based install]),
[enable_stow="yes"],[enable_stow="no"])
AC_SUBST([enable_stow])
# Environment variables
AC_ARG_VAR([STOW_ROOT], [Root for non-native stow-based installs])
AC_ARG_VAR([STOW_PREFIX], [Prefix for stow-based installs])
# Check for install script
AC_PROG_INSTALL
# Deterimine if native build and set prefix appropriately
AS_IF([ test ${enable_stow} = "yes" ],
[
AC_CHECK_PROGS([stow],[stow],[no])
AS_IF([ test ${stow} = "no" ],
[
AC_MSG_ERROR([Cannot use --enable-stow since stow is not available])
])
# Check if native or non-native build
AS_IF([ test "${build}" = "${host}" ],
[
# build == host so this is a native build. Make sure --prefix not
# set and $STOW_PREFIX is set, then set prefix=$STOW_PREFIX.
AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_PREFIX}" ],
[
prefix="${STOW_PREFIX}"
AC_MSG_NOTICE([Using \$STOW_PREFIX from environment])
AC_MSG_NOTICE([prefix=${prefix}])
])
],[
# build != host so this is a non-native build. Make sure --prefix
# not set and $STOW_ROOT is set, then set
# prefix=$STOW_ROOT/${host_alias}.
AS_IF([ test "${prefix}" = "NONE" && test -n "${STOW_ROOT}" ],
[
prefix="${STOW_ROOT}/${host_alias}"
AC_MSG_NOTICE([Using \$STOW_ROOT from environment])
AC_MSG_NOTICE([prefix=${prefix}])
])
])
])
])
#-------------------------------------------------------------------------
# MCPPBS_SUBPROJECTS([ sproj1, sproj2, ... ])
#-------------------------------------------------------------------------
# The developer should call this macro with a list of the subprojects
# which make up this project. One should order the list such that any
# given subproject only depends on subprojects listed before it. The
# subproject names can also include an * suffix which indicates that
# this is an optional subproject. Optional subprojects are only included
# as part of the project build if enabled on the configure command line
# with a --enable-<subproject> flag. The user can also specify that all
# optional subprojects should be included in the build with the
# --enable-optional-subprojects flag.
#
# Subproject names can also include a ** suffix which indicates that it
# is an optional subproject, but there is a group with the same name.
# Thus the --enable-<sproj> command line option will enable not just the
# subproject sproj but all of the subprojects which are in the group.
# There is no error checking to make sure that if you use the ** suffix
# you actually define a group so be careful.
#
# Both required and optional subprojects should have a 'subproject.ac'
# file. The script's filename should be the abbreivated subproject name
# (assuming the subproject name is sproj then we would use 'sproj.ac')
# The MCPPBS_SUBPROJECTS macro includes the 'subproject.ac' files for
# enabled subprojects. Whitespace and newlines are allowed within the
# list.
#
# Author : Christopher Batten
# Date : September 10, 2008
AC_DEFUN([MCPPBS_SUBPROJECTS],
[
# Add command line argument to enable all optional subprojects
AC_ARG_ENABLE(optional-subprojects,
AS_HELP_STRING([--enable-optional-subprojects],
[Enable all optional subprojects]))
# Loop through the subprojects given in the macro argument
m4_foreach([MCPPBS_SPROJ],[$1],
[
# Determine if this is a required or an optional subproject
m4_define([MCPPBS_IS_REQ],
m4_bmatch(MCPPBS_SPROJ,[\*+],[false],[true]))
# Determine if there is a group with the same name
m4_define([MCPPBS_IS_GROUP],
m4_bmatch(MCPPBS_SPROJ,[\*\*],[true],[false]))
# Create variations of the subproject name suitable for use as a CPP
# enabled define, a shell enabled variable, and a shell function
m4_define([MCPPBS_SPROJ_NORM],
m4_normalize(m4_bpatsubsts(MCPPBS_SPROJ,[*],[])))
m4_define([MCPPBS_SPROJ_DEFINE],
m4_toupper(m4_bpatsubst(MCPPBS_SPROJ_NORM[]_ENABLED,[-],[_])))
m4_define([MCPPBS_SPROJ_FUNC],
m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_]))
m4_define([MCPPBS_SPROJ_UNDERSCORES],
m4_bpatsubsts(MCPPBS_SPROJ,[-],[_]))
m4_define([MCPPBS_SPROJ_SHVAR],
m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_]))
# Add subproject to our running list
subprojects="$subprojects MCPPBS_SPROJ_NORM"
# Process the subproject appropriately. If enabled add it to the
# $enabled_subprojects running shell variable, set a
# SUBPROJECT_ENABLED C define, and include the appropriate
# 'subproject.ac'.
m4_if(MCPPBS_IS_REQ,[true],
[
AC_MSG_NOTICE([configuring default subproject : MCPPBS_SPROJ_NORM])
AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in)
MCPPBS_SPROJ_SHVAR="yes"
subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM"
AC_DEFINE(MCPPBS_SPROJ_DEFINE,,
[Define if subproject MCPPBS_SPROJ_NORM is enabled])
m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac)
],[
# For optional subprojects we capture the 'subproject.ac' as a
# shell function so that in the MCPPBS_GROUP macro we can just
# call this shell function instead of reading in 'subproject.ac'
# again.
MCPPBS_SPROJ_FUNC ()
{
AC_MSG_NOTICE([configuring optional subproject : MCPPBS_SPROJ_NORM])
AC_CONFIG_FILES(MCPPBS_SPROJ_NORM[].mk:MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].mk.in)
MCPPBS_SPROJ_SHVAR="yes"
subprojects_enabled="$subprojects_enabled MCPPBS_SPROJ_NORM"
AC_DEFINE(MCPPBS_SPROJ_DEFINE,,
[Define if subproject MCPPBS_SPROJ_NORM is enabled])
m4_include(MCPPBS_SPROJ_NORM[]/MCPPBS_SPROJ_NORM[].ac)
};
# Optional subprojects add --enable-subproject command line
# options, _if_ the subproject name is not also a group name.
m4_if(MCPPBS_IS_GROUP,[false],
[
AC_ARG_ENABLE(MCPPBS_SPROJ_NORM,
AS_HELP_STRING(--enable-MCPPBS_SPROJ_NORM,
[Subproject MCPPBS_SPROJ_NORM]),
[MCPPBS_SPROJ_SHVAR="yes"],[MCPPBS_SPROJ_SHVAR="no"])
AS_IF([test "$MCPPBS_SPROJ_SHVAR" = "yes"],
[
eval "MCPPBS_SPROJ_FUNC"
],[
AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM])
])
],[
# If the subproject name is also a group name then we need to
# make sure that we set the shell variable for that subproject to
# no so that the group code knows we haven't run it yet.
AC_MSG_NOTICE([processing optional subproject : MCPPBS_SPROJ_NORM])
MCPPBS_SPROJ_SHVAR="no"
])
# Always execute the subproject configure code if we are enabling
# all subprojects.
AS_IF([ test "$enable_optional_subprojects" = "yes" \
&& test "$MCPPBS_SPROJ_SHVAR" = "no" ],
[
eval "MCPPBS_SPROJ_FUNC"
])
])
])
# Output make variables
AC_SUBST([subprojects])
AC_SUBST([subprojects_enabled])
])
#-------------------------------------------------------------------------
# MCPPBS_GROUP( [group-name], [ sproj1, sproj2, ... ] )
#-------------------------------------------------------------------------
# This macro creates a subproject group with the given group-name. When
# a user specifies --enable-<group-name> the listed subprojects will be
# enabled. Groups can have the same name as a subproject and in that
# case whenever a user specifies --enable-<subproject> the subprojects
# listed in the corresponding group will also be enabled. Groups are
# useful for specifying related subprojects which are usually enabled
# together, as well as for specifying that a specific optional
# subproject has dependencies on other optional subprojects.
#
# Author : Christopher Batten
# Date : September 10, 2008
AC_DEFUN([MCPPBS_GROUP],
[
m4_define([MCPPBS_GROUP_NORM],
m4_normalize([$1]))
m4_define([MCPPBS_GROUP_SHVAR],
m4_bpatsubst(enable_[]MCPPBS_GROUP_NORM[]_group,[-],[_]))
AC_ARG_ENABLE(MCPPBS_GROUP_NORM,
AS_HELP_STRING(--enable-MCPPBS_GROUP_NORM,
[Group MCPPBS_GROUP_NORM: $2]),
[MCPPBS_GROUP_SHVAR="yes"],[MCPPBS_GROUP_SHVAR="no"])
AS_IF([test "$MCPPBS_GROUP_SHVAR" = "yes" ],
[
AC_MSG_NOTICE([configuring optional group : MCPPBS_GROUP_NORM])
])
m4_foreach([MCPPBS_SPROJ],[$2],
[
m4_define([MCPPBS_SPROJ_NORM],
m4_normalize(MCPPBS_SPROJ))
m4_define([MCPPBS_SPROJ_SHVAR],
m4_bpatsubst(enable_[]MCPPBS_SPROJ_NORM[]_sproj,[-],[_]))
m4_define([MCPPBS_SPROJ_FUNC],
m4_bpatsubst(_mpbp_[]MCPPBS_SPROJ_NORM[]_configure,[-],[_]))
AS_IF([ test "$MCPPBS_GROUP_SHVAR" = "yes" \
&& test "$MCPPBS_SPROJ_SHVAR" = "no" ],
[
eval "MCPPBS_SPROJ_FUNC"
])
])
])
#-------------------------------------------------------------------------
# AX_DEFAULT_CONFIGURE_ARG
#-------------------------------------------------------------------------
# Simple little macro which adds a configure commane line option to an
# internal autoconf shell variable. Not sure how safe this is, but it
# seems to work fine.
#
# Author : Christopher Batten
# Date : August 20, 2009
AC_DEFUN([AX_DEFAULT_CONFIGURE_ARG],
[
AC_MSG_NOTICE([adding default configure arg: $1])
ac_configure_args="$1 ${ac_configure_args}"
])

View File

@ -1,12 +0,0 @@
AC_ARG_ENABLE([logo], AS_HELP_STRING([--enable-logo], [Enable boot logo]))
AS_IF([test "x$enable_logo" == "xyes"], [
AC_DEFINE([PK_ENABLE_LOGO],,[Define if the RISC-V logo is to be displayed])
])
AC_ARG_WITH([payload], AS_HELP_STRING([--with-payload], [Set ELF payload for bbl]),
[AC_SUBST([BBL_PAYLOAD], $with_payload, [Kernel payload for bbl])],
[AC_SUBST([BBL_PAYLOAD], [dummy_payload], [Kernel payload for bbl])])
AC_ARG_WITH([logo], AS_HELP_STRING([--with-logo], [Specify a better logo]),
[AC_SUBST([BBL_LOGO_FILE], $with_logo, [Logo for bbl])],
[AC_SUBST([BBL_LOGO_FILE], [riscv_logo.txt], [Logo for bbl])])

View File

@ -1,67 +0,0 @@
#include "bbl.h"
#include "mtrap.h"
#include "atomic.h"
#include "vm.h"
#include "bits.h"
#include "config.h"
#include "fdt.h"
#include <string.h>
static const void* entry_point;
long disabled_hart_mask;
static uintptr_t dtb_output()
{
extern char _payload_end;
uintptr_t end = (uintptr_t) &_payload_end;
return (end + MEGAPAGE_SIZE - 1) / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
static void filter_dtb(uintptr_t source)
{
uintptr_t dest = dtb_output();
uint32_t size = fdt_size(source);
memcpy((void*)dest, (void*)source, size);
// Remove information from the chained FDT
filter_harts(dest, &disabled_hart_mask);
filter_plic(dest);
filter_compat(dest, "riscv,clint0");
filter_compat(dest, "riscv,debug-013");
}
void boot_other_hart(uintptr_t unused __attribute__((unused)))
{
const void* entry;
do {
entry = entry_point;
mb();
} while (!entry);
long hartid = read_csr(mhartid);
if ((1 << hartid) & disabled_hart_mask) {
while (1) {
__asm__ volatile("wfi");
#ifdef __riscv_div
__asm__ volatile("div x0, x0, x0");
#endif
}
}
enter_supervisor_mode(entry, hartid, dtb_output(), ~disabled_hart_mask & hart_mask);
}
void boot_loader(uintptr_t dtb)
{
extern char _payload_start;
filter_dtb(dtb);
#ifdef PK_ENABLE_LOGO
print_logo();
#endif
#ifdef PK_PRINT_DEVICE_TREE
fdt_print(dtb_output());
#endif
mb();
entry_point = &_payload_start;
boot_other_hart(0);
}

View File

@ -1,15 +0,0 @@
// See LICENSE for license details.
#ifndef _BBL_H
#define _BBL_H
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
void print_logo();
#endif // !__ASSEMBLER__
#endif

View File

@ -1,111 +0,0 @@
OUTPUT_ARCH( "riscv" )
ENTRY( reset_vector )
SECTIONS
{
/*--------------------------------------------------------------------*/
/* Code and read-only segment */
/*--------------------------------------------------------------------*/
/* Begining of code and text segment */
. = 0x80000000;
_ftext = .;
PROVIDE( eprol = . );
.text :
{
*(.text.init)
}
/* text: Program code section */
.text :
{
*(.text)
*(.text.*)
*(.gnu.linkonce.t.*)
}
/* rodata: Read-only data */
.rodata :
{
*(.rdata)
*(.rodata)
*(.rodata.*)
*(.gnu.linkonce.r.*)
}
/* End of code and read-only segment */
PROVIDE( etext = . );
_etext = .;
/*--------------------------------------------------------------------*/
/* HTIF, isolated onto separate page */
/*--------------------------------------------------------------------*/
. = ALIGN(0x1000);
.htif :
{
PROVIDE( __htif_base = .);
*(.htif)
}
. = ALIGN(0x1000);
/*--------------------------------------------------------------------*/
/* Initialized data segment */
/*--------------------------------------------------------------------*/
/* Start of initialized data segment */
. = ALIGN(16);
_fdata = .;
/* data: Writable data */
.data :
{
*(.data)
*(.data.*)
*(.srodata*)
*(.gnu.linkonce.d.*)
*(.comment)
}
/* End of initialized data segment */
. = ALIGN(4);
PROVIDE( edata = . );
_edata = .;
/*--------------------------------------------------------------------*/
/* Uninitialized data segment */
/*--------------------------------------------------------------------*/
/* Start of uninitialized data segment */
. = .;
_fbss = .;
/* sbss: Uninitialized writeable small data section */
. = .;
/* bss: Uninitialized writeable data section */
. = .;
_bss_start = .;
.bss :
{
*(.bss)
*(.bss.*)
*(.sbss*)
*(.gnu.linkonce.b.*)
*(COMMON)
}
.sbi :
{
*(.sbi)
}
.payload :
{
*(.payload)
}
_end = .;
}

View File

@ -1,29 +0,0 @@
bbl_subproject_deps = \
util \
machine \
dummy_payload \
bbl_hdrs = \
bbl.h \
bbl_c_srcs = \
logo.c \
bbl_asm_srcs = \
payload.S \
raw_logo.S \
payload.o: bbl_payload
bbl_payload: $(BBL_PAYLOAD)
if $(READELF) -h $< 2> /dev/null > /dev/null; then $(OBJCOPY) -O binary $< $@; else cp $< $@; fi
raw_logo.o: bbl_logo_file
bbl_logo_file: @BBL_LOGO_FILE@
cat $^ | sed 's/$$/\r/' > $@
bbl_test_srcs =
bbl_install_prog_srcs = \
bbl.c \

View File

@ -1,9 +0,0 @@
#include <string.h>
#include "mtrap.h"
extern const char logo[];
void print_logo()
{
putstring(logo);
}

View File

@ -1,9 +0,0 @@
#include "encoding.h"
.section ".payload","a",@progbits
.align 17
.globl _payload_start, _payload_end
_payload_start:
.incbin BBL_PAYLOAD
_payload_end:

View File

@ -1,7 +0,0 @@
#include "encoding.h"
.section .rodata
.globl logo
logo:
.incbin BBL_LOGO_FILE
.byte 0

View File

@ -1,23 +0,0 @@
vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv
vvvvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvv
rrrrrrrrrrrrr vvvvvvvvvvvvvvvvvvvvvv
rr vvvvvvvvvvvvvvvvvvvvvv
rr vvvvvvvvvvvvvvvvvvvvvvvv rr
rrrr vvvvvvvvvvvvvvvvvvvvvvvvvv rrrr
rrrrrr vvvvvvvvvvvvvvvvvvvvvv rrrrrr
rrrrrrrr vvvvvvvvvvvvvvvvvv rrrrrrrr
rrrrrrrrrr vvvvvvvvvvvvvv rrrrrrrrrr
rrrrrrrrrrrr vvvvvvvvvv rrrrrrrrrrrr
rrrrrrrrrrrrrr vvvvvv rrrrrrrrrrrrrr
rrrrrrrrrrrrrrrr vv rrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrr
rrrrrrrrrrrrrrrrrrrrrr rrrrrrrrrrrrrrrrrrrrrr
INSTRUCTION SETS WANT TO BE FREE

View File

@ -1,52 +0,0 @@
/* config.h.in. Generated from configure.ac by autoheader. */
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef BBL_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef DUMMY_PAYLOAD_ENABLED
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef MACHINE_ENABLED
/* Define to the address where bug reports for this package should be sent. */
#undef PACKAGE_BUGREPORT
/* Define to the full name of this package. */
#undef PACKAGE_NAME
/* Define to the full name and version of this package. */
#undef PACKAGE_STRING
/* Define to the one symbol short name of this package. */
#undef PACKAGE_TARNAME
/* Define to the home page for this package. */
#undef PACKAGE_URL
/* Define to the version of this package. */
#undef PACKAGE_VERSION
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef PK_ENABLED
/* Define if floating-point emulation is enabled */
#undef PK_ENABLE_FP_EMULATION
/* Define if the RISC-V logo is to be displayed */
#undef PK_ENABLE_LOGO
/* Define if virtual memory support is enabled */
#undef PK_ENABLE_VM
/* Define if the DTS is to be displayed */
#undef PK_PRINT_DEVICE_TREE
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef SOFTFLOAT_ENABLED
/* Define to 1 if you have the ANSI C header files. */
#undef STDC_HEADERS
/* Define if subproject MCPPBS_SPROJ_NORM is enabled */
#undef UTIL_ENABLED

5775
riscv-pk/configure vendored

File diff suppressed because it is too large Load Diff

View File

@ -1,138 +0,0 @@
#=========================================================================
# Toplevel configure.ac for the Modular C++ Build System
#=========================================================================
# Please read the documenation in 'mcppbs-doc.txt' for more details on
# how the Modular C++ Build System works. For most new projects, a
# developer will only need to make the following changes:
#
# - change the project metadata listed right below
# - update the list of subprojects via the 'MCPPBS_SUBPROJECTS' macro
# - possibly add subproject groups if needed to ease configuration
# - add more configure checks for platform specific configuration
#
#-------------------------------------------------------------------------
# Project metadata
#-------------------------------------------------------------------------
m4_define( proj_name, [RISC-V Proxy Kernel])
m4_define( proj_maintainer, [Andrew Waterman])
m4_define( proj_abbreviation, [riscv-pk])
#-------------------------------------------------------------------------
# Project version information
#-------------------------------------------------------------------------
# Version information is meant to be managed through a version control
# system's tags and revision numbers. In a working copy the version will
# not be defined here (you should just use the version control system's
# mechanisms). When we make a distribution then we can set the version
# here as formed by the scripts/vcs-version.sh script so that the
# distribution knows what version it came from. If you are not using
# version control then it is fine to set this directly.
m4_define( proj_version, [?])
#-------------------------------------------------------------------------
# Setup
#-------------------------------------------------------------------------
AC_INIT(proj_name,proj_version,proj_maintainer,proj_abbreviation)
AC_CONFIG_SRCDIR([pk/pk.h])
AC_CONFIG_AUX_DIR([scripts])
AC_CANONICAL_BUILD
AC_CANONICAL_HOST
#-------------------------------------------------------------------------
# Checks for programs
#-------------------------------------------------------------------------
AC_PROG_CC
AC_PROG_CXX
AC_CHECK_TOOL([AR],[ar])
AC_CHECK_TOOL([RANLIB],[ranlib])
AC_CHECK_TOOL([READELF],[readelf])
AC_CHECK_TOOL([OBJCOPY],[objcopy])
#-------------------------------------------------------------------------
# MCPPBS specific program checks
#-------------------------------------------------------------------------
# These macros check to see if we can do a stow-based install and also
# check for an isa simulator suitable for running the unit test programs
# via the makefile.
MCPPBS_PROG_INSTALL
#-------------------------------------------------------------------------
# Checks for header files
#-------------------------------------------------------------------------
AC_HEADER_STDC
#-------------------------------------------------------------------------
# Register RISCV environment variable
#-------------------------------------------------------------------------
AC_ARG_VAR(RISCV, [top-level RISC-V install directory])
#-------------------------------------------------------------------------
# Set compiler flags
#-------------------------------------------------------------------------
default_CFLAGS="-Wall -Werror -D__NO_INLINE__ -mcmodel=medany -O2 -std=gnu99 -Wno-unused -Wno-attributes -fno-delete-null-pointer-checks"
AC_ARG_ENABLE([32bit],
AS_HELP_STRING([--enable-32bit], [Build a 32-bit pk]),
BUILD_32BIT=$enableval,
BUILD_32BIT=no)
case "${BUILD_32BIT}" in
yes|default)
echo "Building 32-bit pk"
CFLAGS="$default_CFLAGS -march=rv32iac -mabi=ilp32"
LDFLAGS="-march=rv32iac -mabi=ilp32"
install_subdir="riscv32-unknown-elf"
;;
*)
CFLAGS="$default_CFLAGS"
LDFLAGS=
install_subdir="riscv64-unknown-elf"
;;
esac
AC_ARG_ENABLE([print-device-tree], AS_HELP_STRING([--enable-print-device-tree], [Print DTS when booting]))
AS_IF([test "x$enable_print_device_tree" == "xyes"], [
AC_DEFINE([PK_PRINT_DEVICE_TREE],,[Define if the DTS is to be displayed])
])
AC_SUBST(CFLAGS)
AC_SUBST(LDFLAGS)
AC_SUBST([LIBS], ["-lgcc"])
AC_SUBST(install_subdir)
#-------------------------------------------------------------------------
# MCPPBS subproject list
#-------------------------------------------------------------------------
# Order list so that subprojects only depend on those listed earlier.
# The '*' suffix indicates an optional subproject. The '**' suffix
# indicates an optional subproject which is also the name of a group.
MCPPBS_SUBPROJECTS([ pk, bbl, dummy_payload, machine, util ])
#-------------------------------------------------------------------------
# MCPPBS subproject groups
#-------------------------------------------------------------------------
# If a group has the same name as a subproject then you must add the
# '**' suffix in the subproject list above. The list of subprojects in a
# group should be ordered so that subprojets only depend on those listed
# earlier. Here is an example:
#
# MCPPBS_GROUP( [group-name], [sproja,sprojb,...] )
#
#-------------------------------------------------------------------------
# Output
#-------------------------------------------------------------------------
AC_CONFIG_HEADERS([config.h])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT

View File

@ -1,22 +0,0 @@
#include "mcall.h"
.section ".text.init"
.globl _start
_start:
la s0, str
1:
lbu a0, (s0)
beqz a0, 1f
li a7, SBI_CONSOLE_PUTCHAR
ecall
add s0, s0, 1
j 1b
1:
li a7, SBI_SHUTDOWN
ecall
.data
str:
.asciz "This is bbl's dummy_payload. To boot a real kernel, reconfigure\n\
bbl with the flag --with-payload=PATH, then rebuild bbl.\n"

View File

@ -1,7 +0,0 @@
ENTRY(_start)
SECTIONS {
. = -0x80000000;
.text.init : { *(.text.init) }
}

View File

@ -1,13 +0,0 @@
dummy_payload_subproject_deps = \
dummy_payload_hdrs = \
dummy_payload_c_srcs = \
dummy_payload_asm_srcs = \
dummy_entry.S \
dummy_payload_test_srcs =
dummy_payload_install_prog_srcs = \
dummy_payload.c \

View File

@ -1,78 +0,0 @@
// See LICENSE for license details.
#ifndef _RISCV_ATOMIC_H
#define _RISCV_ATOMIC_H
#include "config.h"
#include "encoding.h"
// Currently, interrupts are always disabled in M-mode.
#define disable_irqsave() (0)
#define enable_irqrestore(flags) ((void) (flags))
typedef struct { int lock; } spinlock_t;
#define SPINLOCK_INIT {0}
#define mb() asm volatile ("fence" ::: "memory")
#define atomic_set(ptr, val) (*(volatile typeof(*(ptr)) *)(ptr) = val)
#define atomic_read(ptr) (*(volatile typeof(*(ptr)) *)(ptr))
#ifdef __riscv_atomic
# define atomic_add(ptr, inc) __sync_fetch_and_add(ptr, inc)
# define atomic_or(ptr, inc) __sync_fetch_and_or(ptr, inc)
# define atomic_swap(ptr, swp) __sync_lock_test_and_set(ptr, swp)
# define atomic_cas(ptr, cmp, swp) __sync_val_compare_and_swap(ptr, cmp, swp)
#else
# define atomic_binop(ptr, inc, op) ({ \
long flags = disable_irqsave(); \
typeof(*(ptr)) res = atomic_read(ptr); \
atomic_set(ptr, op); \
enable_irqrestore(flags); \
res; })
# define atomic_add(ptr, inc) atomic_binop(ptr, inc, res + (inc))
# define atomic_or(ptr, inc) atomic_binop(ptr, inc, res | (inc))
# define atomic_swap(ptr, inc) atomic_binop(ptr, inc, (inc))
# define atomic_cas(ptr, cmp, swp) ({ \
long flags = disable_irqsave(); \
typeof(*(ptr)) res = *(volatile typeof(*(ptr)) *)(ptr); \
if (res == (cmp)) *(volatile typeof(ptr))(ptr) = (swp); \
enable_irqrestore(flags); \
res; })
#endif
static inline int spinlock_trylock(spinlock_t* lock)
{
int res = atomic_swap(&lock->lock, -1);
mb();
return res;
}
static inline void spinlock_lock(spinlock_t* lock)
{
do
{
while (atomic_read(&lock->lock))
;
} while (spinlock_trylock(lock));
}
static inline void spinlock_unlock(spinlock_t* lock)
{
mb();
atomic_set(&lock->lock,0);
}
static inline long spinlock_lock_irqsave(spinlock_t* lock)
{
long flags = disable_irqsave();
spinlock_lock(lock);
return flags;
}
static inline void spinlock_unlock_irqrestore(spinlock_t* lock, long flags)
{
spinlock_unlock(lock);
enable_irqrestore(flags);
}
#endif

View File

@ -1,35 +0,0 @@
#ifndef _RISCV_BITS_H
#define _RISCV_BITS_H
#define likely(x) __builtin_expect((x), 1)
#define unlikely(x) __builtin_expect((x), 0)
#define ROUNDUP(a, b) ((((a)-1)/(b)+1)*(b))
#define ROUNDDOWN(a, b) ((a)/(b)*(b))
#define MAX(a, b) ((a) > (b) ? (a) : (b))
#define MIN(a, b) ((a) < (b) ? (a) : (b))
#define CLAMP(a, lo, hi) MIN(MAX(a, lo), hi)
#define EXTRACT_FIELD(val, which) (((val) & (which)) / ((which) & ~((which)-1)))
#define INSERT_FIELD(val, which, fieldval) (((val) & ~(which)) | ((fieldval) * ((which) & ~((which)-1))))
#define STR(x) XSTR(x)
#define XSTR(x) #x
#if __riscv_xlen == 64
# define SLL32 sllw
# define STORE sd
# define LOAD ld
# define LWU lwu
# define LOG_REGBYTES 3
#else
# define SLL32 sll
# define STORE sw
# define LOAD lw
# define LWU lw
# define LOG_REGBYTES 2
#endif
#define REGBYTES (1 << LOG_REGBYTES)
#endif

View File

@ -1,4 +0,0 @@
#ifndef DISABLED_HART_MASK_H
#define DISABLED_HART_MASK_H
extern long disabled_hart_mask;
#endif

View File

@ -1,234 +0,0 @@
#include "emulation.h"
//#include "fp_emulation.h"
#include "config.h"
#include "unprivileged_memory.h"
#include "mtrap.h"
#include <limits.h>
static DECLARE_EMULATION_FUNC(emulate_rvc)
{
#ifdef __riscv_compressed
// the only emulable RVC instructions are FP loads and stores.
# if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
write_csr(mepc, mepc + 2);
// if FPU is disabled, punt back to the OS
if (unlikely((mstatus & MSTATUS_FS) == 0))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
if ((insn & MASK_C_FLD) == MATCH_C_FLD) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LD_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_load_trap(regs, mcause, mepc);
SET_F64_RD(RVC_RS2S(insn) << SH_RD, regs, load_uint64_t((void *)addr, mepc));
} else if ((insn & MASK_C_FLDSP) == MATCH_C_FLDSP) {
uintptr_t addr = GET_SP(regs) + RVC_LDSP_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_load_trap(regs, mcause, mepc);
SET_F64_RD(insn, regs, load_uint64_t((void *)addr, mepc));
} else if ((insn & MASK_C_FSD) == MATCH_C_FSD) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LD_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_store_trap(regs, mcause, mepc);
store_uint64_t((void *)addr, GET_F64_RS2(RVC_RS2S(insn) << SH_RS2, regs), mepc);
} else if ((insn & MASK_C_FSDSP) == MATCH_C_FSDSP) {
uintptr_t addr = GET_SP(regs) + RVC_SDSP_IMM(insn);
if (unlikely(addr % sizeof(uintptr_t)))
return misaligned_store_trap(regs, mcause, mepc);
store_uint64_t((void *)addr, GET_F64_RS2(RVC_RS2(insn) << SH_RS2, regs), mepc);
} else
# if __riscv_xlen == 32
if ((insn & MASK_C_FLW) == MATCH_C_FLW) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LW_IMM(insn);
if (unlikely(addr % 4))
return misaligned_load_trap(regs, mcause, mepc);
SET_F32_RD(RVC_RS2S(insn) << SH_RD, regs, load_int32_t((void *)addr, mepc));
} else if ((insn & MASK_C_FLWSP) == MATCH_C_FLWSP) {
uintptr_t addr = GET_SP(regs) + RVC_LWSP_IMM(insn);
if (unlikely(addr % 4))
return misaligned_load_trap(regs, mcause, mepc);
SET_F32_RD(insn, regs, load_int32_t((void *)addr, mepc));
} else if ((insn & MASK_C_FSW) == MATCH_C_FSW) {
uintptr_t addr = GET_RS1S(insn, regs) + RVC_LW_IMM(insn);
if (unlikely(addr % 4))
return misaligned_store_trap(regs, mcause, mepc);
store_uint32_t((void *)addr, GET_F32_RS2(RVC_RS2S(insn) << SH_RS2, regs), mepc);
} else if ((insn & MASK_C_FSWSP) == MATCH_C_FSWSP) {
uintptr_t addr = GET_SP(regs) + RVC_SWSP_IMM(insn);
if (unlikely(addr % 4))
return misaligned_store_trap(regs, mcause, mepc);
store_uint32_t((void *)addr, GET_F32_RS2(RVC_RS2(insn) << SH_RS2, regs), mepc);
} else
# endif
# endif
#endif
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
}
void illegal_insn_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
asm (".pushsection .rodata\n"
"illegal_insn_trap_table:\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
" .word emulate_float_load\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
" .word emulate_float_store\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#if !defined(__riscv_muldiv)
" .word emulate_mul_div\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
#if !defined(__riscv_muldiv) && __riscv_xlen >= 64
" .word emulate_mul_div32\n"
#else
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
#ifdef PK_ENABLE_FP_EMULATION
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fmadd\n"
" .word emulate_fp\n"
#else
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
#endif
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word emulate_system_opcode\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .word truly_illegal_insn\n"
" .popsection");
uintptr_t mstatus = read_csr(mstatus);
insn_t insn = read_csr(mbadaddr);
if (unlikely((insn & 3) != 3)) {
if (insn == 0)
insn = get_insn(mepc, &mstatus);
if ((insn & 3) != 3)
return emulate_rvc(regs, mcause, mepc, mstatus, insn);
}
write_csr(mepc, mepc + 4);
extern uint32_t illegal_insn_trap_table[];
uint32_t* pf = (void*)illegal_insn_trap_table + (insn & 0x7c);
emulation_func f = (emulation_func)(uintptr_t)*pf;
f(regs, mcause, mepc, mstatus, insn);
}
__attribute__((noinline))
DECLARE_EMULATION_FUNC(truly_illegal_insn)
{
return redirect_trap(mepc, mstatus, insn);
}
static inline int emulate_read_csr(int num, uintptr_t mstatus, uintptr_t* result)
{
uintptr_t counteren = -1;
if (EXTRACT_FIELD(mstatus, MSTATUS_MPP) == PRV_U)
counteren = read_csr(scounteren);
switch (num)
{
case CSR_TIME:
if (!((counteren >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*result = *mtime;
return 0;
#if __riscv_xlen == 32
case CSR_TIMEH:
if (!((counteren >> (CSR_TIME - CSR_CYCLE)) & 1))
return -1;
*result = *mtime >> 32;
return 0;
#endif
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
case CSR_FRM:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FRM();
return 0;
case CSR_FFLAGS:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FFLAGS();
return 0;
case CSR_FCSR:
if ((mstatus & MSTATUS_FS) == 0) break;
*result = GET_FCSR();
return 0;
#endif
}
return -1;
}
static inline int emulate_write_csr(int num, uintptr_t value, uintptr_t mstatus)
{
switch (num)
{
#if !defined(__riscv_flen) && defined(PK_ENABLE_FP_EMULATION)
case CSR_FRM: SET_FRM(value); return 0;
case CSR_FFLAGS: SET_FFLAGS(value); return 0;
case CSR_FCSR: SET_FCSR(value); return 0;
#endif
}
return -1;
}
DECLARE_EMULATION_FUNC(emulate_system_opcode)
{
int rs1_num = (insn >> 15) & 0x1f;
uintptr_t rs1_val = GET_RS1(insn, regs);
int csr_num = (uint32_t)insn >> 20;
uintptr_t csr_val, new_csr_val;
if (emulate_read_csr(csr_num, mstatus, &csr_val))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
int do_write = rs1_num;
#if 0
switch (GET_RM(insn))
{
case 0: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
case 1: new_csr_val = rs1_val; do_write = 1; break;
case 2: new_csr_val = csr_val | rs1_val; break;
case 3: new_csr_val = csr_val & ~rs1_val; break;
case 4: return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
case 5: new_csr_val = rs1_num; do_write = 1; break;
case 6: new_csr_val = csr_val | rs1_num; break;
case 7: new_csr_val = csr_val & ~rs1_num; break;
}
#endif
if (do_write && emulate_write_csr(csr_num, new_csr_val, mstatus))
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, csr_val);
}

View File

@ -1,51 +0,0 @@
#ifndef _RISCV_EMULATION_H
#define _RISCV_EMULATION_H
#include "encoding.h"
#include "bits.h"
#include <stdint.h>
typedef uintptr_t insn_t;
typedef void (*emulation_func)(uintptr_t*, uintptr_t, uintptr_t, uintptr_t, insn_t);
#define DECLARE_EMULATION_FUNC(name) void name(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc, uintptr_t mstatus, insn_t insn)
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc);
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr);
DECLARE_EMULATION_FUNC(truly_illegal_insn);
DECLARE_EMULATION_FUNC(emulate_rvc_0);
DECLARE_EMULATION_FUNC(emulate_rvc_2);
#define SH_RD 7
#define SH_RS1 15
#define SH_RS2 20
#define SH_RS2C 2
#define RV_X(x, s, n) (((x) >> (s)) & ((1 << (n)) - 1))
#define RVC_LW_IMM(x) ((RV_X(x, 6, 1) << 2) | (RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 1) << 6))
#define RVC_LD_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 5, 2) << 6))
#define RVC_LWSP_IMM(x) ((RV_X(x, 4, 3) << 2) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 2) << 6))
#define RVC_LDSP_IMM(x) ((RV_X(x, 5, 2) << 3) | (RV_X(x, 12, 1) << 5) | (RV_X(x, 2, 3) << 6))
#define RVC_SWSP_IMM(x) ((RV_X(x, 9, 4) << 2) | (RV_X(x, 7, 2) << 6))
#define RVC_SDSP_IMM(x) ((RV_X(x, 10, 3) << 3) | (RV_X(x, 7, 3) << 6))
#define RVC_RS1S(insn) (8 + RV_X(insn, SH_RD, 3))
#define RVC_RS2S(insn) (8 + RV_X(insn, SH_RS2C, 3))
#define RVC_RS2(insn) RV_X(insn, SH_RS2C, 5)
#define SHIFT_RIGHT(x, y) ((y) < 0 ? ((x) << -(y)) : ((x) >> (y)))
#define GET_REG(insn, pos, regs) ({ \
int mask = (1 << (5+LOG_REGBYTES)) - (1 << LOG_REGBYTES); \
(uintptr_t*)((uintptr_t)regs + (SHIFT_RIGHT(insn, (pos) - LOG_REGBYTES) & (mask))); \
})
#define GET_RS1(insn, regs) (*GET_REG(insn, SH_RS1, regs))
#define GET_RS2(insn, regs) (*GET_REG(insn, SH_RS2, regs))
#define GET_RS1S(insn, regs) (*GET_REG(RVC_RS1S(insn), 0, regs))
#define GET_RS2S(insn, regs) (*GET_REG(RVC_RS2S(insn), 0, regs))
#define GET_RS2C(insn, regs) (*GET_REG(insn, SH_RS2C, regs))
#define GET_SP(regs) (*GET_REG(2, 0, regs))
#define SET_RD(insn, regs, val) (*GET_REG(insn, SH_RD, regs) = (val))
#define IMM_I(insn) ((int32_t)(insn) >> 20)
#define IMM_S(insn) (((int32_t)(insn) >> 25 << 5) | (int32_t)(((insn) >> 7) & 0x1f))
#define MASK_FUNCT3 0x7000
#endif

File diff suppressed because it is too large Load Diff

View File

@ -1,740 +0,0 @@
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include "config.h"
#include "fdt.h"
#include "mtrap.h"
static inline uint32_t bswap(uint32_t x)
{
uint32_t y = (x & 0x00FF00FF) << 8 | (x & 0xFF00FF00) >> 8;
uint32_t z = (y & 0x0000FFFF) << 16 | (y & 0xFFFF0000) >> 16;
return z;
}
static inline int isstring(char c)
{
if (c >= 'A' && c <= 'Z')
return 1;
if (c >= 'a' && c <= 'z')
return 1;
if (c >= '0' && c <= '9')
return 1;
if (c == '\0' || c == ' ' || c == ',' || c == '-')
return 1;
return 0;
}
static uint32_t *fdt_scan_helper(
uint32_t *lex,
const char *strings,
struct fdt_scan_node *node,
const struct fdt_cb *cb)
{
struct fdt_scan_node child;
struct fdt_scan_prop prop;
int last = 0;
child.parent = node;
// these are the default cell counts, as per the FDT spec
child.address_cells = 2;
child.size_cells = 1;
prop.node = node;
while (1) {
switch (bswap(lex[0])) {
case FDT_NOP: {
lex += 1;
break;
}
case FDT_PROP: {
assert (!last);
prop.name = strings + bswap(lex[2]);
prop.len = bswap(lex[1]);
prop.value = lex + 3;
if (node && !strcmp(prop.name, "#address-cells")) { node->address_cells = bswap(lex[3]); }
if (node && !strcmp(prop.name, "#size-cells")) { node->size_cells = bswap(lex[3]); }
lex += 3 + (prop.len+3)/4;
cb->prop(&prop, cb->extra);
break;
}
case FDT_BEGIN_NODE: {
uint32_t *lex_next;
if (!last && node && cb->done) cb->done(node, cb->extra);
last = 1;
child.name = (const char *)(lex+1);
if (cb->open) cb->open(&child, cb->extra);
lex_next = fdt_scan_helper(
lex + 2 + strlen(child.name)/4,
strings, &child, cb);
if (cb->close && cb->close(&child, cb->extra) == -1)
while (lex != lex_next) *lex++ = bswap(FDT_NOP);
lex = lex_next;
break;
}
case FDT_END_NODE: {
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex + 1;
}
default: { // FDT_END
if (!last && node && cb->done) cb->done(node, cb->extra);
return lex;
}
}
}
}
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return;
const char *strings = (const char *)(fdt + bswap(header->off_dt_strings));
uint32_t *lex = (uint32_t *)(fdt + bswap(header->off_dt_struct));
fdt_scan_helper(lex, strings, 0, cb);
}
uint32_t fdt_size(uintptr_t fdt)
{
struct fdt_header *header = (struct fdt_header *)fdt;
// Only process FDT that we understand
if (bswap(header->magic) != FDT_MAGIC ||
bswap(header->last_comp_version) > FDT_VERSION) return 0;
return bswap(header->totalsize);
}
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->address_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *value, uint64_t *result)
{
*result = 0;
for (int cells = node->size_cells; cells > 0; --cells)
*result = (*result << 32) + bswap(*value++);
return value;
}
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str)
{
const char *list = (const char *)prop->value;
const char *end = list + prop->len;
int index = 0;
while (end - list > 0) {
if (!strcmp(list, str)) return index;
++index;
list += strlen(list) + 1;
}
return -1;
}
//////////////////////////////////////////// MEMORY SCAN /////////////////////////////////////////
struct mem_scan {
int memory;
const uint32_t *reg_value;
int reg_len;
};
static void mem_open(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void mem_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "memory")) {
scan->memory = 1;
} else if (!strcmp(prop->name, "reg")) {
scan->reg_value = prop->value;
scan->reg_len = prop->len;
}
}
static void mem_done(const struct fdt_scan_node *node, void *extra)
{
struct mem_scan *scan = (struct mem_scan *)extra;
const uint32_t *value = scan->reg_value;
const uint32_t *end = value + scan->reg_len/4;
uintptr_t self = (uintptr_t)mem_done;
if (!scan->memory) return;
assert (scan->reg_value && scan->reg_len % 4 == 0);
while (end - value > 0) {
uint64_t base, size;
value = fdt_get_address(node->parent, value, &base);
value = fdt_get_size (node->parent, value, &size);
if (base <= self && self <= base + size) { mem_size = size; }
}
assert (end == value);
}
void query_mem(uintptr_t fdt)
{
struct fdt_cb cb;
struct mem_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = mem_open;
cb.prop = mem_prop;
cb.done = mem_done;
cb.extra = &scan;
mem_size = 0;
fdt_scan(fdt, &cb);
assert (mem_size > 0);
}
///////////////////////////////////////////// HART SCAN //////////////////////////////////////////
static uint32_t hart_phandles[MAX_HARTS];
uint64_t hart_mask;
struct hart_scan {
const struct fdt_scan_node *cpu;
int hart;
const struct fdt_scan_node *controller;
int cells;
uint32_t phandle;
};
static void hart_open(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (!scan->cpu) {
scan->hart = -1;
}
if (!scan->controller) {
scan->cells = 0;
scan->phandle = 0;
}
}
static void hart_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) {
assert (!scan->cpu);
scan->cpu = prop->node;
} else if (!strcmp(prop->name, "interrupt-controller")) {
assert (!scan->controller);
scan->controller = prop->node;
} else if (!strcmp(prop->name, "#interrupt-cells")) {
scan->cells = bswap(prop->value[0]);
} else if (!strcmp(prop->name, "phandle")) {
scan->phandle = bswap(prop->value[0]);
} else if (!strcmp(prop->name, "reg")) {
uint64_t reg;
fdt_get_address(prop->node->parent, prop->value, &reg);
scan->hart = reg;
}
}
static void hart_done(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (scan->cpu == node) {
assert (scan->hart >= 0);
}
if (scan->controller == node && scan->cpu) {
assert (scan->phandle > 0);
assert (scan->cells == 1);
if (scan->hart < MAX_HARTS) {
hart_phandles[scan->hart] = scan->phandle;
hart_mask |= 1 << scan->hart;
hls_init(scan->hart);
}
}
}
static int hart_close(const struct fdt_scan_node *node, void *extra)
{
struct hart_scan *scan = (struct hart_scan *)extra;
if (scan->cpu == node) scan->cpu = 0;
if (scan->controller == node) scan->controller = 0;
return 0;
}
void query_harts(uintptr_t fdt)
{
struct fdt_cb cb;
struct hart_scan scan;
memset(&cb, 0, sizeof(cb));
memset(&scan, 0, sizeof(scan));
cb.open = hart_open;
cb.prop = hart_prop;
cb.done = hart_done;
cb.close= hart_close;
cb.extra = &scan;
fdt_scan(fdt, &cb);
// The current hart should have been detected
assert ((hart_mask >> read_csr(mhartid)) != 0);
}
///////////////////////////////////////////// CLINT SCAN /////////////////////////////////////////
struct clint_scan
{
int compat;
uint64_t reg;
const uint32_t *int_value;
int int_len;
int done;
};
static void clint_open(const struct fdt_scan_node *node, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
scan->compat = 0;
scan->reg = 0;
scan->int_value = 0;
}
static void clint_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,clint0") >= 0) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
} else if (!strcmp(prop->name, "interrupts-extended")) {
scan->int_value = prop->value;
scan->int_len = prop->len;
}
}
static void clint_done(const struct fdt_scan_node *node, void *extra)
{
struct clint_scan *scan = (struct clint_scan *)extra;
const uint32_t *value = scan->int_value;
const uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
assert (scan->reg != 0);
assert (scan->int_value && scan->int_len % 16 == 0);
assert (!scan->done); // only one clint
scan->done = 1;
mtime = (void*)((uintptr_t)scan->reg + 0xbff8);
for (int index = 0; end - value > 0; ++index) {
uint32_t phandle = bswap(value[0]);
int hart;
for (hart = 0; hart < MAX_HARTS; ++hart)
if (hart_phandles[hart] == phandle)
break;
if (hart < MAX_HARTS) {
hls_t *hls = OTHER_HLS(hart);
hls->ipi = (void*)((uintptr_t)scan->reg + index * 4);
hls->timecmp = (void*)((uintptr_t)scan->reg + 0x4000 + (index * 8));
}
value += 4;
}
}
void query_clint(uintptr_t fdt)
{
struct fdt_cb cb;
struct clint_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = clint_open;
cb.prop = clint_prop;
cb.done = clint_done;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
assert (scan.done);
}
///////////////////////////////////////////// PLIC SCAN /////////////////////////////////////////
struct plic_scan
{
int compat;
uint64_t reg;
uint32_t *int_value;
int int_len;
int done;
int ndev;
};
static void plic_open(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
scan->compat = 0;
scan->reg = 0;
scan->int_value = 0;
}
static void plic_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, "riscv,plic0") >= 0) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
} else if (!strcmp(prop->name, "interrupts-extended")) {
scan->int_value = prop->value;
scan->int_len = prop->len;
} else if (!strcmp(prop->name, "riscv,ndev")) {
scan->ndev = bswap(prop->value[0]);
}
}
#define HART_BASE 0x200000
#define HART_SIZE 0x1000
#define ENABLE_BASE 0x2000
#define ENABLE_SIZE 0x80
static void plic_done(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
const uint32_t *value = scan->int_value;
const uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
assert (scan->reg != 0);
assert (scan->int_value && scan->int_len % 8 == 0);
assert (scan->ndev >= 0 && scan->ndev < 1024);
assert (!scan->done); // only one plic
scan->done = 1;
plic_priorities = (uint32_t*)(uintptr_t)scan->reg;
plic_ndevs = scan->ndev;
for (int index = 0; end - value > 0; ++index) {
uint32_t phandle = bswap(value[0]);
uint32_t cpu_int = bswap(value[1]);
int hart;
for (hart = 0; hart < MAX_HARTS; ++hart)
if (hart_phandles[hart] == phandle)
break;
if (hart < MAX_HARTS) {
hls_t *hls = OTHER_HLS(hart);
if (cpu_int == IRQ_M_EXT) {
hls->plic_m_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
hls->plic_m_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index);
} else if (cpu_int == IRQ_S_EXT) {
hls->plic_s_ie = (uintptr_t*)((uintptr_t)scan->reg + ENABLE_BASE + ENABLE_SIZE * index);
hls->plic_s_thresh = (uint32_t*) ((uintptr_t)scan->reg + HART_BASE + HART_SIZE * index);
} else {
printm("PLIC wired hart %d to wrong interrupt %d", hart, cpu_int);
}
}
value += 2;
}
#if 0
printm("PLIC: prio %x devs %d\r\n", (uint32_t)(uintptr_t)plic_priorities, plic_ndevs);
for (int i = 0; i < MAX_HARTS; ++i) {
hls_t *hls = OTHER_HLS(i);
printm("CPU %d: %x %x %x %x\r\n", i, (uint32_t)(uintptr_t)hls->plic_m_ie, (uint32_t)(uintptr_t)hls->plic_m_thresh, (uint32_t)(uintptr_t)hls->plic_s_ie, (uint32_t)(uintptr_t)hls->plic_s_thresh);
}
#endif
}
void query_plic(uintptr_t fdt)
{
struct fdt_cb cb;
struct plic_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = plic_open;
cb.prop = plic_prop;
cb.done = plic_done;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
}
static void plic_redact(const struct fdt_scan_node *node, void *extra)
{
struct plic_scan *scan = (struct plic_scan *)extra;
uint32_t *value = scan->int_value;
uint32_t *end = value + scan->int_len/4;
if (!scan->compat) return;
scan->done = 1;
while (end - value > 0) {
if (bswap(value[1]) == IRQ_M_EXT) value[1] = bswap(-1);
value += 2;
}
}
void filter_plic(uintptr_t fdt)
{
struct fdt_cb cb;
struct plic_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = plic_open;
cb.prop = plic_prop;
cb.done = plic_redact;
cb.extra = &scan;
scan.done = 0;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// COMPAT SCAN ////////////////////////////////////////
struct compat_scan
{
const char *compat;
int depth;
int kill;
};
static void compat_open(const struct fdt_scan_node *node, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
++scan->depth;
}
static void compat_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
if (!strcmp(prop->name, "compatible") && fdt_string_list_index(prop, scan->compat) >= 0)
if (scan->depth < scan->kill)
scan->kill = scan->depth;
}
static int compat_close(const struct fdt_scan_node *node, void *extra)
{
struct compat_scan *scan = (struct compat_scan *)extra;
if (scan->kill == scan->depth--) {
scan->kill = 999;
return -1;
} else {
return 0;
}
}
void filter_compat(uintptr_t fdt, const char *compat)
{
struct fdt_cb cb;
struct compat_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = compat_open;
cb.prop = compat_prop;
cb.close = compat_close;
cb.extra = &scan;
scan.compat = compat;
scan.depth = 0;
scan.kill = 999;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// HART FILTER ////////////////////////////////////////
struct hart_filter {
int compat;
int hart;
char *status;
char *mmu_type;
long *disabled_hart_mask;
};
static void hart_filter_open(const struct fdt_scan_node *node, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
filter->status = NULL;
filter->mmu_type = NULL;
filter->compat = 0;
filter->hart = -1;
}
static void hart_filter_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
if (!strcmp(prop->name, "device_type") && !strcmp((const char*)prop->value, "cpu")) {
filter->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
uint64_t reg;
fdt_get_address(prop->node->parent, prop->value, &reg);
filter->hart = reg;
} else if (!strcmp(prop->name, "status")) {
filter->status = (char*)prop->value;
} else if (!strcmp(prop->name, "mmu-type")) {
filter->mmu_type = (char*)prop->value;
}
}
static bool hart_filter_mask(const struct hart_filter *filter)
{
if (filter->mmu_type == NULL) return true;
if (strcmp(filter->status, "okay")) return true;
if (!strcmp(filter->mmu_type, "riscv,sv39")) return false;
if (!strcmp(filter->mmu_type, "riscv,sv48")) return false;
printm("hart_filter_mask saw unknown hart type: status=\"%s\", mmu_type=\"%s\"\n",
filter->status, filter->mmu_type);
return true;
}
static void hart_filter_done(const struct fdt_scan_node *node, void *extra)
{
struct hart_filter *filter = (struct hart_filter *)extra;
if (!filter->compat) return;
assert (filter->status);
assert (filter->hart >= 0);
if (hart_filter_mask(filter)) {
strcpy(filter->status, "masked");
uint32_t *len = (uint32_t*)filter->status;
len[-2] = bswap(strlen("masked")+1);
*filter->disabled_hart_mask |= (1 << filter->hart);
}
}
void filter_harts(uintptr_t fdt, long *disabled_hart_mask)
{
struct fdt_cb cb;
struct hart_filter filter;
memset(&cb, 0, sizeof(cb));
cb.open = hart_filter_open;
cb.prop = hart_filter_prop;
cb.done = hart_filter_done;
cb.extra = &filter;
filter.disabled_hart_mask = disabled_hart_mask;
*disabled_hart_mask = 0;
fdt_scan(fdt, &cb);
}
//////////////////////////////////////////// PRINT //////////////////////////////////////////////
#ifdef PK_PRINT_DEVICE_TREE
#define FDT_PRINT_MAX_DEPTH 32
struct fdt_print_info {
int depth;
const struct fdt_scan_node *stack[FDT_PRINT_MAX_DEPTH];
};
void fdt_print_printm(struct fdt_print_info *info, const char *format, ...)
{
va_list vl;
for (int i = 0; i < info->depth; ++i)
printm(" ");
va_start(vl, format);
vprintm(format, vl);
va_end(vl);
}
static void fdt_print_open(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
while (node->parent != NULL && info->stack[info->depth-1] != node->parent) {
info->depth--;
fdt_print_printm(info, "}\r\n");
}
fdt_print_printm(info, "%s {\r\n", node->name);
info->stack[info->depth] = node;
info->depth++;
}
static void fdt_print_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
int asstring = 1;
char *char_data = (char *)(prop->value);
fdt_print_printm(info, "%s", prop->name);
if (prop->len == 0) {
printm(";\r\n");
return;
} else {
printm(" = ");
}
/* It appears that dtc uses a hueristic to detect strings so I'm using a
* similar one here. */
for (int i = 0; i < prop->len; ++i) {
if (!isstring(char_data[i]))
asstring = 0;
if (i > 0 && char_data[i] == '\0' && char_data[i-1] == '\0')
asstring = 0;
}
if (asstring) {
for (size_t i = 0; i < prop->len; i += strlen(char_data + i) + 1) {
if (i != 0)
printm(", ");
printm("\"%s\"", char_data + i);
}
} else {
printm("<");
for (size_t i = 0; i < prop->len/4; ++i) {
if (i != 0)
printm(" ");
printm("0x%08x", bswap(prop->value[i]));
}
printm(">");
}
printm(";\r\n");
}
static void fdt_print_done(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
}
static int fdt_print_close(const struct fdt_scan_node *node, void *extra)
{
struct fdt_print_info *info = (struct fdt_print_info *)extra;
return 0;
}
void fdt_print(uintptr_t fdt)
{
struct fdt_print_info info;
struct fdt_cb cb;
info.depth = 0;
memset(&cb, 0, sizeof(cb));
cb.open = fdt_print_open;
cb.prop = fdt_print_prop;
cb.done = fdt_print_done;
cb.close = fdt_print_close;
cb.extra = &info;
fdt_scan(fdt, &cb);
while (info.depth > 0) {
info.depth--;
fdt_print_printm(&info, "}\r\n");
}
}
#endif

View File

@ -1,76 +0,0 @@
#ifndef FDT_H
#define FDT_H
#define FDT_MAGIC 0xd00dfeed
#define FDT_VERSION 17
struct fdt_header {
uint32_t magic;
uint32_t totalsize;
uint32_t off_dt_struct;
uint32_t off_dt_strings;
uint32_t off_mem_rsvmap;
uint32_t version;
uint32_t last_comp_version; /* <= 17 */
uint32_t boot_cpuid_phys;
uint32_t size_dt_strings;
uint32_t size_dt_struct;
};
#define FDT_BEGIN_NODE 1
#define FDT_END_NODE 2
#define FDT_PROP 3
#define FDT_NOP 4
#define FDT_END 9
struct fdt_scan_node {
const struct fdt_scan_node *parent;
const char *name;
int address_cells;
int size_cells;
};
struct fdt_scan_prop {
const struct fdt_scan_node *node;
const char *name;
uint32_t *value;
int len; // in bytes of value
};
struct fdt_cb {
void (*open)(const struct fdt_scan_node *node, void *extra);
void (*prop)(const struct fdt_scan_prop *prop, void *extra);
void (*done)(const struct fdt_scan_node *node, void *extra); // last property was seen
int (*close)(const struct fdt_scan_node *node, void *extra); // -1 => delete the node + children
void *extra;
};
// Scan the contents of FDT
void fdt_scan(uintptr_t fdt, const struct fdt_cb *cb);
uint32_t fdt_size(uintptr_t fdt);
// Extract fields
const uint32_t *fdt_get_address(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
const uint32_t *fdt_get_size(const struct fdt_scan_node *node, const uint32_t *base, uint64_t *value);
int fdt_string_list_index(const struct fdt_scan_prop *prop, const char *str); // -1 if not found
// Setup memory+clint+plic
void query_mem(uintptr_t fdt);
void query_harts(uintptr_t fdt);
void query_plic(uintptr_t fdt);
void query_clint(uintptr_t fdt);
// Remove information from FDT
void filter_harts(uintptr_t fdt, long *disabled_hart_mask);
void filter_plic(uintptr_t fdt);
void filter_compat(uintptr_t fdt, const char *compat);
// The hartids of available harts
extern uint64_t hart_mask;
#ifdef PK_PRINT_DEVICE_TREE
// Prints the device tree to the console as a DTS
void fdt_print(uintptr_t fdt);
#endif
#endif

View File

@ -1,58 +0,0 @@
#include <string.h>
#include "finisher.h"
#include "fdt.h"
volatile uint32_t* finisher;
void finisher_exit(uint16_t code)
{
if (!finisher) return;
if (code == 0) {
*finisher = FINISHER_PASS;
} else {
*finisher = code << 16 | FINISHER_FAIL;
}
}
struct finisher_scan
{
int compat;
uint64_t reg;
};
static void finisher_open(const struct fdt_scan_node *node, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void finisher_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,test0")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void finisher_done(const struct fdt_scan_node *node, void *extra)
{
struct finisher_scan *scan = (struct finisher_scan *)extra;
if (!scan->compat || !scan->reg || finisher) return;
finisher = (uint32_t*)(uintptr_t)scan->reg;
}
void query_finisher(uintptr_t fdt)
{
struct fdt_cb cb;
struct finisher_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = finisher_open;
cb.prop = finisher_prop;
cb.done = finisher_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -1,13 +0,0 @@
#ifndef _RISCV_FINISHER_H
#define _RISCV_FINISHER_H
#include <stdint.h>
#define FINISHER_REG_FINISH 0
#define FINISHER_FAIL 0x3333
#define FINISHER_PASS 0x5555
void finisher_exit(uint16_t code);
void query_finisher(uintptr_t fdt);
#endif

View File

@ -1,3 +0,0 @@
void __riscv_flush_icache(void) {
__asm__ volatile ("fence.i");
}

View File

@ -1,138 +0,0 @@
#include "htif.h"
#include "atomic.h"
#include "mtrap.h"
#include "fdt.h"
#include <string.h>
extern uint64_t __htif_base;
volatile uint64_t tohost __attribute__((section(".htif")));
volatile uint64_t fromhost __attribute__((section(".htif")));
volatile int htif_console_buf;
static spinlock_t htif_lock = SPINLOCK_INIT;
uintptr_t htif;
#define TOHOST(base_int) (uint64_t *)(base_int + TOHOST_OFFSET)
#define FROMHOST(base_int) (uint64_t *)(base_int + FROMHOST_OFFSET)
#define TOHOST_OFFSET ((uintptr_t)tohost - (uintptr_t)__htif_base)
#define FROMHOST_OFFSET ((uintptr_t)fromhost - (uintptr_t)__htif_base)
static void __check_fromhost()
{
uint64_t fh = fromhost;
if (!fh)
return;
fromhost = 0;
// this should be from the console
assert(FROMHOST_DEV(fh) == 1);
switch (FROMHOST_CMD(fh)) {
case 0:
htif_console_buf = 1 + (uint8_t)FROMHOST_DATA(fh);
break;
case 1:
break;
default:
assert(0);
}
}
static void __set_tohost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
{
while (tohost)
__check_fromhost();
tohost = TOHOST_CMD(dev, cmd, data);
}
int htif_console_getchar()
{
spinlock_lock(&htif_lock);
__check_fromhost();
int ch = htif_console_buf;
if (ch >= 0) {
htif_console_buf = -1;
__set_tohost(1, 0, 0);
}
spinlock_unlock(&htif_lock);
return ch - 1;
}
static void do_tohost_fromhost(uintptr_t dev, uintptr_t cmd, uintptr_t data)
{
spinlock_lock(&htif_lock);
__set_tohost(dev, cmd, data);
while (1) {
uint64_t fh = fromhost;
if (fh) {
if (FROMHOST_DEV(fh) == dev && FROMHOST_CMD(fh) == cmd) {
fromhost = 0;
break;
}
__check_fromhost();
}
}
spinlock_unlock(&htif_lock);
}
void htif_syscall(uintptr_t arg)
{
do_tohost_fromhost(0, 0, arg);
}
void htif_console_putchar(uint8_t ch)
{
spinlock_lock(&htif_lock);
__set_tohost(1, 1, ch);
spinlock_unlock(&htif_lock);
}
void htif_poweroff()
{
while (1) {
fromhost = 0;
tohost = 1;
}
}
struct htif_scan
{
int compat;
};
static void htif_open(const struct fdt_scan_node *node, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void htif_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ucb,htif0")) {
scan->compat = 1;
}
}
static void htif_done(const struct fdt_scan_node *node, void *extra)
{
struct htif_scan *scan = (struct htif_scan *)extra;
if (!scan->compat) return;
htif = 1;
}
void query_htif(uintptr_t fdt)
{
struct fdt_cb cb;
struct htif_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = htif_open;
cb.prop = htif_prop;
cb.done = htif_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -1,25 +0,0 @@
#ifndef _RISCV_HTIF_H
#define _RISCV_HTIF_H
#include <stdint.h>
#if __riscv_xlen == 64
# define TOHOST_CMD(dev, cmd, payload) \
(((uint64_t)(dev) << 56) | ((uint64_t)(cmd) << 48) | (uint64_t)(payload))
#else
# define TOHOST_CMD(dev, cmd, payload) ({ \
if ((dev) || (cmd)) __builtin_trap(); \
(payload); })
#endif
#define FROMHOST_DEV(fromhost_value) ((uint64_t)(fromhost_value) >> 56)
#define FROMHOST_CMD(fromhost_value) ((uint64_t)(fromhost_value) << 8 >> 56)
#define FROMHOST_DATA(fromhost_value) ((uint64_t)(fromhost_value) << 16 >> 16)
extern uintptr_t htif;
void query_htif(uintptr_t dtb);
void htif_console_putchar(uint8_t);
int htif_console_getchar();
void htif_poweroff() __attribute__((noreturn));
void htif_syscall(uintptr_t);
#endif

View File

@ -1,4 +0,0 @@
AC_ARG_ENABLE([fp-emulation], AS_HELP_STRING([--disable-fp-emulation], [Disable floating-point emulation]))
AS_IF([test "x$enable_fp_emulation" != "xno"], [
AC_DEFINE([PK_ENABLE_FP_EMULATION],,[Define if floating-point emulation is enabled])
])

View File

@ -1,30 +0,0 @@
machine_hdrs = \
atomic.h \
bits.h \
fdt.h \
emulation.h \
encoding.h \
htif.h \
mcall.h \
mtrap.h \
uart.h \
uart16550.h \
finisher.h \
unprivileged_memory.h \
vm.h \
machine_c_srcs = \
fdt.c \
mtrap.c \
minit.c \
htif.c \
emulation.c \
muldiv_emulation.c \
uart.c \
uart16550.c \
finisher.c \
misaligned_ldst.c \
flush_icache.c \
machine_asm_srcs = \
mentry.S \

View File

@ -1,14 +0,0 @@
#ifndef _RISCV_SBI_H
#define _RISCV_SBI_H
#define SBI_SET_TIMER 0
#define SBI_CONSOLE_PUTCHAR 1
#define SBI_CONSOLE_GETCHAR 2
#define SBI_CLEAR_IPI 3
#define SBI_SEND_IPI 4
#define SBI_REMOTE_FENCE_I 5
#define SBI_REMOTE_SFENCE_VMA 6
#define SBI_REMOTE_SFENCE_VMA_ASID 7
#define SBI_SHUTDOWN 8
#endif

View File

@ -1,295 +0,0 @@
// See LICENSE for license details.
#include "mtrap.h"
#include "bits.h"
.data
.align 6
trap_table:
#define BAD_TRAP_VECTOR 0
.word bad_trap
.word pmp_trap
.word illegal_insn_trap
.word bad_trap
.word misaligned_load_trap
.word pmp_trap
.word misaligned_store_trap
.word pmp_trap
.word bad_trap
.word mcall_trap
.word bad_trap
.word bad_trap
.word bad_trap
#define TRAP_FROM_MACHINE_MODE_VECTOR 13
.word __trap_from_machine_mode
.word bad_trap
.word bad_trap
.option norvc
.section .text.init,"ax",@progbits
.globl reset_vector
reset_vector:
j do_reset
trap_vector:
csrrw sp, mscratch, sp
beqz sp, .Ltrap_from_machine_mode
STORE a0, 10*REGBYTES(sp)
STORE a1, 11*REGBYTES(sp)
csrr a1, mcause
bgez a1, .Lhandle_trap_in_machine_mode
# This is an interrupt. Discard the mcause MSB and decode the rest.
sll a1, a1, 1
# Is it a machine timer interrupt?
li a0, IRQ_M_TIMER * 2
bne a0, a1, 1f
# Yes. Simply clear MSIE and raise SSIP.
li a0, MIP_MTIP
csrc mie, a0
li a0, MIP_STIP
csrs mip, a0
.Lmret:
# Go back whence we came.
LOAD a0, 10*REGBYTES(sp)
LOAD a1, 11*REGBYTES(sp)
csrrw sp, mscratch, sp
mret
1:
# Is it an IPI?
li a0, IRQ_M_SOFT * 2
bne a0, a1, .Lbad_trap
# Yes. First, clear the MIPI bit.
LOAD a0, MENTRY_IPI_OFFSET(sp)
sw x0, (a0)
fence
# Now, decode the cause(s).
#ifdef __riscv_atomic
addi a0, sp, MENTRY_IPI_PENDING_OFFSET
amoswap.w a0, x0, (a0)
#else
lw a0, MENTRY_IPI_PENDING_OFFSET(a0)
sw x0, MENTRY_IPI_PENDING_OFFSET(a0)
#endif
and a1, a0, IPI_SOFT
beqz a1, 1f
csrs mip, MIP_SSIP
1:
andi a1, a0, IPI_FENCE_I
beqz a1, 1f
fence.i
1:
andi a1, a0, IPI_SFENCE_VMA
beqz a1, 1f
sfence.vma
1:
j .Lmret
.Lhandle_trap_in_machine_mode:
# Preserve the registers. Compute the address of the trap handler.
STORE ra, 1*REGBYTES(sp)
STORE gp, 3*REGBYTES(sp)
STORE tp, 4*REGBYTES(sp)
STORE t0, 5*REGBYTES(sp)
1:auipc t0, %pcrel_hi(trap_table) # t0 <- %hi(trap_table)
STORE t1, 6*REGBYTES(sp)
sll t1, a1, 2 # t1 <- mcause << 2
STORE t2, 7*REGBYTES(sp)
add t1, t0, t1 # t1 <- %hi(trap_table)[mcause]
STORE s0, 8*REGBYTES(sp)
LWU t1, %pcrel_lo(1b)(t1) # t1 <- trap_table[mcause]
STORE s1, 9*REGBYTES(sp)
mv a0, sp # a0 <- regs
STORE a2,12*REGBYTES(sp)
csrr a2, mepc # a2 <- mepc
STORE a3,13*REGBYTES(sp)
csrrw t0, mscratch, x0 # t0 <- user sp
STORE a4,14*REGBYTES(sp)
STORE a5,15*REGBYTES(sp)
STORE a6,16*REGBYTES(sp)
STORE a7,17*REGBYTES(sp)
STORE s2,18*REGBYTES(sp)
STORE s3,19*REGBYTES(sp)
STORE s4,20*REGBYTES(sp)
STORE s5,21*REGBYTES(sp)
STORE s6,22*REGBYTES(sp)
STORE s7,23*REGBYTES(sp)
STORE s8,24*REGBYTES(sp)
STORE s9,25*REGBYTES(sp)
STORE s10,26*REGBYTES(sp)
STORE s11,27*REGBYTES(sp)
STORE t3,28*REGBYTES(sp)
STORE t4,29*REGBYTES(sp)
STORE t5,30*REGBYTES(sp)
STORE t6,31*REGBYTES(sp)
STORE t0, 2*REGBYTES(sp) # sp
#ifndef __riscv_flen
lw tp, (sp) # Move the emulated FCSR from x0's save slot into tp.
#endif
STORE x0, (sp) # Zero x0's save slot.
# Invoke the handler.
jalr t1
#ifndef __riscv_flen
sw tp, (sp) # Move the emulated FCSR from tp into x0's save slot.
#endif
restore_mscratch:
# Restore mscratch, so future traps will know they didn't come from M-mode.
csrw mscratch, sp
restore_regs:
# Restore all of the registers.
LOAD ra, 1*REGBYTES(sp)
LOAD gp, 3*REGBYTES(sp)
LOAD tp, 4*REGBYTES(sp)
LOAD t0, 5*REGBYTES(sp)
LOAD t1, 6*REGBYTES(sp)
LOAD t2, 7*REGBYTES(sp)
LOAD s0, 8*REGBYTES(sp)
LOAD s1, 9*REGBYTES(sp)
LOAD a0,10*REGBYTES(sp)
LOAD a1,11*REGBYTES(sp)
LOAD a2,12*REGBYTES(sp)
LOAD a3,13*REGBYTES(sp)
LOAD a4,14*REGBYTES(sp)
LOAD a5,15*REGBYTES(sp)
LOAD a6,16*REGBYTES(sp)
LOAD a7,17*REGBYTES(sp)
LOAD s2,18*REGBYTES(sp)
LOAD s3,19*REGBYTES(sp)
LOAD s4,20*REGBYTES(sp)
LOAD s5,21*REGBYTES(sp)
LOAD s6,22*REGBYTES(sp)
LOAD s7,23*REGBYTES(sp)
LOAD s8,24*REGBYTES(sp)
LOAD s9,25*REGBYTES(sp)
LOAD s10,26*REGBYTES(sp)
LOAD s11,27*REGBYTES(sp)
LOAD t3,28*REGBYTES(sp)
LOAD t4,29*REGBYTES(sp)
LOAD t5,30*REGBYTES(sp)
LOAD t6,31*REGBYTES(sp)
LOAD sp, 2*REGBYTES(sp)
mret
.Ltrap_from_machine_mode:
csrr sp, mscratch
addi sp, sp, -INTEGER_CONTEXT_SIZE
STORE a0,10*REGBYTES(sp)
STORE a1,11*REGBYTES(sp)
li a1, TRAP_FROM_MACHINE_MODE_VECTOR
j .Lhandle_trap_in_machine_mode
.Lbad_trap:
li a1, BAD_TRAP_VECTOR
j .Lhandle_trap_in_machine_mode
.globl __redirect_trap
__redirect_trap:
# reset sp to top of M-mode stack
li t0, MACHINE_STACK_SIZE
add sp, sp, t0
neg t0, t0
and sp, sp, t0
addi sp, sp, -MENTRY_FRAME_SIZE
j restore_mscratch
__trap_from_machine_mode:
jal trap_from_machine_mode
j restore_regs
do_reset:
li x1, 0
li x2, 0
li x3, 0
li x4, 0
li x5, 0
li x6, 0
li x7, 0
li x8, 0
li x9, 0
// save a0 and a1; arguments from previous boot loader stage:
// li x10, 0
// li x11, 0
li x12, 0
li x13, 0
li x14, 0
li x15, 0
li x16, 0
li x17, 0
li x18, 0
li x19, 0
li x20, 0
li x21, 0
li x22, 0
li x23, 0
li x24, 0
li x25, 0
li x26, 0
li x27, 0
li x28, 0
li x29, 0
li x30, 0
li x31, 0
csrw mscratch, x0
# write mtvec and make sure it sticks
la t0, trap_vector
csrw mtvec, t0
csrr t1, mtvec
1:bne t0, t1, 1b
la sp, stacks + RISCV_PGSIZE - MENTRY_FRAME_SIZE
csrr a3, mhartid
slli a2, a3, RISCV_PGSHIFT
add sp, sp, a2
# Boot on the first hart
beqz a3, init_first_hart
# set MSIE bit to receive IPI
li a2, MIP_MSIP
csrw mie, a2
.LmultiHart:
#if MAX_HARTS > 1
# wait for an IPI to signal that it's safe to boot
wfi
# masked harts never start
la a4, disabled_hart_mask
LOAD a4, 0(a4)
srl a4, a4, a3
andi a4, a4, 1
bnez a4, .LmultiHart
# only start if mip is set
csrr a2, mip
andi a2, a2, MIP_MSIP
beqz a2, .LmultiHart
# make sure our hart id is within a valid range
fence
li a2, MAX_HARTS
bltu a3, a2, init_other_hart
#endif
wfi
j .LmultiHart
.bss
.align RISCV_PGSHIFT
stacks:
.skip RISCV_PGSIZE * MAX_HARTS

View File

@ -1,200 +0,0 @@
#include "mtrap.h"
#include "atomic.h"
#include "vm.h"
//#include "fp_emulation.h"
#include "bits.h"
#include "fdt.h"
#include "uart.h"
#include "uart16550.h"
#include "finisher.h"
#include "disabled_hart_mask.h"
#include "htif.h"
#include <string.h>
#include <limits.h>
pte_t* root_page_table;
uintptr_t mem_size;
volatile uint64_t* mtime;
volatile uint32_t* plic_priorities;
size_t plic_ndevs;
static void mstatus_init()
{
// Enable FPU
if (supports_extension('D') || supports_extension('F'))
write_csr(mstatus, MSTATUS_FS);
// Enable user/supervisor use of perf counters
if (supports_extension('S'))
write_csr(scounteren, -1);
write_csr(mcounteren, -1);
// Enable software interrupts
write_csr(mie, MIP_MSIP);
// Disable paging
if (supports_extension('S'))
write_csr(sptbr, 0);
}
// send S-mode interrupts and most exceptions straight to S-mode
static void delegate_traps()
{
if (!supports_extension('S'))
return;
uintptr_t interrupts = MIP_SSIP | MIP_STIP | MIP_SEIP;
uintptr_t exceptions =
(1U << CAUSE_MISALIGNED_FETCH) |
(1U << CAUSE_FETCH_PAGE_FAULT) |
(1U << CAUSE_BREAKPOINT) |
(1U << CAUSE_LOAD_PAGE_FAULT) |
(1U << CAUSE_STORE_PAGE_FAULT) |
(1U << CAUSE_USER_ECALL);
write_csr(mideleg, interrupts);
write_csr(medeleg, exceptions);
assert(read_csr(mideleg) == interrupts);
assert(read_csr(medeleg) == exceptions);
}
static void fp_init()
{
if (!supports_extension('D') && !supports_extension('F'))
return;
assert(read_csr(mstatus) & MSTATUS_FS);
#ifdef __riscv_flen
// for (int i = 0; i < 32; i++)
// init_fp_reg(i);
// write_csr(fcsr, 0);
#else
uintptr_t fd_mask = (1 << ('F' - 'A')) | (1 << ('D' - 'A'));
clear_csr(misa, fd_mask);
assert(!(read_csr(misa) & fd_mask));
#endif
}
hls_t* hls_init(uintptr_t id)
{
hls_t* hls = OTHER_HLS(id);
memset(hls, 0, sizeof(*hls));
return hls;
}
static void memory_init()
{
mem_size = mem_size / MEGAPAGE_SIZE * MEGAPAGE_SIZE;
}
static void hart_init()
{
mstatus_init();
// fp_init();
delegate_traps();
}
static void plic_init()
{
for (size_t i = 1; i <= plic_ndevs; i++)
plic_priorities[i] = 1;
}
static void prci_test()
{
assert(!(read_csr(mip) & MIP_MSIP));
*HLS()->ipi = 1;
assert(read_csr(mip) & MIP_MSIP);
*HLS()->ipi = 0;
assert(!(read_csr(mip) & MIP_MTIP));
*HLS()->timecmp = 0;
assert(read_csr(mip) & MIP_MTIP);
*HLS()->timecmp = -1ULL;
}
static void hart_plic_init()
{
// clear pending interrupts
*HLS()->ipi = 0;
*HLS()->timecmp = -1ULL;
write_csr(mip, 0);
if (!plic_ndevs)
return;
size_t ie_words = plic_ndevs / sizeof(uintptr_t) + 1;
for (size_t i = 0; i < ie_words; i++)
HLS()->plic_s_ie[i] = ULONG_MAX;
*HLS()->plic_m_thresh = 1;
*HLS()->plic_s_thresh = 0;
}
static void wake_harts()
{
for (int hart = 0; hart < MAX_HARTS; ++hart)
if ((((~disabled_hart_mask & hart_mask) >> hart) & 1))
*OTHER_HLS(hart)->ipi = 1; // wakeup the hart
}
void init_first_hart(uintptr_t hartid, uintptr_t dtb)
{
// Confirm console as early as possible
query_uart(dtb);
query_uart16550(dtb);
query_htif(dtb);
hart_init();
hls_init(0); // this might get called again from parse_config_string
// Find the power button early as well so die() works
query_finisher(dtb);
query_mem(dtb);
query_harts(dtb);
query_clint(dtb);
query_plic(dtb);
wake_harts();
plic_init();
hart_plic_init();
//prci_test();
memory_init();
boot_loader(dtb);
}
void init_other_hart(uintptr_t hartid, uintptr_t dtb)
{
hart_init();
hart_plic_init();
boot_other_hart(dtb);
}
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2)
{
// Set up a PMP to permit access to all of memory.
// Ignore the illegal-instruction trap if PMPs aren't supported.
uintptr_t pmpc = PMP_NAPOT | PMP_R | PMP_W | PMP_X;
asm volatile ("la t0, 1f\n\t"
"csrrw t0, mtvec, t0\n\t"
"csrw pmpaddr0, %1\n\t"
"csrw pmpcfg0, %0\n\t"
".align 2\n\t"
"1: csrw mtvec, t0"
: : "r" (pmpc), "r" (-1UL) : "t0");
uintptr_t mstatus = read_csr(mstatus);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPP, PRV_S);
mstatus = INSERT_FIELD(mstatus, MSTATUS_MPIE, 0);
write_csr(mstatus, mstatus);
write_csr(mscratch, MACHINE_STACK_TOP() - MENTRY_FRAME_SIZE);
write_csr(mepc, fn);
register uintptr_t a0 asm ("a0") = arg0;
register uintptr_t a1 asm ("a1") = arg1;
register uintptr_t a2 asm ("a2") = arg2;
asm volatile ("mret" : : "r" (a0), "r" (a1), "r" (a2));
__builtin_unreachable();
}

View File

@ -1,143 +0,0 @@
#include "emulation.h"
//#include "fp_emulation.h"
#include "unprivileged_memory.h"
#include "mtrap.h"
#include "config.h"
//#include "pk.h"
union byte_array {
uint8_t bytes[8];
uintptr_t intx;
uint64_t int64;
};
static inline int insn_len(long insn)
{
return (insn & 0x3) < 0x3 ? 2 : 4;
}
void misaligned_load_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
union byte_array val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
uintptr_t npc = mepc + insn_len(insn);
uintptr_t addr = read_csr(mbadaddr);
int shift = 0, fp = 0, len;
if ((insn & MASK_LW) == MATCH_LW)
len = 4, shift = 8*(sizeof(uintptr_t) - len);
#if __riscv_xlen == 64
else if ((insn & MASK_LD) == MATCH_LD)
len = 8, shift = 8*(sizeof(uintptr_t) - len);
else if ((insn & MASK_LWU) == MATCH_LWU)
len = 4;
#endif
#ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_FLD) == MATCH_FLD)
fp = 1, len = 8;
else if ((insn & MASK_FLW) == MATCH_FLW)
fp = 1, len = 4;
#endif
else if ((insn & MASK_LH) == MATCH_LH)
len = 2, shift = 8*(sizeof(uintptr_t) - len);
else if ((insn & MASK_LHU) == MATCH_LHU)
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
else if ((insn & MASK_C_LD) == MATCH_C_LD)
len = 8, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_LDSP) == MATCH_C_LDSP && ((insn >> SH_RD) & 0x1f))
len = 8, shift = 8*(sizeof(uintptr_t) - len);
# endif
else if ((insn & MASK_C_LW) == MATCH_C_LW)
len = 4, shift = 8*(sizeof(uintptr_t) - len), insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_LWSP) == MATCH_C_LWSP && ((insn >> SH_RD) & 0x1f))
len = 4, shift = 8*(sizeof(uintptr_t) - len);
# ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_C_FLD) == MATCH_C_FLD)
fp = 1, len = 8, insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_FLDSP) == MATCH_C_FLDSP)
fp = 1, len = 8;
# if __riscv_xlen == 32
else if ((insn & MASK_C_FLW) == MATCH_C_FLW)
fp = 1, len = 4, insn = RVC_RS2S(insn) << SH_RD;
else if ((insn & MASK_C_FLWSP) == MATCH_C_FLWSP)
fp = 1, len = 4;
# endif
# endif
#endif
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
val.int64 = 0;
for (intptr_t i = 0; i < len; i++)
val.bytes[i] = load_uint8_t((void *)(addr + i), mepc);
if (!fp)
SET_RD(insn, regs, (intptr_t)val.intx << shift >> shift);
#ifdef PK_ENABLE_FP_EMULATION
else if (len == 8)
SET_F64_RD(insn, regs, val.int64);
else
SET_F32_RD(insn, regs, val.intx);
#endif
write_csr(mepc, npc);
}
void misaligned_store_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
union byte_array val;
uintptr_t mstatus;
insn_t insn = get_insn(mepc, &mstatus);
uintptr_t npc = mepc + insn_len(insn);
int len;
val.intx = GET_RS2(insn, regs);
if ((insn & MASK_SW) == MATCH_SW)
len = 4;
#if __riscv_xlen == 64
else if ((insn & MASK_SD) == MATCH_SD)
len = 8;
#endif
#ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_FSD) == MATCH_FSD)
len = 8, val.int64 = GET_F64_RS2(insn, regs);
else if ((insn & MASK_FSW) == MATCH_FSW)
len = 4, val.intx = GET_F32_RS2(insn, regs);
#endif
else if ((insn & MASK_SH) == MATCH_SH)
len = 2;
#ifdef __riscv_compressed
# if __riscv_xlen >= 64
else if ((insn & MASK_C_SD) == MATCH_C_SD)
len = 8, val.intx = GET_RS2S(insn, regs);
else if ((insn & MASK_C_SDSP) == MATCH_C_SDSP && ((insn >> SH_RD) & 0x1f))
len = 8, val.intx = GET_RS2C(insn, regs);
# endif
else if ((insn & MASK_C_SW) == MATCH_C_SW)
len = 4, val.intx = GET_RS2S(insn, regs);
else if ((insn & MASK_C_SWSP) == MATCH_C_SWSP && ((insn >> SH_RD) & 0x1f))
len = 4, val.intx = GET_RS2C(insn, regs);
# ifdef PK_ENABLE_FP_EMULATION
else if ((insn & MASK_C_FSD) == MATCH_C_FSD)
len = 8, val.int64 = GET_F64_RS2S(insn, regs);
else if ((insn & MASK_C_FSDSP) == MATCH_C_FSDSP)
len = 8, val.int64 = GET_F64_RS2C(insn, regs);
# if __riscv_xlen == 32
else if ((insn & MASK_C_FSW) == MATCH_C_FSW)
len = 4, val.intx = GET_F32_RS2S(insn, regs);
else if ((insn & MASK_C_FSWSP) == MATCH_C_FSWSP)
len = 4, val.intx = GET_F32_RS2C(insn, regs);
# endif
# endif
#endif
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
uintptr_t addr = read_csr(mbadaddr);
for (int i = 0; i < len; i++)
store_uint8_t((void *)(addr + i), val.bytes[i], mepc);
write_csr(mepc, npc);
}

View File

@ -1,235 +0,0 @@
#include "mtrap.h"
#include "mcall.h"
#include "htif.h"
#include "atomic.h"
#include "bits.h"
#include "vm.h"
#include "uart.h"
#include "uart16550.h"
#include "finisher.h"
#include "fdt.h"
#include "unprivileged_memory.h"
#include "disabled_hart_mask.h"
#include <errno.h>
#include <stdarg.h>
#include <stdio.h>
void __attribute__((noreturn)) bad_trap(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
die("machine mode: unhandlable trap %d @ %p", read_csr(mcause), mepc);
}
static uintptr_t mcall_console_putchar(uint8_t ch)
{
if (uart) {
uart_putchar(ch);
} else if (uart16550) {
uart16550_putchar(ch);
} else if (htif) {
htif_console_putchar(ch);
}
return 0;
}
void poweroff(uint16_t code)
{
printm("Power off\n");
finisher_exit(code);
if (htif) {
htif_poweroff();
} else {
while (1) { asm volatile ("#noop\n"); }
}
}
void putstring(const char* s)
{
while (*s)
mcall_console_putchar(*s++);
}
void vprintm(const char* s, va_list vl)
{
char buf[256];
vsnprintf(buf, sizeof buf, s, vl);
putstring(buf);
}
void printm(const char* s, ...)
{
va_list vl;
va_start(vl, s);
vprintm(s, vl);
va_end(vl);
}
static void send_ipi(uintptr_t recipient, int event)
{
if (((disabled_hart_mask >> recipient) & 1)) return;
atomic_or(&OTHER_HLS(recipient)->mipi_pending, event);
mb();
*OTHER_HLS(recipient)->ipi = 1;
}
static uintptr_t mcall_console_getchar()
{
if (uart) {
return uart_getchar();
} else if (uart16550) {
return uart16550_getchar();
} else if (htif) {
return htif_console_getchar();
} else {
return '\0';
}
}
static uintptr_t mcall_clear_ipi()
{
return clear_csr(mip, MIP_SSIP) & MIP_SSIP;
}
static uintptr_t mcall_shutdown()
{
poweroff(0);
}
static uintptr_t mcall_set_timer(uint64_t when)
{
*HLS()->timecmp = when;
clear_csr(mip, MIP_STIP);
set_csr(mie, MIP_MTIP);
return 0;
}
static void send_ipi_many(uintptr_t* pmask, int event)
{
_Static_assert(MAX_HARTS <= 8 * sizeof(*pmask), "# harts > uintptr_t bits");
uintptr_t mask = hart_mask;
if (pmask)
mask &= load_uintptr_t(pmask, read_csr(mepc));
// send IPIs to everyone
for (uintptr_t i = 0, m = mask; m; i++, m >>= 1)
if (m & 1)
send_ipi(i, event);
if (event == IPI_SOFT)
return;
// wait until all events have been handled.
// prevent deadlock by consuming incoming IPIs.
uint32_t incoming_ipi = 0;
for (uintptr_t i = 0, m = mask; m; i++, m >>= 1)
if (m & 1)
while (*OTHER_HLS(i)->ipi)
incoming_ipi |= atomic_swap(HLS()->ipi, 0);
// if we got an IPI, restore it; it will be taken after returning
if (incoming_ipi) {
*HLS()->ipi = incoming_ipi;
mb();
}
}
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr);
void mcall_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
write_csr(mepc, mepc + 4);
uintptr_t n = regs[17], arg0 = regs[10], arg1 = regs[11], retval, ipi_type;
switch (n)
{
case SBI_CONSOLE_PUTCHAR:
retval = mcall_console_putchar(arg0);
break;
case SBI_CONSOLE_GETCHAR:
retval = mcall_console_getchar();
break;
case SBI_SEND_IPI:
ipi_type = IPI_SOFT;
goto send_ipi;
case SBI_REMOTE_SFENCE_VMA:
case SBI_REMOTE_SFENCE_VMA_ASID:
ipi_type = IPI_SFENCE_VMA;
goto send_ipi;
case SBI_REMOTE_FENCE_I:
ipi_type = IPI_FENCE_I;
send_ipi:
send_ipi_many((uintptr_t*)arg0, ipi_type);
retval = 0;
break;
case SBI_CLEAR_IPI:
retval = mcall_clear_ipi();
break;
case SBI_SHUTDOWN:
retval = mcall_shutdown();
break;
case SBI_SET_TIMER:
#if __riscv_xlen == 32
retval = mcall_set_timer(arg0 + ((uint64_t)arg1 << 32));
#else
retval = mcall_set_timer(arg0);
#endif
break;
default:
redirect_trap(read_csr(mepc), read_csr(mstatus), read_csr(mbadaddr));
retval = -ENOSYS;
break;
}
regs[10] = retval;
}
void redirect_trap(uintptr_t epc, uintptr_t mstatus, uintptr_t badaddr)
{
write_csr(sbadaddr, badaddr);
write_csr(sepc, epc);
write_csr(scause, read_csr(mcause));
write_csr(mepc, read_csr(stvec));
uintptr_t new_mstatus = mstatus & ~(MSTATUS_SPP | MSTATUS_SPIE | MSTATUS_SIE);
uintptr_t mpp_s = MSTATUS_MPP & (MSTATUS_MPP >> 1);
new_mstatus |= (mstatus * (MSTATUS_SPIE / MSTATUS_SIE)) & MSTATUS_SPIE;
new_mstatus |= (mstatus / (mpp_s / MSTATUS_SPP)) & MSTATUS_SPP;
new_mstatus |= mpp_s;
write_csr(mstatus, new_mstatus);
extern void __redirect_trap();
return __redirect_trap();
}
void pmp_trap(uintptr_t* regs, uintptr_t mcause, uintptr_t mepc)
{
redirect_trap(mepc, read_csr(mstatus), read_csr(mbadaddr));
}
static void machine_page_fault(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
// MPRV=1 iff this trap occurred while emulating an instruction on behalf
// of a lower privilege level. In that case, a2=epc and a3=mstatus.
if (read_csr(mstatus) & MSTATUS_MPRV) {
return redirect_trap(regs[12], regs[13], read_csr(mbadaddr));
}
bad_trap(regs, dummy, mepc);
}
void trap_from_machine_mode(uintptr_t* regs, uintptr_t dummy, uintptr_t mepc)
{
uintptr_t mcause = read_csr(mcause);
switch (mcause)
{
case CAUSE_LOAD_PAGE_FAULT:
case CAUSE_STORE_PAGE_FAULT:
case CAUSE_FETCH_ACCESS:
case CAUSE_LOAD_ACCESS:
case CAUSE_STORE_ACCESS:
return machine_page_fault(regs, dummy, mepc);
default:
bad_trap(regs, dummy, mepc);
}
}

View File

@ -1,96 +0,0 @@
#ifndef _RISCV_MTRAP_H
#define _RISCV_MTRAP_H
#include "encoding.h"
#ifdef __riscv_atomic
# define MAX_HARTS 8 // arbitrary
#else
# define MAX_HARTS 1
#endif
#ifndef __ASSEMBLER__
#include <stdint.h>
#include <stddef.h>
#include <stdarg.h>
#define read_const_csr(reg) ({ unsigned long __tmp; \
asm ("csrr %0, " #reg : "=r"(__tmp)); \
__tmp; })
static inline int supports_extension(char ext)
{
return read_const_csr(misa) & (1 << (ext - 'A'));
}
static inline int xlen()
{
return read_const_csr(misa) < 0 ? 64 : 32;
}
extern uintptr_t mem_size;
extern volatile uint64_t* mtime;
extern volatile uint32_t* plic_priorities;
extern size_t plic_ndevs;
typedef struct {
volatile uint32_t* ipi;
volatile int mipi_pending;
volatile uint64_t* timecmp;
volatile uint32_t* plic_m_thresh;
volatile uintptr_t* plic_m_ie;
volatile uint32_t* plic_s_thresh;
volatile uintptr_t* plic_s_ie;
} hls_t;
#define MACHINE_STACK_TOP() ({ \
register uintptr_t sp asm ("sp"); \
(void*)((sp + RISCV_PGSIZE) & -RISCV_PGSIZE); })
// hart-local storage, at top of stack
#define HLS() ((hls_t*)(MACHINE_STACK_TOP() - HLS_SIZE))
#define OTHER_HLS(id) ((hls_t*)((void*)HLS() + RISCV_PGSIZE * ((id) - read_const_csr(mhartid))))
hls_t* hls_init(uintptr_t hart_id);
void parse_config_string();
void poweroff(uint16_t code) __attribute((noreturn));
void printm(const char* s, ...);
void vprintm(const char *s, va_list args);
void putstring(const char* s);
#define assert(x) ({ if (!(x)) die("assertion failed: %s", #x); })
#define die(str, ...) ({ printm("%s:%d: " str "\n", __FILE__, __LINE__, ##__VA_ARGS__); poweroff(-1); })
void enter_supervisor_mode(void (*fn)(uintptr_t), uintptr_t arg0, uintptr_t arg1, uintptr_t arg2)
__attribute__((noreturn));
void boot_loader(uintptr_t dtb);
void boot_other_hart(uintptr_t dtb);
static inline void wfi()
{
asm volatile ("wfi" ::: "memory");
}
#endif // !__ASSEMBLER__
#define IPI_SOFT 0x1
#define IPI_FENCE_I 0x2
#define IPI_SFENCE_VMA 0x4
#define MACHINE_STACK_SIZE RISCV_PGSIZE
#define MENTRY_HLS_OFFSET (INTEGER_CONTEXT_SIZE + SOFT_FLOAT_CONTEXT_SIZE)
#define MENTRY_FRAME_SIZE (MENTRY_HLS_OFFSET + HLS_SIZE)
#define MENTRY_IPI_OFFSET (MENTRY_HLS_OFFSET)
#define MENTRY_IPI_PENDING_OFFSET (MENTRY_HLS_OFFSET + REGBYTES)
#ifdef __riscv_flen
# define SOFT_FLOAT_CONTEXT_SIZE 0
#else
# define SOFT_FLOAT_CONTEXT_SIZE (8 * 32)
#endif
#define HLS_SIZE 64
#define INTEGER_CONTEXT_SIZE (32 * REGBYTES)
#endif

View File

@ -1,64 +0,0 @@
#include "emulation.h"
#ifndef __riscv_muldiv
#if __riscv_xlen == 64
typedef __int128 double_int;
#else
typedef int64_t double_int;
#endif
// These routines rely on the compiler to turn these operations into libcalls
// when not natively supported. So work on making those go fast.
DECLARE_EMULATION_FUNC(emulate_mul_div)
{
uintptr_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs), val;
if ((insn & MASK_MUL) == MATCH_MUL)
val = rs1 * rs2;
else if ((insn & MASK_DIV) == MATCH_DIV)
val = (intptr_t)rs1 / (intptr_t)rs2;
else if ((insn & MASK_DIVU) == MATCH_DIVU)
val = rs1 / rs2;
else if ((insn & MASK_REM) == MATCH_REM)
val = (intptr_t)rs1 % (intptr_t)rs2;
else if ((insn & MASK_REMU) == MATCH_REMU)
val = rs1 % rs2;
else if ((insn & MASK_MULH) == MATCH_MULH)
val = ((double_int)(intptr_t)rs1 * (double_int)(intptr_t)rs2) >> (8 * sizeof(rs1));
else if ((insn & MASK_MULHU) == MATCH_MULHU)
val = ((double_int)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
else if ((insn & MASK_MULHSU) == MATCH_MULHSU)
val = ((double_int)(intptr_t)rs1 * (double_int)rs2) >> (8 * sizeof(rs1));
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, val);
}
#if __riscv_xlen == 64
DECLARE_EMULATION_FUNC(emulate_mul_div32)
{
uint32_t rs1 = GET_RS1(insn, regs), rs2 = GET_RS2(insn, regs);
int32_t val;
if ((insn & MASK_MULW) == MATCH_MULW)
val = rs1 * rs2;
else if ((insn & MASK_DIVW) == MATCH_DIVW)
val = (int32_t)rs1 / (int32_t)rs2;
else if ((insn & MASK_DIVUW) == MATCH_DIVUW)
val = rs1 / rs2;
else if ((insn & MASK_REMW) == MATCH_REMW)
val = (int32_t)rs1 % (int32_t)rs2;
else if ((insn & MASK_REMUW) == MATCH_REMUW)
val = rs1 % rs2;
else
return truly_illegal_insn(regs, mcause, mepc, mstatus, insn);
SET_RD(insn, regs, val);
}
#endif
#endif

View File

@ -1,76 +0,0 @@
#include <string.h>
#include "uart.h"
#include "fdt.h"
volatile uint32_t* uart;
void uart_putchar(uint8_t ch)
{
#ifdef __riscv_atomic
int32_t r;
do {
__asm__ __volatile__ (
"amoor.w %0, %2, %1\n"
: "=r" (r), "+A" (uart[UART_REG_TXFIFO])
: "r" (ch));
} while (r < 0);
#else
volatile uint32_t *tx = uart + UART_REG_TXFIFO;
while ((int32_t)(*tx) < 0);
*tx = ch;
#endif
}
int uart_getchar()
{
int32_t ch = uart[UART_REG_RXFIFO];
if (ch < 0) return -1;
return ch;
}
struct uart_scan
{
int compat;
uint64_t reg;
};
static void uart_open(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void uart_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "sifive,uart0")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void uart_done(const struct fdt_scan_node *node, void *extra)
{
struct uart_scan *scan = (struct uart_scan *)extra;
if (!scan->compat || !scan->reg || uart) return;
// Enable Rx/Tx channels
uart = (void*)(uintptr_t)scan->reg;
uart[UART_REG_TXCTRL] = UART_TXEN;
uart[UART_REG_RXCTRL] = UART_RXEN;
}
void query_uart(uintptr_t fdt)
{
struct fdt_cb cb;
struct uart_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = uart_open;
cb.prop = uart_prop;
cb.done = uart_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -1,21 +0,0 @@
#ifndef _RISCV_UART_H
#define _RISCV_UART_H
#include <stdint.h>
extern volatile uint32_t* uart;
#define UART_REG_TXFIFO 0
#define UART_REG_RXFIFO 1
#define UART_REG_TXCTRL 2
#define UART_REG_RXCTRL 3
#define UART_REG_DIV 4
#define UART_TXEN 0x1
#define UART_RXEN 0x1
void uart_putchar(uint8_t ch);
int uart_getchar();
void query_uart(uintptr_t dtb);
#endif

View File

@ -1,76 +0,0 @@
#include <string.h>
#include "uart16550.h"
#include "fdt.h"
volatile uint8_t* uart16550;
#define UART_REG_QUEUE 0
#define UART_REG_LINESTAT 5
#define UART_REG_STATUS_RX 0x01
#define UART_REG_STATUS_TX 0x20
void uart16550_putchar(uint8_t ch)
{
while ((uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_TX) == 0);
uart16550[UART_REG_QUEUE] = ch;
}
int uart16550_getchar()
{
if (uart16550[UART_REG_LINESTAT] & UART_REG_STATUS_RX)
return uart16550[UART_REG_QUEUE];
return -1;
}
struct uart16550_scan
{
int compat;
uint64_t reg;
};
static void uart16550_open(const struct fdt_scan_node *node, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
memset(scan, 0, sizeof(*scan));
}
static void uart16550_prop(const struct fdt_scan_prop *prop, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
if (!strcmp(prop->name, "compatible") && !strcmp((const char*)prop->value, "ns16550a")) {
scan->compat = 1;
} else if (!strcmp(prop->name, "reg")) {
fdt_get_address(prop->node->parent, prop->value, &scan->reg);
}
}
static void uart16550_done(const struct fdt_scan_node *node, void *extra)
{
struct uart16550_scan *scan = (struct uart16550_scan *)extra;
if (!scan->compat || !scan->reg || uart16550) return;
uart16550 = (void*)(uintptr_t)scan->reg;
// http://wiki.osdev.org/Serial_Ports
uart16550[1] = 0x00; // Disable all interrupts
uart16550[3] = 0x80; // Enable DLAB (set baud rate divisor)
uart16550[0] = 0x03; // Set divisor to 3 (lo byte) 38400 baud
uart16550[1] = 0x00; // (hi byte)
uart16550[3] = 0x03; // 8 bits, no parity, one stop bit
uart16550[2] = 0xC7; // Enable FIFO, clear them, with 14-byte threshold
uart16550[4] = 0x0B;
uart16550[1] = 0x01; // Enable interrupt
}
void query_uart16550(uintptr_t fdt)
{
struct fdt_cb cb;
struct uart16550_scan scan;
memset(&cb, 0, sizeof(cb));
cb.open = uart16550_open;
cb.prop = uart16550_prop;
cb.done = uart16550_done;
cb.extra = &scan;
fdt_scan(fdt, &cb);
}

View File

@ -1,12 +0,0 @@
#ifndef _RISCV_16550_H
#define _RISCV_16550_H
#include <stdint.h>
extern volatile uint8_t* uart16550;
void uart16550_putchar(uint8_t ch);
int uart16550_getchar();
void query_uart16550(uintptr_t dtb);
#endif

View File

@ -1,103 +0,0 @@
#ifndef _RISCV_MISALIGNED_H
#define _RISCV_MISALIGNED_H
#include "encoding.h"
#include "bits.h"
#include <stdint.h>
#define DECLARE_UNPRIVILEGED_LOAD_FUNCTION(type, insn) \
static inline type load_##type(const type* addr, uintptr_t mepc) \
{ \
register uintptr_t __mepc asm ("a2") = mepc; \
register uintptr_t __mstatus asm ("a3"); \
type val; \
asm ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus), "=&r" (val) \
: "m" (*addr), "r" (MSTATUS_MPRV), "r" (__mepc)); \
return val; \
}
#define DECLARE_UNPRIVILEGED_STORE_FUNCTION(type, insn) \
static inline void store_##type(type* addr, type val, uintptr_t mepc) \
{ \
register uintptr_t __mepc asm ("a2") = mepc; \
register uintptr_t __mstatus asm ("a3"); \
asm volatile ("csrrs %0, mstatus, %3\n" \
#insn " %1, %2\n" \
"csrw mstatus, %0" \
: "+&r" (__mstatus) \
: "r" (val), "m" (*addr), "r" (MSTATUS_MPRV), \
"r" (__mepc)); \
}
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint8_t, lbu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint16_t, lhu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int8_t, lb)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int16_t, lh)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(int32_t, lw)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint8_t, sb)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint16_t, sh)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint32_t, sw)
#if __riscv_xlen == 64
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lwu)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint64_t, ld)
DECLARE_UNPRIVILEGED_STORE_FUNCTION(uint64_t, sd)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, ld)
#else
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uint32_t, lw)
DECLARE_UNPRIVILEGED_LOAD_FUNCTION(uintptr_t, lw)
static inline uint64_t load_uint64_t(const uint64_t* addr, uintptr_t mepc)
{
return load_uint32_t((uint32_t*)addr, mepc)
+ ((uint64_t)load_uint32_t((uint32_t*)addr + 1, mepc) << 32);
}
static inline void store_uint64_t(uint64_t* addr, uint64_t val, uintptr_t mepc)
{
store_uint32_t((uint32_t*)addr, val, mepc);
store_uint32_t((uint32_t*)addr + 1, val >> 32, mepc);
}
#endif
static uintptr_t __attribute__((always_inline)) get_insn(uintptr_t mepc, uintptr_t* mstatus)
{
register uintptr_t __mepc asm ("a2") = mepc;
register uintptr_t __mstatus asm ("a3");
uintptr_t val;
#ifndef __riscv_compressed
asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
STR(LWU) " %[insn], (%[addr])\n"
"csrw mstatus, %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc));
#else
uintptr_t rvc_mask = 3, tmp;
asm ("csrrs %[mstatus], mstatus, %[mprv]\n"
"and %[tmp], %[addr], 2\n"
"bnez %[tmp], 1f\n"
STR(LWU) " %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"beq %[tmp], %[rvc_mask], 2f\n"
"sll %[insn], %[insn], %[xlen_minus_16]\n"
"srl %[insn], %[insn], %[xlen_minus_16]\n"
"j 2f\n"
"1:\n"
"lhu %[insn], (%[addr])\n"
"and %[tmp], %[insn], %[rvc_mask]\n"
"bne %[tmp], %[rvc_mask], 2f\n"
"lhu %[tmp], 2(%[addr])\n"
"sll %[tmp], %[tmp], 16\n"
"add %[insn], %[insn], %[tmp]\n"
"2: csrw mstatus, %[mstatus]"
: [mstatus] "+&r" (__mstatus), [insn] "=&r" (val), [tmp] "=&r" (tmp)
: [mprv] "r" (MSTATUS_MPRV | MSTATUS_MXR), [addr] "r" (__mepc),
[rvc_mask] "r" (rvc_mask), [xlen_minus_16] "i" (__riscv_xlen - 16));
#endif
*mstatus = __mstatus;
return val;
}
#endif

View File

@ -1,35 +0,0 @@
#ifndef _VM_H
#define _VM_H
#include "encoding.h"
#include <stdint.h>
#define MEGAPAGE_SIZE ((uintptr_t)(RISCV_PGSIZE << RISCV_PGLEVEL_BITS))
#if __riscv_xlen == 64
# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP64_MODE, SATP_MODE_SV39)
# define VA_BITS 39
# define GIGAPAGE_SIZE (MEGAPAGE_SIZE << RISCV_PGLEVEL_BITS)
#else
# define SATP_MODE_CHOICE INSERT_FIELD(0, SATP32_MODE, SATP_MODE_SV32)
# define VA_BITS 32
#endif
typedef uintptr_t pte_t;
extern pte_t* root_page_table;
static inline void flush_tlb()
{
asm volatile ("sfence.vma");
}
static inline pte_t pte_create(uintptr_t ppn, int type)
{
return (ppn << PTE_PPN_SHIFT) | PTE_V | type;
}
static inline pte_t ptd_create(uintptr_t ppn)
{
return pte_create(ppn, PTE_V);
}
#endif

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -1,238 +0,0 @@
#! /bin/sh
#
# install - install a program, script, or datafile
# This comes from X11R5.
#
# Calling this script install-sh is preferred over install.sh, to prevent
# `make' implicit rules from creating a file called install from it
# when there is no Makefile.
#
# This script is compatible with the BSD install script, but was written
# from scratch.
#
# set DOITPROG to echo to test this script
# Don't use :- since 4.3BSD and earlier shells don't like it.
doit="${DOITPROG-}"
# put in absolute paths if you don't have them in your path; or use env. vars.
mvprog="${MVPROG-mv}"
cpprog="${CPPROG-cp}"
chmodprog="${CHMODPROG-chmod}"
chownprog="${CHOWNPROG-chown}"
chgrpprog="${CHGRPPROG-chgrp}"
stripprog="${STRIPPROG-strip}"
rmprog="${RMPROG-rm}"
mkdirprog="${MKDIRPROG-mkdir}"
tranformbasename=""
transform_arg=""
instcmd="$mvprog"
chmodcmd="$chmodprog 0755"
chowncmd=""
chgrpcmd=""
stripcmd=""
rmcmd="$rmprog -f"
mvcmd="$mvprog"
src=""
dst=""
dir_arg=""
while [ x"$1" != x ]; do
case $1 in
-c) instcmd="$cpprog"
shift
continue;;
-d) dir_arg=true
shift
continue;;
-m) chmodcmd="$chmodprog $2"
shift
shift
continue;;
-o) chowncmd="$chownprog $2"
shift
shift
continue;;
-g) chgrpcmd="$chgrpprog $2"
shift
shift
continue;;
-s) stripcmd="$stripprog"
shift
continue;;
-t=*) transformarg=`echo $1 | sed 's/-t=//'`
shift
continue;;
-b=*) transformbasename=`echo $1 | sed 's/-b=//'`
shift
continue;;
*) if [ x"$src" = x ]
then
src=$1
else
# this colon is to work around a 386BSD /bin/sh bug
:
dst=$1
fi
shift
continue;;
esac
done
if [ x"$src" = x ]
then
echo "install: no input file specified"
exit 1
else
true
fi
if [ x"$dir_arg" != x ]; then
dst=$src
src=""
if [ -d $dst ]; then
instcmd=:
else
instcmd=mkdir
fi
else
# Waiting for this to be detected by the "$instcmd $src $dsttmp" command
# might cause directories to be created, which would be especially bad
# if $src (and thus $dsttmp) contains '*'.
if [ -f $src -o -d $src ]
then
true
else
echo "install: $src does not exist"
exit 1
fi
if [ x"$dst" = x ]
then
echo "install: no destination specified"
exit 1
else
true
fi
# If destination is a directory, append the input filename; if your system
# does not like double slashes in filenames, you may need to add some logic
if [ -d $dst ]
then
dst="$dst"/`basename $src`
else
true
fi
fi
## this sed command emulates the dirname command
dstdir=`echo $dst | sed -e 's,[^/]*$,,;s,/$,,;s,^$,.,'`
# Make sure that the destination directory exists.
# this part is taken from Noah Friedman's mkinstalldirs script
# Skip lots of stat calls in the usual case.
if [ ! -d "$dstdir" ]; then
defaultIFS='
'
IFS="${IFS-${defaultIFS}}"
oIFS="${IFS}"
# Some sh's can't handle IFS=/ for some reason.
IFS='%'
set - `echo ${dstdir} | sed -e 's@/@%@g' -e 's@^%@/@'`
IFS="${oIFS}"
pathcomp=''
while [ $# -ne 0 ] ; do
pathcomp="${pathcomp}${1}"
shift
if [ ! -d "${pathcomp}" ] ;
then
$mkdirprog "${pathcomp}"
else
true
fi
pathcomp="${pathcomp}/"
done
fi
if [ x"$dir_arg" != x ]
then
$doit $instcmd $dst &&
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dst; else true ; fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dst; else true ; fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dst; else true ; fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dst; else true ; fi
else
# If we're going to rename the final executable, determine the name now.
if [ x"$transformarg" = x ]
then
dstfile=`basename $dst`
else
dstfile=`basename $dst $transformbasename |
sed $transformarg`$transformbasename
fi
# don't allow the sed command to completely eliminate the filename
if [ x"$dstfile" = x ]
then
dstfile=`basename $dst`
else
true
fi
# Make a temp file name in the proper directory.
dsttmp=$dstdir/#inst.$$#
# Move or copy the file name to the temp name
$doit $instcmd $src $dsttmp &&
trap "rm -f ${dsttmp}" 0 &&
# and set any options; do chmod last to preserve setuid bits
# If any of these fail, we abort the whole thing. If we want to
# ignore errors from any of these, just make sure not to ignore
# errors from the above "$doit $instcmd $src $dsttmp" command.
if [ x"$chowncmd" != x ]; then $doit $chowncmd $dsttmp; else true;fi &&
if [ x"$chgrpcmd" != x ]; then $doit $chgrpcmd $dsttmp; else true;fi &&
if [ x"$stripcmd" != x ]; then $doit $stripcmd $dsttmp; else true;fi &&
if [ x"$chmodcmd" != x ]; then $doit $chmodcmd $dsttmp; else true;fi &&
# Now rename the file to the real destination.
$doit $rmcmd -f $dstdir/$dstfile &&
$doit $mvcmd $dsttmp $dstdir/$dstfile
fi &&
exit 0

View File

@ -1,40 +0,0 @@
#! /bin/sh
# mkinstalldirs --- make directory hierarchy
# Author: Noah Friedman <friedman@prep.ai.mit.edu>
# Created: 1993-05-16
# Public domain
# $Id: mkinstalldirs,v 1.1 2003/09/09 22:24:03 mhampton Exp $
errstatus=0
for file
do
set fnord `echo ":$file" | sed -ne 's/^:\//#/;s/^://;s/\// /g;s/^#/\//;p'`
shift
pathcomp=
for d
do
pathcomp="$pathcomp$d"
case "$pathcomp" in
-* ) pathcomp=./$pathcomp ;;
esac
if test ! -d "$pathcomp"; then
echo "mkdir $pathcomp" 1>&2
mkdir "$pathcomp" || lasterr=$?
if test ! -d "$pathcomp"; then
errstatus=$lasterr
fi
fi
pathcomp="$pathcomp/"
done
done
exit $errstatus
# mkinstalldirs ends here

View File

@ -1,117 +0,0 @@
#!/bin/bash
#=========================================================================
# vcs-version.sh [options] [src-dir]
#=========================================================================
#
# -h Display this message
# -v Verbose mode
#
# This script will create a version string by querying a version control
# system. The string is appropriate for use in installations and
# distributions. Currently this script assumes we are using git as our
# version control system but it would be possible to check and see if we
# are using an alternative version control system and create a version
# string appropriately.
#
# The script uses git describe plus a few other git commands to create a
# version strings in the following format:
#
# X.Y[-Z-gN][-dirty]
#
# where X is the major release, Y is the minor release, Z is the number
# of commits since the X.Y release, N is an eight digit abbreviated SHA
# hash of the most recent commit and the dirty suffix is appended when
# the working directory used to create the installation or distribution
# is not a pristine checkout. Here are some example version strings:
#
# 0.0 : initial import
# 0.0-3-g99ef6933 : 3rd commit since initial import (N=99ef6933)
# 1.0 : release 1.0
# 1.1-12-g3487ab12 : 12th commit since release 1.1 (N=3487ab12)
# 1.1-12-g3487ab12-dirty : 12th commit since release 1.1 (N=3487ab12)
#
# The last example is from a dirty working directory. To find the last
# release, the script looks for the last tag (does not need to be an
# annotated tag, but probably should be) which matches the format rel-*.
# If there is no such tag in the history, then the script uses 0.0 as
# the release number and counts the total number of commits since the
# original import for the commit count.
#
# If the current directory is not within the working directory, then the
# path to the source directory should be supplied on the command line.
#
# Author : Christopher Batten
# Date : August 5, 2009
set -e
#-------------------------------------------------------------------------
# Command line parsing
#-------------------------------------------------------------------------
if ( test "$1" = "-h" ); then
echo ""
sed -n '3p' $0 | sed -e 's/#//'
sed -n '5,/^$/p' $0 | sed -e 's/#//'
exit 1
fi
# Source directory command line option
src_dir="."
if ( test -n "$1" ); then
src_dir="$1"
fi
#-------------------------------------------------------------------------
# Verify source directory
#-------------------------------------------------------------------------
# If the source directory is not a git working directory output a
# question mark. A distribution will not be in a working directory, but
# the build system should be structured such that this script is not
# executed (and instead the version information should probably come
# from configure). If the user does not specify a source directory use
# the current directory.
if !( git rev-parse --is-inside-work-tree &> /dev/null ); then
echo "?"
exit 1;
fi
top_dir=`git rev-parse --show-cdup`
cd ./${top_dir}
#-------------------------------------------------------------------------
# Create the version string
#-------------------------------------------------------------------------
# See if we can do a describe based on a tag and if not use a default
# release number of 0.0 so that we always get canonical version number
if ( git describe --tags --match "rel-*" &> /dev/null ); then
ver_str=`git describe --tags --match "rel-*" | sed 's/rel-//'`
else
ver_num="0.0"
ver_commits=`git rev-list --all | wc -l | tr -d " "`
ver_sha=`git describe --tags --match "rel-*" --always`
ver_str="${ver_num}-${ver_commits}-g${ver_sha}"
fi
# Add a dirty suffix if working directory is dirty
if !( git diff --quiet ); then
ver_str="${ver_str}-dirty"
else
untracked=`git ls-files --directory --exclude-standard --others -t`
if ( test -n "${untracked}" ); then
ver_str="${ver_str}-dirty"
fi
fi
# Output the final version string
echo "${ver_str}"
# Final exit status
exit 0;

View File

@ -1,98 +0,0 @@
// See LICENSE for license details.
#include <stdint.h>
#include <string.h>
#include <stdarg.h>
#include <stdbool.h>
int vsnprintf(char* out, size_t n, const char* s, va_list vl)
{
bool format = false;
bool longarg = false;
size_t pos = 0;
for( ; *s; s++)
{
if(format)
{
switch(*s)
{
case 'l':
longarg = true;
break;
case 'p':
longarg = true;
if (++pos < n) out[pos-1] = '0';
if (++pos < n) out[pos-1] = 'x';
case 'x':
{
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
for(int i = 2*(longarg ? sizeof(long) : sizeof(int))-1; i >= 0; i--) {
int d = (num >> (4*i)) & 0xF;
if (++pos < n) out[pos-1] = (d < 10 ? '0'+d : 'a'+d-10);
}
longarg = false;
format = false;
break;
}
case 'd':
{
long num = longarg ? va_arg(vl, long) : va_arg(vl, int);
if (num < 0) {
num = -num;
if (++pos < n) out[pos-1] = '-';
}
long digits = 1;
for (long nn = num; nn /= 10; digits++)
;
for (int i = digits-1; i >= 0; i--) {
if (pos + i + 1 < n) out[pos + i] = '0' + (num % 10);
num /= 10;
}
pos += digits;
longarg = false;
format = false;
break;
}
case 's':
{
const char* s2 = va_arg(vl, const char*);
while (*s2) {
if (++pos < n)
out[pos-1] = *s2;
s2++;
}
longarg = false;
format = false;
break;
}
case 'c':
{
if (++pos < n) out[pos-1] = (char)va_arg(vl,int);
longarg = false;
format = false;
break;
}
default:
break;
}
}
else if(*s == '%')
format = true;
else
if (++pos < n) out[pos-1] = *s;
}
if (pos < n)
out[pos] = 0;
else if (n)
out[n-1] = 0;
return pos;
}
int snprintf(char* out, size_t n, const char* s, ...)
{
va_list vl;
va_start(vl, s);
int res = vsnprintf(out, n, s, vl);
va_end(vl);
return res;
}

View File

@ -1,90 +0,0 @@
#include <string.h>
#include <stdint.h>
#include <ctype.h>
void* memcpy(void* dest, const void* src, size_t len)
{
const char* s = src;
char *d = dest;
if ((((uintptr_t)dest | (uintptr_t)src) & (sizeof(uintptr_t)-1)) == 0) {
while ((void*)d < (dest + len - (sizeof(uintptr_t)-1))) {
*(uintptr_t*)d = *(const uintptr_t*)s;
d += sizeof(uintptr_t);
s += sizeof(uintptr_t);
}
}
while (d < (char*)(dest + len))
*d++ = *s++;
return dest;
}
void* memset(void* dest, int byte, size_t len)
{
if ((((uintptr_t)dest | len) & (sizeof(uintptr_t)-1)) == 0) {
uintptr_t word = byte & 0xFF;
word |= word << 8;
word |= word << 16;
word |= word << 16 << 16;
uintptr_t *d = dest;
while (d < (uintptr_t*)(dest + len))
*d++ = word;
} else {
char *d = dest;
while (d < (char*)(dest + len))
*d++ = byte;
}
return dest;
}
size_t strlen(const char *s)
{
const char *p = s;
while (*p)
p++;
return p - s;
}
int strcmp(const char* s1, const char* s2)
{
unsigned char c1, c2;
do {
c1 = *s1++;
c2 = *s2++;
} while (c1 != 0 && c1 == c2);
return c1 - c2;
}
char* strcpy(char* dest, const char* src)
{
char* d = dest;
while ((*d++ = *src++))
;
return dest;
}
long atol(const char* str)
{
long res = 0;
int sign = 0;
while (*str == ' ')
str++;
if (*str == '-' || *str == '+') {
sign = *str == '-';
str++;
}
while (*str) {
res *= 10;
res += *str++ - '0';
}
return sign ? -res : res;
}

View File

Some files were not shown because too many files have changed in this diff Show More