use core::{ptr, mem}; use log::{debug, error}; use alloc::{vec::Vec, sync::Arc}; use cslice::CSlice; use libcortex_a9::{mutex::Mutex, sync_channel::{self, sync_channel}}; use libsupport_zynq::boot::Core1; use dyld; use crate::rpc; use crate::rtio; #[derive(Debug)] pub enum Message { LoadRequest(Arc>), LoadCompleted, LoadFailed, StartRequest, KernelFinished, RpcSend { is_async: bool, data: Arc> }, RpcRecvRequest(*mut ()), RpcRecvReply(Result), } static CHANNEL_0TO1: Mutex>> = Mutex::new(None); static CHANNEL_1TO0: Mutex>> = Mutex::new(None); pub struct Control { core1: Core1, pub tx: sync_channel::Sender, pub rx: sync_channel::Receiver, } impl Control { pub fn start() -> Self { let core1 = Core1::start(true); let (core0_tx, core1_rx) = sync_channel(4); let (core1_tx, core0_rx) = sync_channel(4); *CHANNEL_0TO1.lock() = Some(core1_rx); *CHANNEL_1TO0.lock() = Some(core1_tx); Control { core1, tx: core0_tx, rx: core0_rx, } } pub fn restart(&mut self) { *CHANNEL_0TO1.lock() = None; *CHANNEL_1TO0.lock() = None; self.core1.restart(); let (core0_tx, core1_rx) = sync_channel(4); let (core1_tx, core0_rx) = sync_channel(4); *CHANNEL_0TO1.lock() = Some(core1_rx); *CHANNEL_1TO0.lock() = Some(core1_tx); self.tx = core0_tx; self.rx = core0_rx; } } static mut KERNEL_CHANNEL_0TO1: *mut () = ptr::null_mut(); static mut KERNEL_CHANNEL_1TO0: *mut () = ptr::null_mut(); fn rpc_send_common(is_async: bool, service: u32, tag: &CSlice, data: *const *const ()) { let core1_tx: &mut sync_channel::Sender = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; let mut buffer = Vec::::new(); rpc::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) }); } extern fn rpc_send(service: u32, tag: &CSlice, data: *const *const ()) { rpc_send_common(false, service, tag, data); } extern fn rpc_send_async(service: u32, tag: &CSlice, data: *const *const ()) { rpc_send_common(true, service, tag, data); } unsafe fn attribute_writeback(typeinfo: *const ()) { struct Attr { offset: usize, tag: CSlice<'static, u8>, name: CSlice<'static, u8> } struct Type { attributes: *const *const Attr, objects: *const *const () } let mut tys = typeinfo as *const *const Type; while !(*tys).is_null() { let ty = *tys; tys = tys.offset(1); let mut objects = (*ty).objects; while !(*objects).is_null() { let object = *objects; objects = objects.offset(1); let mut attributes = (*ty).attributes; while !(*attributes).is_null() { let attribute = *attributes; attributes = attributes.offset(1); if (*attribute).tag.len() > 0 { rpc_send_async(0, &(*attribute).tag, [ &object as *const _ as *const (), &(*attribute).name as *const _ as *const (), (object as usize + (*attribute).offset) as *const () ].as_ptr()); } } } } } extern fn rpc_recv(slot: *mut ()) -> usize { let core1_rx: &mut sync_channel::Receiver = unsafe { mem::transmute(KERNEL_CHANNEL_0TO1) }; let core1_tx: &mut sync_channel::Sender = unsafe { mem::transmute(KERNEL_CHANNEL_1TO0) }; core1_tx.send(Message::RpcRecvRequest(slot)); let reply = core1_rx.recv(); match *reply { Message::RpcRecvReply(Ok(alloc_size)) => alloc_size, Message::RpcRecvReply(Err(_)) => unimplemented!(), _ => panic!("received unexpected reply to RpcRecvRequest: {:?}", reply) } } extern fn exception_unimplemented() { unimplemented!(); } macro_rules! api { ($i:ident) => ({ extern { static $i: u8; } unsafe { api!($i = &$i as *const _) } }); ($i:ident, $d:item) => ({ $d api!($i = $i) }); ($i:ident = $e:expr) => { (stringify!($i), $e as *const ()) } } fn resolve(required: &[u8]) -> Option { let api = &[ api!(now_mu = rtio::now_mu), api!(at_mu = rtio::at_mu), api!(delay_mu = rtio::delay_mu), api!(rpc_send = rpc_send), api!(rpc_send_async = rpc_send_async), api!(rpc_recv = rpc_recv), api!(rtio_init = rtio::init), api!(rtio_get_destination_status = rtio::get_destination_status), api!(rtio_get_counter = rtio::get_counter), api!(rtio_output = rtio::output), api!(rtio_output_wide = rtio::output_wide), api!(rtio_input_timestamp = rtio::input_timestamp), api!(rtio_input_data = rtio::input_data), api!(rtio_input_timestamped_data = rtio::input_timestamped_data), api!(__aeabi_l2d), api!(_Unwind_Resume = exception_unimplemented), api!(__artiq_personality = exception_unimplemented), api!(__artiq_raise = exception_unimplemented), api!(__artiq_reraise = exception_unimplemented), ]; api.iter() .find(|&&(exported, _)| exported.as_bytes() == required) .map(|&(_, ptr)| ptr as u32) } #[no_mangle] pub fn main_core1() { debug!("Core1 started"); unsafe { llvm_asm!(" mrc p15, 0, r1, c1, c0, 2 orr r1, r1, (0b1111<<20) mcr p15, 0, r1, c1, c0, 2 vmrs r1, fpexc orr r1, r1, (1<<30) vmsr fpexc, r1 ":::"r1"); } debug!("FPU enabled on Core1"); let mut core1_tx = None; while core1_tx.is_none() { core1_tx = CHANNEL_1TO0.lock().take(); } let mut core1_tx = core1_tx.unwrap(); let mut core1_rx = None; while core1_rx.is_none() { core1_rx = CHANNEL_0TO1.lock().take(); } let mut core1_rx = core1_rx.unwrap(); let mut current_modinit: Option = None; let mut current_typeinfo: Option = None; loop { let message = core1_rx.recv(); match *message { Message::LoadRequest(data) => { match dyld::load(&data, &resolve) { Ok(library) => { let bss_start = library.lookup(b"__bss_start"); let end = library.lookup(b"_end"); if let Some(bss_start) = bss_start { let end = end.unwrap(); unsafe { ptr::write_bytes(bss_start as *mut u8, 0, (end - bss_start) as usize); } } let __modinit__ = library.lookup(b"__modinit__").unwrap(); current_modinit = Some(__modinit__); current_typeinfo = library.lookup(b"typeinfo"); debug!("kernel loaded"); core1_tx.send(Message::LoadCompleted); }, Err(error) => { error!("failed to load shared library: {}", error); core1_tx.send(Message::LoadFailed); } } }, Message::StartRequest => { debug!("kernel starting"); if let Some(__modinit__) = current_modinit { unsafe { KERNEL_CHANNEL_0TO1 = mem::transmute(&mut core1_rx); KERNEL_CHANNEL_1TO0 = mem::transmute(&mut core1_tx); (mem::transmute::(__modinit__))(); if let Some(typeinfo) = current_typeinfo { attribute_writeback(typeinfo as *const ()); } KERNEL_CHANNEL_0TO1 = ptr::null_mut(); KERNEL_CHANNEL_1TO0 = ptr::null_mut(); } } debug!("kernel finished"); core1_tx.send(Message::KernelFinished); } _ => error!("Core1 received unexpected message: {:?}", message), } } }