From 8ed57a84bf323d3b84a8ac8d9450104300f61462 Mon Sep 17 00:00:00 2001 From: Brad Campbell Date: Thu, 28 Jun 2018 16:14:50 -0400 Subject: [PATCH] PR #1046 --- boards/ek-tm4c1294xl/src/main.rs | 43 ++- boards/hail/src/main.rs | 44 ++- boards/imix/src/main.rs | 40 +- boards/launchxl/src/main.rs | 42 ++- boards/nordic/nrf51dk/src/main.rs | 43 ++- boards/nordic/nrf52dk_base/src/lib.rs | 41 ++- capsules/README.md | 1 + capsules/src/lib.rs | 1 + capsules/src/virtual_uart.rs | 190 ++++++++++ kernel/src/callback.rs | 75 +--- kernel/src/debug.rs | 510 ++++++++++++++------------ kernel/src/grant.rs | 163 +++----- 12 files changed, 744 insertions(+), 449 deletions(-) create mode 100644 capsules/src/virtual_uart.rs diff --git a/boards/ek-tm4c1294xl/src/main.rs b/boards/ek-tm4c1294xl/src/main.rs index b64b7a9820..0fccf2ad65 100644 --- a/boards/ek-tm4c1294xl/src/main.rs +++ b/boards/ek-tm4c1294xl/src/main.rs @@ -12,6 +12,7 @@ extern crate cortexm4; extern crate tm4c129x; use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; +use capsules::virtual_uart::{UartDevice, UartMux}; use kernel::hil; use kernel::hil::Controller; use kernel::Platform; @@ -43,7 +44,7 @@ pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000]; /// A structure representing this platform that holds references to all /// capsules for this platform. struct EkTm4c1294xl { - console: &'static capsules::console::Console<'static, tm4c129x::uart::UART>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, alarm: &'static capsules::alarm::AlarmDriver< 'static, VirtualMuxAlarm<'static, tm4c129x::gpt::AlarmTimer>, @@ -80,19 +81,49 @@ pub unsafe fn reset_handler() { tm4c129x::sysctl::PSYSCTLM .setup_system_clock(tm4c129x::sysctl::SystemClockSource::PllPioscAt120MHz); + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&tm4c129x::uart::UART0, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&tm4c129x::uart::UART0, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); + let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &tm4c129x::uart::UART0, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - hil::uart::UART::set_client(&tm4c129x::uart::UART0, console); + hil::uart::UART::set_client(console_uart, console); tm4c129x::uart::UART0.specify_pins(&tm4c129x::gpio::PA[0], &tm4c129x::gpio::PA[1]); + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); + // Alarm let alarm_timer = &tm4c129x::gpt::TIMER0; let mux_alarm = static_init!( @@ -193,10 +224,6 @@ pub unsafe fn reset_handler() { tm4c1294.console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(tm4c1294.console), kc); - debug!("Initialization complete. Entering main loop...\r"); let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new()); diff --git a/boards/hail/src/main.rs b/boards/hail/src/main.rs index 47f35043ae..5f58432f06 100644 --- a/boards/hail/src/main.rs +++ b/boards/hail/src/main.rs @@ -18,6 +18,7 @@ extern crate sam4l; use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; use capsules::virtual_i2c::{I2CDevice, MuxI2C}; use capsules::virtual_spi::{MuxSpiMaster, VirtualSpiMasterDevice}; +use capsules::virtual_uart::{UartDevice, UartMux}; use kernel::hil; use kernel::hil::spi::SpiMaster; use kernel::hil::Controller; @@ -60,7 +61,7 @@ pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000]; /// A structure representing this platform that holds references to all /// capsules for this platform. struct Hail { - console: &'static capsules::console::Console<'static, sam4l::usart::USART>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, gpio: &'static capsules::gpio::GPIO<'static, sam4l::gpio::GPIOPin>, alarm: &'static capsules::alarm::AlarmDriver< 'static, @@ -200,17 +201,27 @@ pub unsafe fn reset_handler() { let mut chip = sam4l::chip::Sam4l::new(); + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&sam4l::usart::USART0, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&sam4l::usart::USART0, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &sam4l::usart::USART0, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - hil::uart::UART::set_client(&sam4l::usart::USART0, console); + hil::uart::UART::set_client(console_uart, console); // Create the Nrf51822Serialization driver for passing BLE commands // over UART to the nRF51822 radio. @@ -476,17 +487,34 @@ pub unsafe fn reset_handler() { } sam4l::gpio::PA[17].set(); + // Initialize the UART bus. hail.console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(hail.console), kc); + + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); hail.nrf51822.initialize(); // Uncomment to measure overheads for TakeCell and MapCell: // test_take_map_cell::test_take_map_cell(); - // debug!("Initialization complete. Entering main loop"); + debug!("Initialization complete. Entering main loop"); let board_kernel = static_init!(kernel::Kernel, kernel::Kernel::new()); diff --git a/boards/imix/src/main.rs b/boards/imix/src/main.rs index fac9f02e33..9f69742cb6 100644 --- a/boards/imix/src/main.rs +++ b/boards/imix/src/main.rs @@ -24,6 +24,7 @@ use capsules::rf233::RF233; use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; use capsules::virtual_i2c::{I2CDevice, MuxI2C}; use capsules::virtual_spi::{MuxSpiMaster, VirtualSpiMasterDevice}; +use capsules::virtual_uart::{UartDevice, UartMux}; use kernel::hil; use kernel::hil::radio; use kernel::hil::radio::{RadioConfig, RadioData}; @@ -82,7 +83,7 @@ type RF233Device = capsules::rf233::RF233<'static, VirtualSpiMasterDevice<'static, sam4l::spi::SpiHw>>; struct Imix { - console: &'static capsules::console::Console<'static, sam4l::usart::USART>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, gpio: &'static capsules::gpio::GPIO<'static, sam4l::gpio::GPIOPin>, alarm: &'static AlarmDriver<'static, VirtualMuxAlarm<'static, sam4l::ast::Ast<'static>>>, temp: &'static capsules::temperature::TemperatureSensor<'static>, @@ -255,22 +256,47 @@ pub unsafe fn reset_handler() { // # CONSOLE + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&sam4l::usart::USART3, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&sam4l::usart::USART3, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &sam4l::usart::USART3, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - hil::uart::UART::set_client(&sam4l::usart::USART3, console); + hil::uart::UART::set_client(console_uart, console); console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(console), kc); + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); // Create the Nrf51822Serialization driver for passing BLE commands // over UART to the nRF51822 radio. diff --git a/boards/launchxl/src/main.rs b/boards/launchxl/src/main.rs index aec1dc91a4..fbb72725d6 100644 --- a/boards/launchxl/src/main.rs +++ b/boards/launchxl/src/main.rs @@ -12,8 +12,10 @@ extern crate cc26xx; #[macro_use(debug, debug_gpio, static_init)] extern crate kernel; +use capsules::virtual_uart::{UartDevice, UartMux}; use cc26xx::aon; use cc26xx::prcm; +use kernel::hil; #[macro_use] pub mod io; @@ -38,7 +40,7 @@ pub static mut STACK_MEMORY: [u8; 0x1000] = [0; 0x1000]; pub struct Platform { gpio: &'static capsules::gpio::GPIO<'static, cc26xx::gpio::GPIOPin>, led: &'static capsules::led::LED<'static, cc26xx::gpio::GPIOPin>, - console: &'static capsules::console::Console<'static, cc26xx::uart::UART>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, button: &'static capsules::button::Button<'static, cc26xx::gpio::GPIOPin>, alarm: &'static capsules::alarm::AlarmDriver< 'static, @@ -125,23 +127,49 @@ pub unsafe fn reset_handler() { } // UART + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&cc26xx::uart::UART0, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&cc26xx::uart::UART0, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); + cc26xx::uart::UART0.set_pins(3, 2); let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &cc26xx::uart::UART0, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - kernel::hil::uart::UART::set_client(&cc26xx::uart::UART0, console); + kernel::hil::uart::UART::set_client(console_uart, console); console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(console), kc); + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); // Setup for remaining GPIO pins let gpio_pins = static_init!( diff --git a/boards/nordic/nrf51dk/src/main.rs b/boards/nordic/nrf51dk/src/main.rs index 6acff666b1..c2543e06fb 100644 --- a/boards/nordic/nrf51dk/src/main.rs +++ b/boards/nordic/nrf51dk/src/main.rs @@ -57,6 +57,8 @@ extern crate nrf5x; use capsules::alarm::AlarmDriver; use capsules::virtual_alarm::{MuxAlarm, VirtualMuxAlarm}; +use capsules::virtual_uart::{UartDevice, UartMux}; +use kernel::hil; use kernel::hil::uart::UART; use kernel::{Chip, SysTick}; use nrf5x::pinmux::Pinmux; @@ -106,7 +108,7 @@ pub struct Platform { VirtualMuxAlarm<'static, Rtc>, >, button: &'static capsules::button::Button<'static, nrf5x::gpio::GPIOPin>, - console: &'static capsules::console::Console<'static, nrf51::uart::UART>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, gpio: &'static capsules::gpio::GPIO<'static, nrf5x::gpio::GPIOPin>, led: &'static capsules::led::LED<'static, nrf5x::gpio::GPIOPin>, temp: &'static capsules::temperature::TemperatureSensor<'static>, @@ -235,22 +237,49 @@ pub unsafe fn reset_handler() { Pinmux::new(10), /* cts */ Pinmux::new(8), /*. rts */ ); + + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&nrf51::uart::UART0, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&nrf51::uart::UART0, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); + let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &nrf51::uart::UART0, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - UART::set_client(&nrf51::uart::UART0, console); + UART::set_client(console_uart, console); console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(console), kc); + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); let rtc = &nrf5x::rtc::RTC; rtc.start(); diff --git a/boards/nordic/nrf52dk_base/src/lib.rs b/boards/nordic/nrf52dk_base/src/lib.rs index 6b6e889257..2c47ec3e4e 100644 --- a/boards/nordic/nrf52dk_base/src/lib.rs +++ b/boards/nordic/nrf52dk_base/src/lib.rs @@ -11,6 +11,7 @@ extern crate nrf5x; use capsules::virtual_alarm::VirtualMuxAlarm; use capsules::virtual_spi::MuxSpiMaster; +use capsules::virtual_uart::{UartDevice, UartMux}; use kernel::hil; use nrf5x::rtc::Rtc; @@ -69,7 +70,7 @@ pub struct Platform { VirtualMuxAlarm<'static, Rtc>, >, button: &'static capsules::button::Button<'static, nrf5x::gpio::GPIOPin>, - console: &'static capsules::console::Console<'static, nrf52::uart::Uarte>, + console: &'static capsules::console::Console<'static, UartDevice<'static>>, gpio: &'static capsules::gpio::GPIO<'static, nrf5x::gpio::GPIOPin>, led: &'static capsules::led::LED<'static, nrf5x::gpio::GPIOPin>, rng: &'static capsules::rng::SimpleRng<'static, nrf5x::trng::Trng<'static>>, @@ -192,6 +193,17 @@ pub unsafe fn setup_board( capsules::virtual_alarm::VirtualMuxAlarm::new(mux_alarm) ); + // Create a shared UART channel for the console and for kernel debug. + let uart_mux = static_init!( + UartMux<'static>, + UartMux::new(&nrf52::uart::UARTE0, &mut capsules::virtual_uart::RX_BUF) + ); + hil::uart::UART::set_client(&nrf52::uart::UARTE0, uart_mux); + + // Create a UartDevice for the console. + let console_uart = static_init!(UartDevice, UartDevice::new(uart_mux, true)); + console_uart.setup(); + nrf52::uart::UARTE0.configure( nrf5x::pinmux::Pinmux::new(uart_pins.txd as u32), nrf5x::pinmux::Pinmux::new(uart_pins.rxd as u32), @@ -199,21 +211,36 @@ pub unsafe fn setup_board( nrf5x::pinmux::Pinmux::new(uart_pins.rts as u32), ); let console = static_init!( - capsules::console::Console, + capsules::console::Console, capsules::console::Console::new( - &nrf52::uart::UARTE0, + console_uart, 115200, &mut capsules::console::WRITE_BUF, &mut capsules::console::READ_BUF, kernel::Grant::create() ) ); - kernel::hil::uart::UART::set_client(&nrf52::uart::UARTE0, console); + kernel::hil::uart::UART::set_client(console_uart, console); console.initialize(); - // Attach the kernel debug interface to this console - let kc = static_init!(capsules::console::App, capsules::console::App::default()); - kernel::debug::assign_console_driver(Some(console), kc); + // Create virtual device for kernel debug. + let debugger_uart = static_init!(UartDevice, UartDevice::new(uart_mux, false)); + debugger_uart.setup(); + let debugger = static_init!( + kernel::debug::DebugWriter, + kernel::debug::DebugWriter::new( + debugger_uart, + &mut kernel::debug::OUTPUT_BUF, + &mut kernel::debug::INTERNAL_BUF, + ) + ); + hil::uart::UART::set_client(debugger_uart, debugger); + + let debug_wrapper = static_init!( + kernel::debug::DebugWriterWrapper, + kernel::debug::DebugWriterWrapper::new(debugger) + ); + kernel::debug::set_debug_writer_wrapper(debug_wrapper); let ble_radio = static_init!( capsules::ble_advertising_driver::BLE< diff --git a/capsules/README.md b/capsules/README.md index 3d547c22c2..30c4d6b4a7 100644 --- a/capsules/README.md +++ b/capsules/README.md @@ -114,6 +114,7 @@ These allow for multiple users of shared hardware resources in the kernel. - **[Virtual Flash](src/virtual_flash.rs)**: Shared flash resource. - **[Virtual I2C](src/virtual_i2c.rs)**: Shared I2C and fixed addresses. - **[Virtual SPI](src/virtual_spi.rs)**: Shared SPI and fixed chip select pins. +- **[Virtual UART](src/virtual_uart.rs)**: Shared UART bus. ### Utility Capsules diff --git a/capsules/src/lib.rs b/capsules/src/lib.rs index 318dc22568..4766362bb9 100644 --- a/capsules/src/lib.rs +++ b/capsules/src/lib.rs @@ -59,3 +59,4 @@ pub mod virtual_alarm; pub mod virtual_flash; pub mod virtual_i2c; pub mod virtual_spi; +pub mod virtual_uart; diff --git a/capsules/src/virtual_uart.rs b/capsules/src/virtual_uart.rs new file mode 100644 index 0000000000..520820fc7b --- /dev/null +++ b/capsules/src/virtual_uart.rs @@ -0,0 +1,190 @@ +//! Virtualize a UART bus. +//! +//! This allows multiple Tock capsules to use the same UART bus. This is likely +//! most useful for `printf()` like applications where multiple things want to +//! write to the same UART channel. +//! +//! Clients can choose if they want to receive. Incoming messages will be sent +//! to all clients that have enabled receiving. +//! +//! `UartMux` provides shared access to a single UART bus for multiple users. +//! `UartDevice` provides access for a single client. + +use core::cell::Cell; +use core::cmp; + +use kernel::common::cells::{OptionalCell, TakeCell}; +use kernel::common::{List, ListLink, ListNode}; +use kernel::hil; + +pub static mut RX_BUF: [u8; 64] = [0; 64]; + +pub struct UartMux<'a> { + uart: &'a hil::uart::UART, + devices: List<'a, UartDevice<'a>>, + receive_in_progress: Cell, + inflight: OptionalCell<&'a UartDevice<'a>>, + rx_buffer: TakeCell<'static, [u8]>, +} + +impl<'a> hil::uart::Client for UartMux<'a> { + fn transmit_complete(&self, tx_buffer: &'static mut [u8], error: hil::uart::Error) { + self.inflight.map(move |device| { + self.inflight.clear(); + device.transmit_complete(tx_buffer, error); + }); + self.do_next_op(); + } + + fn receive_complete( + &self, + rx_buffer: &'static mut [u8], + rx_len: usize, + error: hil::uart::Error, + ) { + // Pass the data to each receiver that wants to receive messages. + self.devices.iter().for_each(|device| { + if device.receiver { + device.rx_buffer.take().map(|rxbuf| { + let len = cmp::min(rx_len, device.rx_len.get()); + for i in 0..len { + rxbuf[i] = rx_buffer[i]; + } + device.receive_complete(rxbuf, len, error); + }); + } + }); + self.rx_buffer.replace(rx_buffer); + self.receive_in_progress.set(false); + } +} + +impl<'a> UartMux<'a> { + pub fn new(uart: &'a hil::uart::UART, rx_buffer: &'static mut [u8]) -> UartMux<'a> { + UartMux { + uart: uart, + devices: List::new(), + receive_in_progress: Cell::new(false), + inflight: OptionalCell::empty(), + rx_buffer: TakeCell::new(rx_buffer), + } + } + + fn do_next_op(&self) { + if self.inflight.is_none() { + let mnode = self.devices.iter().find(|node| node.operation.is_some()); + mnode.map(|node| { + node.tx_buffer.take().map(|buf| { + node.operation.map(move |op| match op { + Operation::Transmit { len } => self.uart.transmit(buf, *len), + }); + }); + node.operation.clear(); + self.inflight.set(node); + }); + } + } + + /// If we are not currently listening, start listening. + fn start_receive(&self, rx_len: usize) { + if self.receive_in_progress.get() == false { + self.rx_buffer.take().map(|rxbuf| { + self.receive_in_progress.set(true); + let len = cmp::min(rx_len, rxbuf.len()); + self.uart.receive(rxbuf, len); + }); + } + } +} + +#[derive(Copy, Clone, PartialEq)] +enum Operation { + Transmit { len: usize }, +} + +pub struct UartDevice<'a> { + mux: &'a UartMux<'a>, + receiver: bool, // Whether or not to pass this UartDevice incoming messages. + tx_buffer: TakeCell<'static, [u8]>, + rx_buffer: TakeCell<'static, [u8]>, + rx_len: Cell, + operation: OptionalCell, + next: ListLink<'a, UartDevice<'a>>, + client: OptionalCell<&'a hil::uart::Client>, +} + +impl<'a> UartDevice<'a> { + pub const fn new(mux: &'a UartMux<'a>, receiver: bool) -> UartDevice<'a> { + UartDevice { + mux: mux, + receiver: receiver, + tx_buffer: TakeCell::empty(), + rx_buffer: TakeCell::empty(), + rx_len: Cell::new(0), + operation: OptionalCell::empty(), + next: ListLink::empty(), + client: OptionalCell::empty(), + } + } + + /// Must be called right after `static_init!()`. + pub fn setup(&'a self) { + self.mux.devices.push_head(self); + } +} + +impl<'a> hil::uart::Client for UartDevice<'a> { + fn transmit_complete(&self, tx_buffer: &'static mut [u8], error: hil::uart::Error) { + self.client.map(move |client| { + client.transmit_complete(tx_buffer, error); + }); + } + + fn receive_complete( + &self, + rx_buffer: &'static mut [u8], + rx_len: usize, + error: hil::uart::Error, + ) { + self.client.map(move |client| { + client.receive_complete(rx_buffer, rx_len, error); + }); + } +} + +impl<'a> ListNode<'a, UartDevice<'a>> for UartDevice<'a> { + fn next(&'a self) -> &'a ListLink<'a, UartDevice<'a>> { + &self.next + } +} + +impl<'a> hil::uart::UART for UartDevice<'a> { + fn set_client(&self, client: &'a hil::uart::Client) { + self.client.set(client); + } + + // Ideally this wouldn't be here, and if we ever create a "UartDevice" trait + // in the HIL then this could be removed. + fn init(&self, params: hil::uart::UARTParams) { + self.mux.uart.init(params); + } + + /// Transmit data. + fn transmit(&self, tx_data: &'static mut [u8], tx_len: usize) { + self.tx_buffer.replace(tx_data); + self.operation.set(Operation::Transmit { len: tx_len }); + self.mux.do_next_op(); + } + + /// Receive data until buffer is full. + fn receive(&self, rx_buffer: &'static mut [u8], rx_len: usize) { + self.rx_buffer.replace(rx_buffer); + self.rx_len.set(rx_len); + self.mux.start_receive(rx_len); + } + + // It is hard to generate the callback, so let's just ignore this. + fn abort_receive(&self) { + self.mux.uart.abort_receive(); + } +} diff --git a/kernel/src/callback.rs b/kernel/src/callback.rs index a900c17442..783df0df99 100644 --- a/kernel/src/callback.rs +++ b/kernel/src/callback.rs @@ -9,27 +9,11 @@ pub struct AppId { idx: usize, } -/// The kernel can masquerade as an app. IDs >= this value are the kernel. -/// These IDs are used to identify which kernel container is being accessed. -const KERNEL_APPID_BOUNDARY: usize = 100; - impl AppId { crate fn new(idx: usize) -> AppId { AppId { idx: idx } } - crate const fn kernel_new(idx: usize) -> AppId { - AppId { idx: idx } - } - - pub const fn is_kernel(self) -> bool { - self.idx >= KERNEL_APPID_BOUNDARY - } - - pub const fn is_kernel_idx(idx: usize) -> bool { - idx >= KERNEL_APPID_BOUNDARY - } - pub fn idx(&self) -> usize { self.idx } @@ -39,22 +23,12 @@ impl AppId { } } -#[derive(Clone, Copy, Debug)] -crate enum RustOrRawFnPtr { - Raw { - ptr: NonNull<*mut ()>, - }, - Rust { - func: fn(usize, usize, usize, usize), - }, -} - /// Wrapper around a function pointer. #[derive(Clone, Copy, Debug)] pub struct Callback { app_id: AppId, appdata: usize, - fn_ptr: RustOrRawFnPtr, + fn_ptr: NonNull<*mut ()>, } impl Callback { @@ -62,45 +36,20 @@ impl Callback { Callback { app_id: appid, appdata: appdata, - fn_ptr: RustOrRawFnPtr::Raw { ptr: fn_ptr }, - } - } - - crate const fn kernel_new(appid: AppId, fn_ptr: fn(usize, usize, usize, usize)) -> Callback { - Callback { - app_id: appid, - appdata: 0, - fn_ptr: RustOrRawFnPtr::Rust { func: fn_ptr }, + fn_ptr: fn_ptr, } } pub fn schedule(&mut self, r0: usize, r1: usize, r2: usize) -> bool { - if self.app_id.is_kernel() { - let fn_ptr = match self.fn_ptr { - RustOrRawFnPtr::Raw { ptr } => { - panic!("Attempt to rust_call a raw function pointer: ptr {:?}", ptr) - } - RustOrRawFnPtr::Rust { func } => func, - }; - fn_ptr(r0, r1, r2, self.appdata); - true - } else { - let fn_ptr = match self.fn_ptr { - RustOrRawFnPtr::Raw { ptr } => ptr, - RustOrRawFnPtr::Rust { func } => { - panic!("Attempt to schedule rust function: func {:?}", func) - } - }; - process::schedule( - process::FunctionCall { - r0: r0, - r1: r1, - r2: r2, - r3: self.appdata, - pc: fn_ptr.as_ptr() as usize, - }, - self.app_id, - ) - } + process::schedule( + process::FunctionCall { + r0: r0, + r1: r1, + r2: r2, + r3: self.appdata, + pc: self.fn_ptr.as_ptr() as usize, + }, + self.app_id, + ) } } diff --git a/kernel/src/debug.rs b/kernel/src/debug.rs index 1437b096be..fc865cbbcc 100644 --- a/kernel/src/debug.rs +++ b/kernel/src/debug.rs @@ -33,17 +33,18 @@ //! TOCK_DEBUG(0): /tock/capsules/src/sensys.rs:24: got here //! ``` -use callback::{AppId, Callback}; -use core::cmp::min; +use core::cell::Cell; +use core::cmp::{self, min}; use core::fmt::{write, Arguments, Result, Write}; use core::panic::PanicInfo; -use core::ptr::{read_volatile, write_volatile}; -use core::{slice, str}; -use driver::Driver; +use core::ptr; +use core::slice; +use core::str; + +use common::cells::NumericCellExt; +use common::cells::{MapCell, TakeCell}; use hil; -use mem::AppSlice; use process; -use returncode::ReturnCode; /////////////////////////////////////////////////////////////////// // panic! support routines @@ -184,135 +185,169 @@ macro_rules! debug_gpio { /////////////////////////////////////////////////////////////////// // debug! and debug_verbose! support -pub const APPID_IDX: usize = 255; -const BUF_SIZE: usize = 1024; +/// Wrapper type that we need a mutable reference to for the core::fmt::Write +/// interface. +pub struct DebugWriterWrapper { + dw: MapCell<&'static DebugWriter>, +} +/// Main type that we need an immutable reference to so we can share it with +/// the UART provider and this debug module. pub struct DebugWriter { - driver: Option<&'static Driver>, - pub grant: Option<*mut u8>, - output_buffer: [u8; BUF_SIZE], - output_head: usize, - output_tail: usize, - output_active_len: usize, - count: usize, + // What provides the actual writing mechanism. + uart: &'static hil::uart::UART, + // The buffer that is passed to the writing mechanism. + output_buffer: TakeCell<'static, [u8]>, + // An internal buffer that is used to hold debug!() calls as they come in. + internal_buffer: TakeCell<'static, [u8]>, + head: Cell, + tail: Cell, + // How many bytes are being written on the current publish_str call. + active_len: Cell, + // Number of debug!() calls. + count: Cell, +} + +/// Static variable that holds the kernel's reference to the debug tool. This is +/// needed so the debug!() macros have a reference to the object to use. +static mut DEBUG_WRITER: Option<&'static mut DebugWriterWrapper> = None; + +pub static mut OUTPUT_BUF: [u8; 64] = [0; 64]; +pub static mut INTERNAL_BUF: [u8; 1024] = [0; 1024]; + +pub unsafe fn get_debug_writer() -> &'static mut DebugWriterWrapper { + match ptr::read(&DEBUG_WRITER) { + Some(x) => x, + None => panic!(), + } } -static mut DEBUG_WRITER: DebugWriter = DebugWriter { - driver: None, - grant: None, - output_buffer: [0; BUF_SIZE], - output_head: 0, // first valid index in output_buffer - output_tail: 0, // one past last valid index (wraps to 0) - output_active_len: 0, // how big is the current transaction? - count: 0, // how many debug! calls -}; - -pub unsafe fn assign_console_driver(driver: Option<&'static Driver>, grant: &mut T) { - let ptr: *mut u8 = grant as *mut T as *mut u8; - DEBUG_WRITER.driver = driver; - DEBUG_WRITER.grant = Some(ptr); +/// Function used by board main.rs to set a reference to the writer. +pub unsafe fn set_debug_writer_wrapper(debug_writer: &'static mut DebugWriterWrapper) { + DEBUG_WRITER = Some(debug_writer); } -pub unsafe fn get_grant() -> *mut T { - match DEBUG_WRITER.grant { - Some(grant) => grant as *mut T, - None => panic!("Request for unallocated kernel grant"), +impl DebugWriterWrapper { + pub fn new(dw: &'static DebugWriter) -> DebugWriterWrapper { + DebugWriterWrapper { + dw: MapCell::new(dw), + } } } impl DebugWriter { - /// Convenience method that writes (end-start) bytes from bytes into the debug buffer - fn write_buffer(start: usize, end: usize, bytes: &[u8]) { - unsafe { - if end < start { - panic!("wb bounds: start {} end {} bytes {:?}", start, end, bytes); - } - for (dst, src) in DEBUG_WRITER.output_buffer[start..end] - .iter_mut() - .zip(bytes.iter()) - { - *dst = *src; - } + pub fn new( + uart: &'static hil::uart::UART, + out_buffer: &'static mut [u8], + internal_buffer: &'static mut [u8], + ) -> DebugWriter { + DebugWriter { + uart: uart, + output_buffer: TakeCell::new(out_buffer), + internal_buffer: TakeCell::new(internal_buffer), + head: Cell::new(0), // first valid index in output_buffer + tail: Cell::new(0), // one past last valid index (wraps to 0) + active_len: Cell::new(0), // how big is the current transaction? + count: Cell::new(0), // how many debug! calls } } - fn publish_str(&mut self) { - unsafe { - if read_volatile(&self.output_active_len) != 0 { - // Cannot publish now, there is already an outstanding request - // the callback will call publish_str again to finish - return; + fn increment_count(&self) { + self.count.increment(); + } + + fn get_count(&self) -> usize { + self.count.get() + } + + /// Convenience method that writes (end-start) bytes from bytes into the + /// internal debug buffer. + fn write_buffer(&self, start: usize, end: usize, bytes: &[u8]) { + if end < start { + panic!("wb bounds: start {} end {} bytes {:?}", start, end, bytes); + } + self.internal_buffer.map(|in_buffer| { + for (dst, src) in in_buffer[start..end].iter_mut().zip(bytes.iter()) { + *dst = *src; } + }); + } - match self.driver { - Some(driver) => { - let head = read_volatile(&self.output_head); - let tail = read_volatile(&self.output_tail); - let len = self.output_buffer.len(); - - // Want to write everything from tail inclusive to head - // exclusive - let (start, end) = if tail > head { - // Need to pass subscribe a contiguous buffer, so first - // write from tail to end of buffer. The completion - // callback will see that the buffer's not empty and - // call again to write the rest (tail will be 0) - let start = tail; - let end = len; - (start, end) - } else if tail < head { - let start = tail; - let end = head; - (start, end) - } else { - panic!("Consistency error: publish empty buffer?") - }; - - let slice = AppSlice::new( - self.output_buffer.as_mut_ptr().offset(start as isize), - end - start, - AppId::kernel_new(APPID_IDX), - ); - let slice_len = slice.len(); - if driver.allow(AppId::kernel_new(APPID_IDX), 1, Some(slice)) - != ReturnCode::SUCCESS - { - panic!("Debug print allow fail"); - } - write_volatile(&mut DEBUG_WRITER.output_active_len, slice_len); - if driver.subscribe( - 1, - Some(KERNEL_CONSOLE_CALLBACK), - AppId::kernel_new(APPID_IDX), - ) != ReturnCode::SUCCESS - { - panic!("Debug print subscribe fail"); - } - if driver.command(1, slice_len, 0, AppId::kernel_new(APPID_IDX)) - != ReturnCode::SUCCESS - { - panic!("Debug print command fail"); - } - } - None => { - panic!("Platform has not yet configured kernel debug interface"); + /// Write as many of the bytes from the internal_buffer to the output + /// mechanism as possible. + fn publish_str(&self) { + // Can only publish if we have the output_buffer. If we don't that is + // fine, we will do it when the transmit done callback happens. + self.output_buffer.take().map(|out_buffer| { + let head = self.head.get(); + let tail = self.tail.get(); + let len = self + .internal_buffer + .map_or(0, |internal_buffer| internal_buffer.len()); + + // Want to write everything from tail inclusive to head + // exclusive + let (start, end) = if tail > head { + // Need to pass subscribe a contiguous buffer, so first + // write from tail to end of buffer. The completion + // callback will see that the buffer's not empty and + // call again to write the rest (tail will be 0) + let start = tail; + let end = len; + (start, end) + } else if tail < head { + let start = tail; + let end = head; + (start, end) + } else { + panic!("Consistency error: publish empty buffer?") + }; + + // Check that we aren't writing a segment larger than the output + // buffer. + let real_end = start + cmp::min(end - start, out_buffer.len()); + + self.internal_buffer.map(|internal_buffer| { + for (dst, src) in out_buffer + .iter_mut() + .zip(internal_buffer[start..real_end].iter()) + { + *dst = *src; } - } - } + }); + + // Set the outgoing length + let out_len = real_end - start; + self.active_len.set(out_len); + + // Transmit the data in the output buffer. + self.uart.transmit(out_buffer, out_len); + }); } - fn callback(bytes_written: usize, _: usize, _: usize, _: usize) { - let active = unsafe { read_volatile(&DEBUG_WRITER.output_active_len) }; - if active != bytes_written { - let count = unsafe { read_volatile(&DEBUG_WRITER.count) }; - panic!( - "active {} bytes_written {} count {}", - active, bytes_written, count - ); - } - let len = unsafe { DEBUG_WRITER.output_buffer.len() }; - let head = unsafe { read_volatile(&DEBUG_WRITER.output_head) }; - let mut tail = unsafe { read_volatile(&DEBUG_WRITER.output_tail) }; - tail = tail + bytes_written; + + fn extract(&self) -> Option<(usize, usize, &mut [u8])> { + self.internal_buffer + .take() + .map(|buf| (self.head.get(), self.tail.get(), buf)) + } +} + +impl hil::uart::Client for DebugWriter { + fn transmit_complete(&self, buffer: &'static mut [u8], _error: hil::uart::Error) { + // Replace this buffer since we are done with it. + self.output_buffer.replace(buffer); + + let written_length = self.active_len.get(); + self.active_len.set(0); + let len = self + .internal_buffer + .map_or(0, |internal_buffer| internal_buffer.len()); + let head = self.head.get(); + let mut tail = self.tail.get(); + + // Increment the tail with how many bytes were written to the output + // mechanism, and wrap if needed. + tail += written_length; if tail > len { tail = tail - len; } @@ -320,31 +355,48 @@ impl DebugWriter { if head == tail { // Empty. As an optimization, reset the head and tail pointers to 0 // to maximize the buffer length available before fragmentation - unsafe { - write_volatile(&mut DEBUG_WRITER.output_active_len, 0); - write_volatile(&mut DEBUG_WRITER.output_head, 0); - write_volatile(&mut DEBUG_WRITER.output_tail, 0); - } + self.head.set(0); + self.tail.set(0); } else { // Buffer not empty, go around again - unsafe { - write_volatile(&mut DEBUG_WRITER.output_active_len, 0); - write_volatile(&mut DEBUG_WRITER.output_tail, tail); - DEBUG_WRITER.publish_str(); - } + self.tail.set(tail); + self.publish_str(); } } + + fn receive_complete( + &self, + _buffer: &'static mut [u8], + _rx_len: usize, + _error: hil::uart::Error, + ) { + } } -//XXX http://stackoverflow.com/questions/28116147 -// I think this is benign and needed because NonZero's assuming threading in an -// inappropriate way? -unsafe impl Sync for Callback {} +/// Pass through functions. +impl DebugWriterWrapper { + fn increment_count(&self) { + self.dw.map(|dw| { + dw.increment_count(); + }); + } + + fn get_count(&self) -> usize { + self.dw.map_or(0, |dw| dw.get_count()) + } -static KERNEL_CONSOLE_CALLBACK: Callback = - Callback::kernel_new(AppId::kernel_new(APPID_IDX), DebugWriter::callback); + fn publish_str(&self) { + self.dw.map(|dw| { + dw.publish_str(); + }); + } -impl Write for DebugWriter { + fn extract(&self) -> Option<(usize, usize, &mut [u8])> { + self.dw.map_or(None, |dw| dw.extract()) + } +} + +impl Write for DebugWriterWrapper { fn write_str(&mut self, s: &str) -> Result { // Circular buffer. // @@ -359,81 +411,81 @@ impl Write for DebugWriter { // -> head == tail implies buffer is empty // -> there's no "full/empty" bit, so the effective buffer size is -1 - let mut head = unsafe { read_volatile(&DEBUG_WRITER.output_head) }; - let tail = unsafe { read_volatile(&DEBUG_WRITER.output_tail) }; - let len = unsafe { DEBUG_WRITER.output_buffer.len() }; + self.dw.map(|dw| { + let mut head = dw.head.get(); + let tail = dw.tail.get(); + let len = dw.internal_buffer.map_or(0, |buffer| buffer.len()); - let remaining_bytes = if head >= tail { - let bytes = s.as_bytes(); + let remaining_bytes = if head >= tail { + let bytes = s.as_bytes(); - // First write from current head to end of buffer in memory - let mut backside_len = len - head; - if tail == 0 { - // Handle special case where tail has just wrapped to 0, - // so we can't let the head point to 0 as well - backside_len -= 1; - } + // First write from current head to end of buffer in memory + let mut backside_len = len - head; + if tail == 0 { + // Handle special case where tail has just wrapped to 0, + // so we can't let the head point to 0 as well + backside_len -= 1; + } - let written = if backside_len != 0 { - let start = head; - let end = head + backside_len; - DebugWriter::write_buffer(start, end, bytes); - min(end - start, bytes.len()) + let written = if backside_len != 0 { + let start = head; + let end = head + backside_len; + dw.write_buffer(start, end, bytes); + min(end - start, bytes.len()) + } else { + 0 + }; + + // Advance and possibly wrap the head + head += written; + if head == len { + head = 0; + } + &bytes[written..] } else { - 0 + s.as_bytes() }; - // Advance and possibly wrap the head - head += written; - if head == len { - head = 0; - } - &bytes[written..] - } else { - s.as_bytes() - }; - - // At this point, either - // o head < tail - // o head = len-1, tail = 0 (buffer full edge case) - // o there are no more bytes to write - - if remaining_bytes.len() != 0 { - // Now write from the head up to tail - let start = head; - let end = tail; - if (tail == 0) && (head == len - 1) { - let active = unsafe { read_volatile(&DEBUG_WRITER.output_active_len) }; - panic!( - "Debug buffer full. Head {} tail {} len {} active {} remaining {}", - head, - tail, - len, - active, - remaining_bytes.len() - ); - } - if remaining_bytes.len() > end - start { - let active = unsafe { read_volatile(&DEBUG_WRITER.output_active_len) }; - panic!( - "Debug buffer out of room. Head {} tail {} len {} active {} remaining {}", - head, - tail, - len, - active, - remaining_bytes.len() - ); - } - DebugWriter::write_buffer(start, end, remaining_bytes); - let written = min(end - start, remaining_bytes.len()); + // At this point, either + // o head < tail + // o head = len-1, tail = 0 (buffer full edge case) + // o there are no more bytes to write - // head cannot wrap here - head += written; - } + if remaining_bytes.len() != 0 { + // Now write from the head up to tail + let start = head; + let end = tail; + if (tail == 0) && (head == len - 1) { + let active = dw.active_len.get(); + panic!( + "Debug buffer full. Head {} tail {} len {} active {} remaining {}", + head, + tail, + len, + active, + remaining_bytes.len() + ); + } + if remaining_bytes.len() > end - start { + let active = dw.active_len.get(); + panic!( + "Debug buffer out of room. Head {} tail {} len {} active {} remaining {}", + head, + tail, + len, + active, + remaining_bytes.len() + ); + } + dw.write_buffer(start, end, remaining_bytes); + let written = min(end - start, remaining_bytes.len()); - unsafe { - write_volatile(&mut DEBUG_WRITER.output_head, head); - } + // head cannot wrap here + head += written; + } + + dw.head.set(head); + }); Ok(()) } @@ -441,7 +493,7 @@ impl Write for DebugWriter { pub fn begin_debug_fmt(args: Arguments) { unsafe { - let writer = &mut DEBUG_WRITER; + let writer = get_debug_writer(); let _ = write(writer, args); let _ = writer.write_str("\n"); writer.publish_str(); @@ -450,10 +502,11 @@ pub fn begin_debug_fmt(args: Arguments) { pub fn begin_debug_verbose_fmt(args: Arguments, file_line: &(&'static str, u32)) { unsafe { - let count = read_volatile(&DEBUG_WRITER.count); - write_volatile(&mut DEBUG_WRITER.count, count + 1); + let writer = get_debug_writer(); + + writer.increment_count(); + let count = writer.get_count(); - let writer = &mut DEBUG_WRITER; let (file, line) = *file_line; let _ = writer.write_fmt(format_args!("TOCK_DEBUG({}): {}:{}: ", count, file, line)); let _ = write(writer, args); @@ -515,28 +568,29 @@ impl Default for Debug { } pub unsafe fn flush(writer: &mut W) { - let debug_head = read_volatile(&DEBUG_WRITER.output_head); - let mut debug_tail = read_volatile(&DEBUG_WRITER.output_tail); - let mut debug_buffer = DEBUG_WRITER.output_buffer; - if debug_head != debug_tail { - let _ = writer.write_str( - "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n", - ); + let debug_writer = get_debug_writer(); - if debug_tail > debug_head { - let start = debug_buffer.as_mut_ptr().offset(debug_tail as isize); - let len = debug_buffer.len(); - let slice = slice::from_raw_parts(start, len); - let s = str::from_utf8_unchecked(slice); - let _ = writer.write_str(s); - debug_tail = 0; - } - if debug_tail != debug_head { - let start = debug_buffer.as_mut_ptr().offset(debug_tail as isize); - let len = debug_head - debug_tail; - let slice = slice::from_raw_parts(start, len); - let s = str::from_utf8_unchecked(slice); - let _ = writer.write_str(s); + if let Some((head, mut tail, buffer)) = debug_writer.extract() { + if head != tail { + let _ = writer.write_str( + "\r\n---| Debug buffer not empty. Flushing. May repeat some of last message(s):\r\n", + ); + + if tail > head { + let start = buffer.as_mut_ptr().offset(tail as isize); + let len = buffer.len(); + let slice = slice::from_raw_parts(start, len); + let s = str::from_utf8_unchecked(slice); + let _ = writer.write_str(s); + tail = 0; + } + if tail != head { + let start = buffer.as_mut_ptr().offset(tail as isize); + let len = head - tail; + let slice = slice::from_raw_parts(start, len); + let s = str::from_utf8_unchecked(slice); + let _ = writer.write_str(s); + } } } } diff --git a/kernel/src/grant.rs b/kernel/src/grant.rs index 896f7c5669..42c3e25ad4 100644 --- a/kernel/src/grant.rs +++ b/kernel/src/grant.rs @@ -5,7 +5,6 @@ use core::marker::PhantomData; use core::mem::size_of; use core::ops::{Deref, DerefMut}; use core::ptr::{read_volatile, write_volatile, Unique}; -use debug; use process::{self, Error}; crate static mut CONTAINER_COUNTER: usize = 0; @@ -21,44 +20,28 @@ pub struct AppliedGrant { _phantom: PhantomData, } -/// This function contains the mapping of kernel "app" numbers to their -/// functions for getting a pointer to their grant region. Normal apps are -/// stored in a processes array, and finding apps is a matter of iterating that -/// array. Kernel "apps" currently (June 2018) have no such structure, so -/// finding them is a bit more ad-hoc. -crate unsafe fn kernel_grant_for(app_id: usize) -> *mut T { - match app_id { - debug::APPID_IDX => debug::get_grant(), - _ => panic!("lookup for invalid kernel grant {}", app_id), - } -} - impl AppliedGrant { pub fn enter(self, fun: F) -> R where F: FnOnce(&mut Owned, &mut Allocator) -> R, R: Copy, { - if AppId::is_kernel_idx(self.appid) { - let mut allocator = Allocator { - app: None, - app_id: self.appid, - }; - let mut root = unsafe { Owned::new(self.grant, self.appid) }; - fun(&mut root, &mut allocator) - } else { - let mut allocator = Allocator { - app: unsafe { process::PROCS[self.appid].as_mut() }, - app_id: self.appid, - }; - let mut root = unsafe { Owned::new(self.grant, self.appid) }; - fun(&mut root, &mut allocator) - } + let proc = unsafe { + process::PROCS[self.appid] + .as_mut() + .expect("Request to allocate in nonexistent app") + }; + let mut allocator = Allocator { + app: proc, + app_id: self.appid, + }; + let mut root = unsafe { Owned::new(self.grant, self.appid) }; + fun(&mut root, &mut allocator) } } pub struct Allocator<'a> { - app: Option<&'a mut &'a mut process::Process<'a>>, + app: &'a mut process::Process<'a>, app_id: usize, } @@ -85,15 +68,10 @@ impl Drop for Owned { unsafe { let app_id = self.app_id; let data = self.data.as_ptr() as *mut u8; - if AppId::is_kernel_idx(app_id) { - /* kernel free is nop */ -; - } else { - match process::PROCS[app_id] { - None => {} - Some(ref mut app) => { - app.free(data); - } + match process::PROCS[app_id] { + None => {} + Some(ref mut app) => { + app.free(data); } } } @@ -117,21 +95,13 @@ impl Allocator<'a> { pub fn alloc(&mut self, data: T) -> Result, Error> { unsafe { let app_id = self.app_id; - match self.app.as_mut() { - Some(app) => app - .alloc(size_of::()) - .map_or(Err(Error::OutOfMemory), |arr| { - let mut owned = Owned::new(arr.as_mut_ptr() as *mut T, app_id); - *owned = data; - Ok(owned) - }), - None => { - if !AppId::is_kernel_idx(app_id) { - panic!("No app for allocator for {}", app_id); - } - panic!("Request to allocate in kernel grant"); - } - } + self.app + .alloc(size_of::()) + .map_or(Err(Error::OutOfMemory), |arr| { + let mut owned = Owned::new(arr.as_mut_ptr() as *mut T, app_id); + *owned = data; + Ok(owned) + }) } } } @@ -180,29 +150,20 @@ impl Grant { pub fn grant(&self, appid: AppId) -> Option> { unsafe { let app_id = appid.idx(); - if AppId::is_kernel(appid) { - let cntr = kernel_grant_for::(app_id); - Some(AppliedGrant { - appid: app_id, - grant: cntr, - _phantom: PhantomData, - }) - } else { - match process::PROCS[app_id] { - Some(ref mut app) => { - let cntr = app.grant_for::(self.grant_num); - if cntr.is_null() { - None - } else { - Some(AppliedGrant { - appid: app_id, - grant: cntr, - _phantom: PhantomData, - }) - } + match process::PROCS[app_id] { + Some(ref mut app) => { + let cntr = app.grant_for::(self.grant_num); + if cntr.is_null() { + None + } else { + Some(AppliedGrant { + appid: app_id, + grant: cntr, + _phantom: PhantomData, + }) } - None => None, } + None => None, } } } @@ -214,31 +175,20 @@ impl Grant { { unsafe { let app_id = appid.idx(); - if AppId::is_kernel(appid) { - let root_ptr = kernel_grant_for::(app_id); - let mut root = Borrowed::new(&mut *root_ptr, app_id); - let mut allocator = Allocator { - app: None, - app_id: app_id, - }; - let res = fun(&mut root, &mut allocator); - Ok(res) - } else { - match process::PROCS[app_id] { - Some(ref mut app) => app.grant_for_or_alloc::(self.grant_num).map_or( - Err(Error::OutOfMemory), - move |root_ptr| { - let mut root = Borrowed::new(&mut *root_ptr, app_id); - let mut allocator = Allocator { - app: Some(app), - app_id: app_id, - }; - let res = fun(&mut root, &mut allocator); - Ok(res) - }, - ), - None => Err(Error::NoSuchApp), - } + match process::PROCS[app_id] { + Some(ref mut app) => app.grant_for_or_alloc::(self.grant_num).map_or( + Err(Error::OutOfMemory), + move |root_ptr| { + let mut root = Borrowed::new(&mut *root_ptr, app_id); + let mut allocator = Allocator { + app: app, + app_id: app_id, + }; + let res = fun(&mut root, &mut allocator); + Ok(res) + }, + ), + None => Err(Error::NoSuchApp), } } } @@ -256,12 +206,6 @@ impl Grant { fun(&mut root); } } - // After iterating all possible normal apps, try the debug app. - let root_ptr = kernel_grant_for::(debug::APPID_IDX); - if !root_ptr.is_null() { - let mut root = Owned::new(root_ptr, debug::APPID_IDX); - fun(&mut root); - } } } @@ -294,15 +238,6 @@ impl Iterator for Iter<'a, T> { return res; } } - // After running through all real apps, pass the debug app (idx 255) to - // the grant iterator in case it has state the capsule needs to process. - if self.index == self.len { - self.index += 1; - let res = self.grant.grant(AppId::new(debug::APPID_IDX)); - if res.is_some() { - return res; - } - } None } }