kernel: proper type for static shared variables.

* Changed the KERNEL_CHANNEL_* to Mutex<T> with proper type, remove the
  need for unsafe.
* Exposed a const pointer to KernelImage, with UnsafeCell holding
  the library field for unbind with interior mutability.
This commit is contained in:
pca006132 2020-07-24 12:24:01 +08:00
parent 0310421085
commit 0ce45b145e
4 changed files with 44 additions and 42 deletions

View File

@ -1,6 +1,6 @@
//! Kernel prologue/epilogue that runs on the 2nd CPU core //! Kernel prologue/epilogue that runs on the 2nd CPU core
use core::{mem, ptr}; use core::{mem, ptr, cell::UnsafeCell};
use alloc::borrow::ToOwned; use alloc::borrow::ToOwned;
use log::{debug, info, error}; use log::{debug, info, error};
use cslice::CSlice; use cslice::CSlice;
@ -9,7 +9,6 @@ use libcortex_a9::{
enable_fpu, enable_fpu,
cache::{dcci_slice, iciallu, bpiall}, cache::{dcci_slice, iciallu, bpiall},
asm::{dsb, isb}, asm::{dsb, isb},
sync_channel
}; };
use dyld::{self, Library}; use dyld::{self, Library};
use crate::eh_artiq; use crate::eh_artiq;
@ -19,13 +18,10 @@ use super::{
dma::init_dma, dma::init_dma,
CHANNEL_0TO1, CHANNEL_1TO0, CHANNEL_0TO1, CHANNEL_1TO0,
KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0, KERNEL_CHANNEL_0TO1, KERNEL_CHANNEL_1TO0,
KERNEL_LIBRARY, KERNEL_IMAGE,
Message, Message,
}; };
/// will contain the kernel image address on the heap
static mut KERNEL_LOAD_ADDR: usize = 0;
unsafe fn attribute_writeback(typeinfo: *const ()) { unsafe fn attribute_writeback(typeinfo: *const ()) {
struct Attr { struct Attr {
offset: usize, offset: usize,
@ -65,8 +61,8 @@ unsafe fn attribute_writeback(typeinfo: *const ()) {
} }
} }
struct KernelImage { pub struct KernelImage {
library: Library, library: UnsafeCell<Library>,
__modinit__: u32, __modinit__: u32,
typeinfo: Option<u32>, typeinfo: Option<u32>,
} }
@ -89,21 +85,21 @@ impl KernelImage {
} }
Ok(KernelImage { Ok(KernelImage {
library, library: UnsafeCell::new(library),
__modinit__, __modinit__,
typeinfo, typeinfo,
}) })
} }
pub fn get_library_ptr(&mut self) -> *mut Library { pub unsafe fn rebind(&self, name: &[u8], addr: *const ()) -> Result<(), dyld::Error> {
&mut self.library as *mut Library let library = self.library.get().as_mut().unwrap();
library.rebind(name, addr)
} }
pub unsafe fn exec(&mut self) { pub unsafe fn exec(&self) {
// Flush data cache entries for the image in DDR, including // Flush data cache entries for the image in DDR, including
// Memory/Instruction Synchronization Barriers // Memory/Instruction Synchronization Barriers
dcci_slice(self.library.image.data); dcci_slice(self.library.get().as_ref().unwrap().image.data);
dsb();
iciallu(); iciallu();
bpiall(); bpiall();
dsb(); dsb();
@ -115,6 +111,12 @@ impl KernelImage {
attribute_writeback(typeinfo as *const ()); attribute_writeback(typeinfo as *const ());
} }
} }
pub fn get_load_addr(&self) -> usize {
unsafe {
self.library.get().as_ref().unwrap().image.as_ptr() as usize
}
}
} }
#[no_mangle] #[no_mangle]
@ -148,11 +150,7 @@ pub fn main_core1() {
let result = dyld::load(&data, &resolve) let result = dyld::load(&data, &resolve)
.and_then(KernelImage::new); .and_then(KernelImage::new);
match result { match result {
Ok(mut kernel) => { Ok(kernel) => {
unsafe {
KERNEL_LOAD_ADDR = kernel.library.image.as_ptr() as usize;
KERNEL_LIBRARY = kernel.get_library_ptr();
}
loaded_kernel = Some(kernel); loaded_kernel = Some(kernel);
debug!("kernel loaded"); debug!("kernel loaded");
core1_tx.send(Message::LoadCompleted); core1_tx.send(Message::LoadCompleted);
@ -165,14 +163,16 @@ pub fn main_core1() {
}, },
Message::StartRequest => { Message::StartRequest => {
info!("kernel starting"); info!("kernel starting");
if let Some(mut kernel) = loaded_kernel.take() { if let Some(kernel) = loaded_kernel.take() {
core::mem::replace(&mut *KERNEL_CHANNEL_0TO1.lock(), Some(core1_rx));
core::mem::replace(&mut *KERNEL_CHANNEL_1TO0.lock(), Some(core1_tx));
unsafe { unsafe {
KERNEL_CHANNEL_0TO1 = mem::transmute(&mut core1_rx); KERNEL_IMAGE = &kernel as *const KernelImage;
KERNEL_CHANNEL_1TO0 = mem::transmute(&mut core1_tx);
kernel.exec(); kernel.exec();
KERNEL_CHANNEL_0TO1 = ptr::null_mut(); KERNEL_IMAGE = ptr::null();
KERNEL_CHANNEL_1TO0 = ptr::null_mut();
} }
core1_rx = core::mem::replace(&mut *KERNEL_CHANNEL_0TO1.lock(), None).unwrap();
core1_tx = core::mem::replace(&mut *KERNEL_CHANNEL_1TO0.lock(), None).unwrap();
} }
info!("kernel finished"); info!("kernel finished");
core1_tx.send(Message::KernelFinished); core1_tx.send(Message::KernelFinished);
@ -185,7 +185,7 @@ pub fn main_core1() {
/// Called by eh_artiq /// Called by eh_artiq
pub fn terminate(exception: &'static eh_artiq::Exception<'static>, backtrace: &'static mut [usize]) -> ! { pub fn terminate(exception: &'static eh_artiq::Exception<'static>, backtrace: &'static mut [usize]) -> ! {
let load_addr = unsafe { let load_addr = unsafe {
KERNEL_LOAD_ADDR KERNEL_IMAGE.as_ref().unwrap().get_load_addr()
}; };
let mut cursor = 0; let mut cursor = 0;
// The address in the backtrace is relocated, so we have to convert it back to the address in // The address in the backtrace is relocated, so we have to convert it back to the address in
@ -197,8 +197,10 @@ pub fn terminate(exception: &'static eh_artiq::Exception<'static>, backtrace: &'
} }
} }
let core1_tx: &mut sync_channel::Sender<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; {
core1_tx.send(Message::KernelException(exception, &backtrace[..cursor])); let mut core1_tx = KERNEL_CHANNEL_1TO0.lock();
core1_tx.as_mut().unwrap().send(Message::KernelException(exception, &backtrace[..cursor]));
}
// TODO: remove after implementing graceful kernel termination. // TODO: remove after implementing graceful kernel termination.
error!("Core1 uncaught exception"); error!("Core1 uncaught exception");
loop {} loop {}

View File

@ -5,7 +5,7 @@ use crate::{
}; };
use alloc::{vec::Vec, string::String, collections::BTreeMap, str}; use alloc::{vec::Vec, string::String, collections::BTreeMap, str};
use cslice::CSlice; use cslice::CSlice;
use super::KERNEL_LIBRARY; use super::KERNEL_IMAGE;
use core::mem; use core::mem;
use log::debug; use log::debug;
@ -136,7 +136,7 @@ pub extern fn dma_record_start(name: CSlice<u8>) {
artiq_raise!("DMAError", "DMA is already recording") artiq_raise!("DMAError", "DMA is already recording")
} }
let library = KERNEL_LIBRARY.as_mut().unwrap(); let library = KERNEL_IMAGE.as_ref().unwrap();
library.rebind(b"rtio_output", library.rebind(b"rtio_output",
dma_record_output as *const ()).unwrap(); dma_record_output as *const ()).unwrap();
library.rebind(b"rtio_output_wide", library.rebind(b"rtio_output_wide",
@ -156,7 +156,7 @@ pub extern fn dma_record_stop(duration: i64) {
artiq_raise!("DMAError", "DMA is not recording") artiq_raise!("DMAError", "DMA is not recording")
} }
let library = KERNEL_LIBRARY.as_mut().unwrap(); let library = KERNEL_IMAGE.as_ref().unwrap();
library.rebind(b"rtio_output", library.rebind(b"rtio_output",
rtio::output as *const ()).unwrap(); rtio::output as *const ()).unwrap();
library.rebind(b"rtio_output_wide", library.rebind(b"rtio_output_wide",

View File

@ -1,7 +1,6 @@
use core::ptr; use core::ptr;
use alloc::{vec::Vec, sync::Arc, string::String}; use alloc::{vec::Vec, sync::Arc, string::String};
use dyld::Library;
use libcortex_a9::{mutex::Mutex, sync_channel}; use libcortex_a9::{mutex::Mutex, sync_channel};
use crate::eh_artiq; use crate::eh_artiq;
@ -39,7 +38,8 @@ pub enum Message {
static CHANNEL_0TO1: Mutex<Option<sync_channel::Receiver<Message>>> = Mutex::new(None); static CHANNEL_0TO1: Mutex<Option<sync_channel::Receiver<Message>>> = Mutex::new(None);
static CHANNEL_1TO0: Mutex<Option<sync_channel::Sender<Message>>> = Mutex::new(None); static CHANNEL_1TO0: Mutex<Option<sync_channel::Sender<Message>>> = Mutex::new(None);
static mut KERNEL_CHANNEL_0TO1: *mut () = ptr::null_mut(); static KERNEL_CHANNEL_0TO1: Mutex<Option<sync_channel::Receiver<Message>>> = Mutex::new(None);
static mut KERNEL_CHANNEL_1TO0: *mut () = ptr::null_mut(); static KERNEL_CHANNEL_1TO0: Mutex<Option<sync_channel::Sender<Message>>> = Mutex::new(None);
static mut KERNEL_LIBRARY: *mut Library = ptr::null_mut();
static mut KERNEL_IMAGE: *const core1::KernelImage = ptr::null();

View File

@ -1,10 +1,8 @@
//! Kernel-side RPC API //! Kernel-side RPC API
use core::mem;
use alloc::{vec::Vec, sync::Arc}; use alloc::{vec::Vec, sync::Arc};
use cslice::{CSlice, AsCSlice}; use cslice::{CSlice, AsCSlice};
use libcortex_a9::sync_channel;
use crate::eh_artiq; use crate::eh_artiq;
use crate::rpc::send_args; use crate::rpc::send_args;
use super::{ use super::{
@ -13,10 +11,10 @@ use super::{
}; };
fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) { fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice<u8>, data: *const *const ()) {
let core1_tx: &mut sync_channel::Sender<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; let mut core1_tx = KERNEL_CHANNEL_1TO0.lock();
let mut buffer = Vec::<u8>::new(); let mut buffer = Vec::<u8>::new();
send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed"); send_args(&mut buffer, service, tag.as_ref(), data).expect("RPC encoding failed");
core1_tx.send(Message::RpcSend { is_async: is_async, data: Arc::new(buffer) }); core1_tx.as_mut().unwrap().send(Message::RpcSend { is_async, data: Arc::new(buffer) });
} }
pub extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) { pub extern fn rpc_send(service: u32, tag: &CSlice<u8>, data: *const *const ()) {
@ -28,10 +26,12 @@ pub extern fn rpc_send_async(service: u32, tag: &CSlice<u8>, data: *const *const
} }
pub extern fn rpc_recv(slot: *mut ()) -> usize { pub extern fn rpc_recv(slot: *mut ()) -> usize {
let core1_rx: &mut sync_channel::Receiver<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_0TO1) }; let reply = {
let core1_tx: &mut sync_channel::Sender<Message> = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; let mut core1_rx = KERNEL_CHANNEL_0TO1.lock();
core1_tx.send(Message::RpcRecvRequest(slot)); let mut core1_tx = KERNEL_CHANNEL_1TO0.lock();
let reply = core1_rx.recv(); core1_tx.as_mut().unwrap().send(Message::RpcRecvRequest(slot));
core1_rx.as_mut().unwrap().recv()
};
match *reply { match *reply {
Message::RpcRecvReply(Ok(alloc_size)) => alloc_size, Message::RpcRecvReply(Ok(alloc_size)) => alloc_size,
Message::RpcRecvReply(Err(exception)) => unsafe { Message::RpcRecvReply(Err(exception)) => unsafe {