Since we only currently support Cortex-M class devices it hasn't been a problem to have cortex-m specific things in the kernel crate. However, our longer terms goals require that the kernel crate be architecture agnositic.
Process across architectures. (#1113)PROCS variable. (#1111)/cc @dverhaert
To get this going I took a first pass stab at what an interface might look like that an architecture needs to implement to support a syscall interface between processes and the kernel:
https://github.com/tock/tock/blob/ea39ca74de9e64f908101201748fc701a35c0fa9/kernel/src/syscall.rs#L23-L43
Please comment or add commits as needed. My goal was not to copy the exact interface we are using now. There is also this issue of the stored_regs that I'm not sure how to handle.
This motivated me to resurrect a branch I had lying around towards a Tock native port ( https://github.com/tock/tock/tree/native-port ) -- its fairly immature (currently it'll get as far as segfaulting when it tries to panic from the first of many unimplemented!'s that it hits), but it compiles a native binary! Which is a start.
[Update: Now it'll make it as far a unimplemented! when the kernel tries to go to sleep]
I'll try to see what implementing this interface for a non-MCU case looks like, which hopefully will be a good stress test of its flexibility.
I got started on this on the https://github.com/tock/tock/tree/arch-agnostic2 branch that builds off of the change to add a Kernel struct.
From what I posted before:
APP_FAULT and SYSCALL_FIRED global usize values and instead used two bits of a single variable. This makes the logic cleaner.set_syscall_return_value() function to the interface.Each process needs a way to keep around architecture-dependent state when that process is not running (for cortex-m we save a bunch of registers). This means the Process struct must be templated across architectures, but doing that makes the static PROCS array pointer hard (impossible?) to define. Therefore, this is blocked on removing the PROCS static variable in process.rs.
Templating Process across architectures means process looks like:
pub struct Process<'a, S: SyscallInterface> { ... }
and since the Kernel struct has to hold it, that looks like:
/// Main object for the kernel. Each board will need to create one.
pub struct Kernel<S: SyscallInterface> {
/// How many "to-do" items exist at any given time. These include
/// outstanding callbacks and processes in the Running state.
work: Cell<usize>,
/// This holds a pointer to the static array of Process pointers.
processes: &'static [Option<&'static mut Process<'static, S>>],
}
but now anything that holds a kernel pointer must also have that template, which is fine except that AppId or Callback needs a &kernel so that a capsule can schedule a callback for a process. Right now that means AppId looks like:
/// Userspace app identifier.
#[derive(Clone, Copy)]
pub struct AppId<S> {
kernel: &'static Kernel<S>,
idx: usize,
}
The issue becomes that AppId is in the Driver interface. Which means that Driver would also need to be templated as well, and at that point it seems kind of ridiculous. Why should every capsule that wants to provide a Driver interface also be templated across architectures?
Is there a way to avoid this? Maybe some rust trick or some way to structure this that isn't popping into my head?
Each process needs a way to keep around architecture-dependent state when that process is not running (for cortex-m we save a bunch of registers). This means the Process struct must be templated across architectures, but doing that makes the static PROCS array pointer hard (impossible?) to define.
This is also true for MPUs -- each process will need to store state on how to restore the MPU when it's switched in. That state is chip-specific (e.g., the state kept for the K66 MPU is different than the standard CortexM MPU).
Should we move the KernelUserlandBoundary into the Chip? We would end up with something like:
I think this is cleaner, as there is really no reason the board file should have to pick a chip and an arch.
This board file then looks like:
The full implementation is here: https://github.com/tock/tock/compare/new-mpu-new-chip?expand=1
Ok! For the first pass this is done. We have to actually try to use Tock on a new architecture to really evaluate this, but all of the goals for this issue have been met.