irq commit: this large commit gets interrupts working
Signed-off-by: Sean Cross <sean@xobs.io>
This commit is contained in:
parent
79114aa65a
commit
9a4d002832
@ -7,7 +7,7 @@ description = "Core kernel for Xous, including task switching and memory managem
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
xous-riscv = { path = "xous-riscv" }
|
xous-riscv = { path = "xous-riscv" }
|
||||||
xous-riscv-rt = { path = "xous-riscv-rt" }
|
xous-kernel-riscv-rt = { path = "xous-kernel-riscv-rt" }
|
||||||
|
|
||||||
[profile.release]
|
[profile.release]
|
||||||
codegen-units = 1 # 1 better optimizations
|
codegen-units = 1 # 1 better optimizations
|
||||||
|
19
build.rs
Normal file
19
build.rs
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
// NOTE: Adapted from cortex-m/build.rs
|
||||||
|
use std::env;
|
||||||
|
use std::fs;
|
||||||
|
use std::io::Write;
|
||||||
|
use std::path::PathBuf;
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let out_dir = PathBuf::from(env::var("OUT_DIR").unwrap());
|
||||||
|
|
||||||
|
// Put the linker script somewhere the linker can find it
|
||||||
|
fs::File::create(out_dir.join("memory.x"))
|
||||||
|
.unwrap()
|
||||||
|
.write_all(include_bytes!("memory.x"))
|
||||||
|
.unwrap();
|
||||||
|
println!("cargo:rustc-link-search={}", out_dir.display());
|
||||||
|
|
||||||
|
println!("cargo:rerun-if-changed=build.rs");
|
||||||
|
println!("cargo:rerun-if-changed=memory.x");
|
||||||
|
}
|
83
src/irq.rs
Normal file
83
src/irq.rs
Normal file
@ -0,0 +1,83 @@
|
|||||||
|
use crate::syscalls;
|
||||||
|
use xous_riscv::register::{mstatus, vmim};
|
||||||
|
|
||||||
|
// Shamelessly taken from
|
||||||
|
// https://stackoverflow.com/questions/36258417/using-a-macro-to-initialize-a-big-array-of-non-copy-elements
|
||||||
|
// Allows us to fill an array with a predefined value.
|
||||||
|
macro_rules! filled_array {
|
||||||
|
(@accum (0, $($_es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@as_expr [$($body)*])};
|
||||||
|
(@accum (1, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)*))};
|
||||||
|
(@accum (2, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (0, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
|
||||||
|
(@accum (3, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (2, $($es),*) -> ($($body)* $($es,)*))};
|
||||||
|
(@accum (4, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (2, $($es,)* $($es),*) -> ($($body)*))};
|
||||||
|
(@accum (5, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)*))};
|
||||||
|
(@accum (6, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)*))};
|
||||||
|
(@accum (7, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (4, $($es),*) -> ($($body)* $($es,)* $($es,)* $($es,)*))};
|
||||||
|
(@accum (8, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (4, $($es,)* $($es),*) -> ($($body)*))};
|
||||||
|
(@accum (16, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (8, $($es,)* $($es),*) -> ($($body)*))};
|
||||||
|
(@accum (32, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (16, $($es,)* $($es),*) -> ($($body)*))};
|
||||||
|
(@accum (64, $($es:expr),*) -> ($($body:tt)*))
|
||||||
|
=> {filled_array!(@accum (32, $($es,)* $($es),*) -> ($($body)*))};
|
||||||
|
|
||||||
|
(@as_expr $e:expr) => {$e};
|
||||||
|
|
||||||
|
[$e:expr; $n:tt] => { filled_array!(@accum ($n, $e) -> ()) };
|
||||||
|
}
|
||||||
|
|
||||||
|
static mut IRQ_HANDLERS: [Option<fn(usize)>; 32] = filled_array![None; 32];
|
||||||
|
|
||||||
|
pub fn handle(irqs_pending: usize) {
|
||||||
|
// Unsafe is required here because we're accessing a static
|
||||||
|
// mutable value, and it could be modified from various threads.
|
||||||
|
// However, this is fine because this is run from an IRQ context
|
||||||
|
// with interrupts disabled.
|
||||||
|
// NOTE: This will become an issue when running with multiple cores,
|
||||||
|
// so this should be protected by a mutex.
|
||||||
|
unsafe {
|
||||||
|
for irq_no in 0..IRQ_HANDLERS.len() {
|
||||||
|
if irqs_pending & (1 << irq_no) != 0 {
|
||||||
|
if let Some(f) = IRQ_HANDLERS[irq_no] {
|
||||||
|
// Call the IRQ handler
|
||||||
|
f(irq_no);
|
||||||
|
} else {
|
||||||
|
// If there is no handler, mask this interrupt
|
||||||
|
// to prevent an IRQ storm. This is considered
|
||||||
|
// an error.
|
||||||
|
vmim::write(vmim::read() | (1 << irq_no));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn sys_interrupt_claim(irq: usize, f: fn(usize)) -> Result<(), syscalls::XousError> {
|
||||||
|
// Unsafe is required since we're accessing a static mut array.
|
||||||
|
// However, we disable interrupts to prevent contention on this array.
|
||||||
|
unsafe {
|
||||||
|
mstatus::clear_mie();
|
||||||
|
let result = if irq > IRQ_HANDLERS.len() {
|
||||||
|
Err(syscalls::XousError::InterruptNotFound)
|
||||||
|
} else if IRQ_HANDLERS[irq].is_some() {
|
||||||
|
Err(syscalls::XousError::InterruptInUse)
|
||||||
|
} else {
|
||||||
|
IRQ_HANDLERS[irq] = Some(f);
|
||||||
|
// Note that the vexriscv "IRQ Mask" register is inverse-logic --
|
||||||
|
// that is, setting a bit in the "mask" register unmasks (i.e. enables) it.
|
||||||
|
vmim::write(vmim::read() | (1 << irq));
|
||||||
|
Ok(())
|
||||||
|
};
|
||||||
|
mstatus::set_mie();
|
||||||
|
result
|
||||||
|
}
|
||||||
|
}
|
12
src/lib.rs
Normal file
12
src/lib.rs
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
#![no_std]
|
||||||
|
|
||||||
|
extern crate xous_riscv;
|
||||||
|
|
||||||
|
use core::panic::PanicInfo;
|
||||||
|
#[panic_handler]
|
||||||
|
fn handle_panic(_arg: &PanicInfo) -> ! {
|
||||||
|
loop {}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Allow consumers of this library to make syscalls
|
||||||
|
pub mod syscalls;
|
57
src/main.rs
57
src/main.rs
@ -2,17 +2,68 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
|
|
||||||
extern crate xous_riscv;
|
extern crate xous_riscv;
|
||||||
|
mod syscalls;
|
||||||
|
mod irq;
|
||||||
|
|
||||||
|
pub use irq::sys_interrupt_claim;
|
||||||
|
|
||||||
use core::panic::PanicInfo;
|
use core::panic::PanicInfo;
|
||||||
|
use xous_kernel_riscv_rt::xous_kernel_entry;
|
||||||
|
use xous_riscv::register::{mcause, mstatus, mie, vmim, vmip};
|
||||||
|
|
||||||
|
|
||||||
#[panic_handler]
|
#[panic_handler]
|
||||||
fn handle_panic(arg: &PanicInfo) -> ! {
|
fn handle_panic(_arg: &PanicInfo) -> ! {
|
||||||
loop {}
|
loop {}
|
||||||
}
|
}
|
||||||
|
|
||||||
use xous_riscv_rt::entry;
|
fn print_str(uart: *mut usize, s: &str) {
|
||||||
#[entry]
|
for c in s.bytes() {
|
||||||
|
unsafe { uart.write_volatile(c as usize) };
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[xous_kernel_entry]
|
||||||
fn xous_main() -> ! {
|
fn xous_main() -> ! {
|
||||||
|
unsafe {
|
||||||
|
vmim::write(0); // Disable all machine interrupts
|
||||||
|
mie::set_msoft();
|
||||||
|
mie::set_mtimer();
|
||||||
|
mie::set_mext();
|
||||||
|
mstatus::set_mie(); // Enable CPU interrupts
|
||||||
|
}
|
||||||
|
sys_interrupt_claim(2, |_| {
|
||||||
|
let uart_ptr = 0xE000_1800 as *mut usize;
|
||||||
|
print_str(uart_ptr, "hello, world!\r\n");
|
||||||
|
// Acknowledge the IRQ
|
||||||
|
unsafe {
|
||||||
|
uart_ptr.add(0).read_volatile();
|
||||||
|
|
||||||
|
// Acknowledge the event
|
||||||
|
uart_ptr.add(4).write_volatile(3);
|
||||||
|
};
|
||||||
|
})
|
||||||
|
.unwrap();
|
||||||
|
|
||||||
|
// Enable interrupts
|
||||||
|
let uart_ptr = 0xE000_1800 as *mut usize;
|
||||||
|
unsafe { uart_ptr.add(4).write_volatile(3) };
|
||||||
|
unsafe { uart_ptr.add(5).write_volatile(3) };
|
||||||
|
print_str(uart_ptr, "greetings!\r\n");
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
unsafe { xous_riscv::asm::wfi() };
|
unsafe { xous_riscv::asm::wfi() };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn trap_handler() {
|
||||||
|
let mc = mcause::read();
|
||||||
|
let irqs_pending = vmip::read();
|
||||||
|
|
||||||
|
if mc.is_exception() {}
|
||||||
|
|
||||||
|
if irqs_pending != 0 {
|
||||||
|
irq::handle(irqs_pending);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
291
src/syscalls.rs
Normal file
291
src/syscalls.rs
Normal file
@ -0,0 +1,291 @@
|
|||||||
|
use core::num::NonZeroUsize;
|
||||||
|
|
||||||
|
#[allow(dead_code)] pub type MemoryAddress = NonZeroUsize;
|
||||||
|
#[allow(dead_code)] pub type MemorySize = NonZeroUsize;
|
||||||
|
#[allow(dead_code)] pub type StackPointer = usize;
|
||||||
|
#[allow(dead_code)] pub type MessageId = usize;
|
||||||
|
|
||||||
|
#[allow(dead_code)] pub type XousPid = u8;
|
||||||
|
#[allow(dead_code)] pub type XousMessageSender = usize;
|
||||||
|
#[allow(dead_code)] pub type XousConnection = usize;
|
||||||
|
|
||||||
|
/// Server ID
|
||||||
|
#[allow(dead_code)] pub type XousSid = usize;
|
||||||
|
|
||||||
|
/// Equivalent to a RISC-V Hart ID
|
||||||
|
#[allow(dead_code)] pub type XousCpuId = usize;
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum XousError {
|
||||||
|
BadAlignment,
|
||||||
|
BadAddress,
|
||||||
|
OutOfMemory,
|
||||||
|
InterruptNotFound,
|
||||||
|
InterruptInUse,
|
||||||
|
InvalidString,
|
||||||
|
ServerExists,
|
||||||
|
ServerNotFound,
|
||||||
|
ProcessNotFound,
|
||||||
|
ProcessNotChild,
|
||||||
|
ProcessTerminated,
|
||||||
|
Timeout,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct XousContext {
|
||||||
|
stack: StackPointer,
|
||||||
|
pid: XousPid,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct XousMemoryMessage {
|
||||||
|
id: MessageId,
|
||||||
|
in_buf: Option<MemoryAddress>,
|
||||||
|
in_buf_size: Option<MemorySize>,
|
||||||
|
out_buf: Option<MemoryAddress>,
|
||||||
|
out_buf_size: Option<MemorySize>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct XousScalarMessage {
|
||||||
|
id: MessageId,
|
||||||
|
arg1: usize,
|
||||||
|
arg2: usize,
|
||||||
|
arg3: usize,
|
||||||
|
arg4: usize,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub enum XousMessage {
|
||||||
|
Memory(XousMemoryMessage),
|
||||||
|
Scalar(XousScalarMessage),
|
||||||
|
}
|
||||||
|
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub struct XousMessageReceived {
|
||||||
|
sender: XousMessageSender,
|
||||||
|
message: XousMessage,
|
||||||
|
}
|
||||||
|
|
||||||
|
extern "Rust" {
|
||||||
|
/// Allocates kernel structures for a new process, and returns the new PID.
|
||||||
|
/// This removes `page_count` page tables from the calling process at `origin_address`
|
||||||
|
/// and places them at `target_address`.
|
||||||
|
///
|
||||||
|
/// If the process was created successfully, then the new PID is returned to
|
||||||
|
/// the calling process. The child is not automatically scheduled for running.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **BadAlignment**: `origin_address` or `target_address` were not page-aligned,
|
||||||
|
/// or `address_size` was not a multiple of the page address size.
|
||||||
|
/// * **OutOfMemory**: The kernel couldn't allocate memory for the new process.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_process_spawn(
|
||||||
|
origin_address: MemoryAddress,
|
||||||
|
target_address: MemoryAddress,
|
||||||
|
address_size: MemorySize,
|
||||||
|
) -> Result<XousPid, XousError>;
|
||||||
|
|
||||||
|
/// Pauses execution of the current thread and returns execution to the parent
|
||||||
|
/// process. This function may return at any time in the future, including immediately.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_process_yield();
|
||||||
|
|
||||||
|
/// Interrupts the current process and returns control to the parent process.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ProcessNotFound**: The provided PID doesn't exist, or is not running on the given CPU.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sysi_process_suspend(pid: XousPid, cpu_id: XousCpuId) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
/// Claims an interrupt and unmasks it immediately. The provided function will
|
||||||
|
/// be called from within an interrupt context, but using the ordinary privilege level of
|
||||||
|
/// the process.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **InterruptNotFound**: The specified interrupt isn't valid on this system
|
||||||
|
/// * **InterruptInUse**: The specified interrupt has already been claimed
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_interrupt_claim(irq: usize, f: fn(usize)) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
/// Returns the interrupt back to the operating system and masks it again.
|
||||||
|
/// This function is implicitly called when a process exits.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **InterruptNotFound**: The specified interrupt doesn't exist, or isn't assigned
|
||||||
|
/// to this process.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_interrupt_free(irq: usize) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
/// Resumes a process using the given stack pointer. A parent could use
|
||||||
|
/// this function to implement multi-threading inside a child process, or
|
||||||
|
/// to create a task switcher.
|
||||||
|
///
|
||||||
|
/// To resume a process exactly where it left off, set `stack_pointer` to `None`.
|
||||||
|
/// This would be done in a very simple system that has no threads.
|
||||||
|
///
|
||||||
|
/// By default, at most three context switches can be made before the quantum
|
||||||
|
/// expires. To enable more, pass `additional_contexts`.
|
||||||
|
///
|
||||||
|
/// If no more contexts are available when one is required, then the child
|
||||||
|
/// automatically relinquishes its quantum.
|
||||||
|
///
|
||||||
|
/// # Returns
|
||||||
|
///
|
||||||
|
/// When this function returns, it provides a list of the processes and
|
||||||
|
/// stack pointers that are ready to be run. Three can fit as return values,
|
||||||
|
/// and additional context switches will be supplied in the slice of context
|
||||||
|
/// switches, if one is provided.
|
||||||
|
///
|
||||||
|
/// # Examples
|
||||||
|
///
|
||||||
|
/// If a process called `yield()`, or if its quantum expired normally, then
|
||||||
|
/// a single context is returned: The target thread, and its stack pointer.
|
||||||
|
///
|
||||||
|
/// If the child process called `client_send()` and ended up blocking due to
|
||||||
|
/// the server not being ready, then this would return no context switches.
|
||||||
|
/// This thread or process should not be scheduled to run.
|
||||||
|
///
|
||||||
|
/// If the child called `client_send()` and the server was ready, then the
|
||||||
|
/// server process would be run immediately. If the child process' quantum
|
||||||
|
/// expired while the server was running, then this function would return
|
||||||
|
/// a single context containing the PID of the server, and the stack pointer.
|
||||||
|
///
|
||||||
|
/// If the child called `client_send()` and the server was ready, then the
|
||||||
|
/// server process would be run immediately. If the server then finishes,
|
||||||
|
/// execution flow is returned to the child process. If the quantum then
|
||||||
|
/// expires, this would return two contexts: the server's PID and its stack
|
||||||
|
/// pointer when it called `client_reply()`, and the child's PID with its
|
||||||
|
/// current stack pointer.
|
||||||
|
///
|
||||||
|
/// If the server in turn called another server, and both servers ended up
|
||||||
|
/// returning to the child before the quantum expired, then there would be
|
||||||
|
/// three contexts on the stack.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ProcessNotFound**: The requested process does not exist
|
||||||
|
/// * **ProcessNotChild**: The given process was not a child process, and
|
||||||
|
/// therefore couldn't be resumed.
|
||||||
|
/// * **ProcessTerminated**: The process has crashed.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_process_resume(
|
||||||
|
process_id: XousPid,
|
||||||
|
stack_pointer: Option<usize>,
|
||||||
|
additional_contexts: &Option<&[XousContext]>,
|
||||||
|
) -> Result<
|
||||||
|
(
|
||||||
|
Option<XousContext>,
|
||||||
|
Option<XousContext>,
|
||||||
|
Option<XousContext>,
|
||||||
|
),
|
||||||
|
XousError,
|
||||||
|
>;
|
||||||
|
|
||||||
|
/// Causes a process to terminate immediately.
|
||||||
|
///
|
||||||
|
/// It is recommended that this function only be called on processes that
|
||||||
|
/// have cleaned up after themselves, e.g. shut down any servers and
|
||||||
|
/// flushed any file descriptors.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ProcessNotFound**: The requested process does not exist
|
||||||
|
/// * **ProcessNotChild**: The requested process is not our child process
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_process_terminate(process_id: XousPid) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
/// Allocates pages of memory, equal to a total of `size
|
||||||
|
/// bytes. If a physical address is specified, then this
|
||||||
|
/// can be used to allocate regions such as memory-mapped I/O.
|
||||||
|
/// If a virtual address is specified, then the returned
|
||||||
|
/// pages are located at that address. Otherwise, they
|
||||||
|
/// are located at an unspecified offset.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **BadAlignment**: Either the physical or virtual addresses aren't page-aligned, or the size isn't a multiple of the page width.
|
||||||
|
/// * **OutOfMemory**: A contiguous chunk of memory couldn't be found, or the system's memory size has been exceeded.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_memory_allocate(
|
||||||
|
phys: Option<MemoryAddress>,
|
||||||
|
virt: Option<MemoryAddress>,
|
||||||
|
size: MemorySize,
|
||||||
|
) -> Result<MemoryAddress, XousError>;
|
||||||
|
|
||||||
|
/// Equivalent to the Unix `sbrk` call. Adjusts the
|
||||||
|
/// heap size to be equal to the specified value. Heap
|
||||||
|
/// sizes start out at 0 bytes in new processes.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **OutOfMemory**: The region couldn't be extended.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_heap_resize(size: MemorySize) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
///! Message Passing Functions
|
||||||
|
|
||||||
|
/// Create a new server with the given name. This enables other processes to
|
||||||
|
/// connect to this server to send messages. Only one server name may exist
|
||||||
|
/// on a system at a time.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ServerExists**: A server has already registered with that name
|
||||||
|
/// * **InvalidString**: The name was not a valid UTF-8 string
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_server_create(server_name: usize) -> Result<XousSid, XousError>;
|
||||||
|
|
||||||
|
/// Suspend the current process until a message is received. This thread will
|
||||||
|
/// block until a message is received.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_server_receive(server_id: XousSid) -> Result<XousMessageReceived, XousError>;
|
||||||
|
|
||||||
|
/// Reply to a message received. The thread will be unblocked, and will be
|
||||||
|
/// scheduled to run sometime in the future.
|
||||||
|
///
|
||||||
|
/// If the message that we're responding to is a Memory message, then it should be
|
||||||
|
/// passed back directly to the destination without modification -- the actual contents
|
||||||
|
/// will be passed in the `out` address pointed to by the structure.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ProcessTerminated**: The process we're replying to doesn't exist any more.
|
||||||
|
/// * **BadAddress**: The message didn't pass back all the memory it should have.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_server_reply(
|
||||||
|
destination: XousMessageSender,
|
||||||
|
message: XousMessage,
|
||||||
|
) -> Result<(), XousError>;
|
||||||
|
|
||||||
|
/// Look up a server name and connect to it.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ServerNotFound**: No server is registered with that name.
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_client_connect(server_name: usize) -> Result<XousConnection, XousError>;
|
||||||
|
|
||||||
|
/// Send a message to a server. This thread will block until the message is responded to.
|
||||||
|
/// If the message type is `Memory`, then the memory addresses pointed to will be
|
||||||
|
/// unavailable to this process until this function returns.
|
||||||
|
///
|
||||||
|
/// # Errors
|
||||||
|
///
|
||||||
|
/// * **ServerNotFound**: The server does not exist so the connection is now invalid
|
||||||
|
/// * **BadAddress**: The client tried to pass a Memory message using an address it doesn't own
|
||||||
|
/// * **Timeout**: The timeout limit has been reached
|
||||||
|
#[allow(dead_code)]
|
||||||
|
pub fn sys_client_send(
|
||||||
|
server: XousConnection,
|
||||||
|
message: XousMessage,
|
||||||
|
) -> Result<XousMessage, XousError>;
|
||||||
|
}
|
@ -1,5 +1,5 @@
|
|||||||
[package]
|
[package]
|
||||||
name = "xous-riscv-rt"
|
name = "xous-kernel-riscv-rt"
|
||||||
version = "0.6.1"
|
version = "0.6.1"
|
||||||
repository = "https://github.com/xous/xous-riscv-rt"
|
repository = "https://github.com/xous/xous-riscv-rt"
|
||||||
authors = ["Sean Cross <sean@xobs.io>", "The RISC-V Team <risc-v@teams.rust-embedded.org>"]
|
authors = ["Sean Cross <sean@xobs.io>", "The RISC-V Team <risc-v@teams.rust-embedded.org>"]
|
||||||
@ -10,9 +10,9 @@ license = "ISC"
|
|||||||
|
|
||||||
[dependencies]
|
[dependencies]
|
||||||
r0 = "0.2.2"
|
r0 = "0.2.2"
|
||||||
xous-riscv = { path = "../xous-riscv", version = "0.5.1" }
|
xous-riscv = { path = "../xous-riscv" }
|
||||||
riscv-rt-macros = { path = "macros", version = "0.1.6" }
|
xous-kernel-riscv-rt-macros = { path = "macros" }
|
||||||
|
|
||||||
[dev-dependencies]
|
[dev-dependencies]
|
||||||
xous-riscv = { path = "../xous-riscv", version = "0.5.1" }
|
xous-riscv = { path = "../xous-riscv" }
|
||||||
panic-halt = "0.2.0"
|
panic-halt = "0.2.0"
|
@ -8,7 +8,7 @@ description = "Attributes re-exported in `riscv-rt`"
|
|||||||
documentation = "https://docs.rs/riscv-rt"
|
documentation = "https://docs.rs/riscv-rt"
|
||||||
keywords = ["riscv", "runtime", "startup"]
|
keywords = ["riscv", "runtime", "startup"]
|
||||||
license = "MIT OR Apache-2.0"
|
license = "MIT OR Apache-2.0"
|
||||||
name = "riscv-rt-macros"
|
name = "xous-kernel-riscv-rt-macros"
|
||||||
repository = "https://github.com/rust-embedded/riscv-rt"
|
repository = "https://github.com/rust-embedded/riscv-rt"
|
||||||
version = "0.1.6"
|
version = "0.1.6"
|
||||||
|
|
@ -53,7 +53,7 @@ use proc_macro::TokenStream;
|
|||||||
/// }
|
/// }
|
||||||
/// ```
|
/// ```
|
||||||
#[proc_macro_attribute]
|
#[proc_macro_attribute]
|
||||||
pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
pub fn xous_kernel_entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
||||||
let f = parse_macro_input!(input as ItemFn);
|
let f = parse_macro_input!(input as ItemFn);
|
||||||
|
|
||||||
// check the function signature
|
// check the function signature
|
||||||
@ -94,7 +94,7 @@ pub fn entry(args: TokenStream, input: TokenStream) -> TokenStream {
|
|||||||
let stmts = f.block.stmts;
|
let stmts = f.block.stmts;
|
||||||
|
|
||||||
quote!(
|
quote!(
|
||||||
#[export_name = "xous_main"]
|
#[export_name = "xous_kernel_main"]
|
||||||
#(#attrs)*
|
#(#attrs)*
|
||||||
pub #unsafety fn #hash() -> ! {
|
pub #unsafety fn #hash() -> ! {
|
||||||
#(#stmts)*
|
#(#stmts)*
|
@ -254,10 +254,10 @@
|
|||||||
#![deny(warnings)]
|
#![deny(warnings)]
|
||||||
|
|
||||||
extern crate xous_riscv;
|
extern crate xous_riscv;
|
||||||
extern crate riscv_rt_macros as macros;
|
extern crate xous_kernel_riscv_rt_macros as macros;
|
||||||
extern crate r0;
|
extern crate r0;
|
||||||
|
|
||||||
pub use macros::{entry, pre_init};
|
pub use macros::{xous_kernel_entry, pre_init};
|
||||||
|
|
||||||
use xous_riscv::register::mstatus;
|
use xous_riscv::register::mstatus;
|
||||||
|
|
||||||
@ -288,7 +288,7 @@ extern "C" {
|
|||||||
pub unsafe extern "C" fn start_rust() -> ! {
|
pub unsafe extern "C" fn start_rust() -> ! {
|
||||||
extern "Rust" {
|
extern "Rust" {
|
||||||
// This symbol will be provided by the kernel
|
// This symbol will be provided by the kernel
|
||||||
fn xous_main() -> !;
|
fn xous_kernel_main() -> !;
|
||||||
|
|
||||||
// This symbol will be provided by the user via `#[pre_init]`
|
// This symbol will be provided by the user via `#[pre_init]`
|
||||||
fn __pre_init();
|
fn __pre_init();
|
||||||
@ -303,7 +303,7 @@ pub unsafe extern "C" fn start_rust() -> ! {
|
|||||||
r0::init_data(&mut _sdata, &mut _edata, &_sidata);
|
r0::init_data(&mut _sdata, &mut _edata, &_sidata);
|
||||||
}
|
}
|
||||||
|
|
||||||
xous_main();
|
xous_kernel_main();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -315,3 +315,10 @@ RW(0x7A3, tdata3) // Third Debug/Trace trigger data register
|
|||||||
RW(0x7B0, dcsr) // Debug control and status register
|
RW(0x7B0, dcsr) // Debug control and status register
|
||||||
RW(0x7B1, dpc) // Debug PC
|
RW(0x7B1, dpc) // Debug PC
|
||||||
RW(0x7B2, dscratch) // Debug scratch register
|
RW(0x7B2, dscratch) // Debug scratch register
|
||||||
|
|
||||||
|
// VexRiscv custom registers
|
||||||
|
RW(0xBC0, vmim) // Machine IRQ Mask
|
||||||
|
RW(0xFC0, vmip) // Machine IRQ Pending
|
||||||
|
RW(0x9C0, vsim) // Supervisor IRQ Mask
|
||||||
|
RW(0xDC0, vsip) // Supervisor IRQ Pending
|
||||||
|
RW(0xCC0, vdci) // DCache Info
|
||||||
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -107,3 +107,10 @@ pub use self::mhpmeventx::*;
|
|||||||
|
|
||||||
|
|
||||||
// TODO: Debug Mode Registers
|
// TODO: Debug Mode Registers
|
||||||
|
|
||||||
|
// VexRiscv registers
|
||||||
|
pub mod vmim;
|
||||||
|
pub mod vmip;
|
||||||
|
pub mod vsim;
|
||||||
|
pub mod vsip;
|
||||||
|
pub mod vdci;
|
||||||
|
4
xous-riscv/src/register/vdci.rs
Normal file
4
xous-riscv/src/register/vdci.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! uscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0xCC0, __read_vdci);
|
||||||
|
write_csr_as_usize!(0xCC0, __write_vdci);
|
4
xous-riscv/src/register/vmim.rs
Normal file
4
xous-riscv/src/register/vmim.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! uscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0xBC0, __read_vmim);
|
||||||
|
write_csr_as_usize!(0xBC0, __write_vmim);
|
4
xous-riscv/src/register/vmip.rs
Normal file
4
xous-riscv/src/register/vmip.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! uscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0xFC0, __read_vmip);
|
||||||
|
write_csr_as_usize!(0xFC0, __write_vmip);
|
4
xous-riscv/src/register/vsim.rs
Normal file
4
xous-riscv/src/register/vsim.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! uscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0x9C0, __read_vsim);
|
||||||
|
write_csr_as_usize!(0x9C0, __write_vsim);
|
4
xous-riscv/src/register/vsip.rs
Normal file
4
xous-riscv/src/register/vsip.rs
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
//! uscratch register
|
||||||
|
|
||||||
|
read_csr_as_usize!(0xDC0, __read_vsip);
|
||||||
|
write_csr_as_usize!(0xDC0, __write_vsip);
|
Loading…
Reference in New Issue
Block a user