Skip to content

Commit

Permalink
boards: apollo3: Initial support for the Atecc508a CryptoAuthenticati…
Browse files Browse the repository at this point in the history
…on Device

Signed-off-by: Alistair Francis <alistair.francis@wdc.com>
  • Loading branch information
alistair23 committed Jun 24, 2024
1 parent 5de0ec6 commit b5e1764
Show file tree
Hide file tree
Showing 5 changed files with 241 additions and 11 deletions.
9 changes: 9 additions & 0 deletions boards/apollo3/lora_things_plus/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -19,3 +19,12 @@ apollo3 = { path = "../../../chips/apollo3" }
capsules-core = { path = "../../../capsules/core" }
capsules-extra = { path = "../../../capsules/extra" }
capsules-system = { path = "../../../capsules/system" }

[features]
default = []

# This feature enables support for the ATECC508A Cryptographic Co-Processor
# Breakout. If you connect one of these
# (https://www.sparkfun.com/products/15573) via the I2C Qwiic connector you
# should enable this feature.
atecc508a = []
119 changes: 108 additions & 11 deletions boards/apollo3/lora_things_plus/src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@
//! and <https://cdn.sparkfun.com/assets/4/4/f/7/e/expLoRaBLE_Thing_Plus_schematic.pdf>
//! for details on the pin break outs
//!
//! ION0: Qwiic I2C
//! IOM0: Qwiic I2C
//! IOM1: Not connected
//! IOM2: Broken out SPI
//! IOM3: Semtech SX1262
Expand Down Expand Up @@ -57,6 +57,15 @@ use kernel::platform::{KernelResources, SyscallDriverLookup};
use kernel::scheduler::round_robin::RoundRobinSched;
use kernel::{create_capability, debug, static_init};

#[cfg(feature = "atecc508a")]
use {
capsules_core::virtualizers::virtual_i2c::MuxI2C,
components::atecc508a::Atecc508aComponent,
kernel::hil::entropy::Entropy32,
kernel::hil::gpio::{Configure, Output},
kernel::hil::rng::Rng,
};

/// Support routines for debugging I/O.
pub mod io;

Expand All @@ -80,7 +89,6 @@ const FAULT_RESPONSE: capsules_system::process_policies::PanicFaultPolicy =
capsules_system::process_policies::PanicFaultPolicy {};

// Test access to the peripherals
#[cfg(test)]
static mut PERIPHERALS: Option<&'static Apollo3DefaultPeripherals> = None;
// Test access to board
#[cfg(test)]
Expand All @@ -101,6 +109,8 @@ static mut BME280: Option<
>,
> = None;
static mut CCS811: Option<&'static capsules_extra::ccs811::Ccs811<'static>> = None;
#[cfg(feature = "atecc508a")]
static mut ATECC508A: Option<&'static capsules_extra::atecc508a::Atecc508a<'static>> = None;

/// Dummy buffer that causes the linker to reserve enough space for the stack.
#[no_mangle]
Expand Down Expand Up @@ -155,10 +165,80 @@ struct LoRaThingsPlus {
temperature: &'static TemperatureDriver,
humidity: &'static HumidityDriver,
air_quality: &'static capsules_extra::air_quality::AirQualitySensor<'static>,
rng: Option<
&'static capsules_core::rng::RngDriver<
'static,
capsules_core::rng::Entropy32ToRandom<
'static,
capsules_extra::atecc508a::Atecc508a<'static>,
>,
>,
>,
scheduler: &'static RoundRobinSched<'static>,
systick: cortexm4::systick::SysTick,
}

#[cfg(feature = "atecc508a")]
fn atecc508a_wakeup() {
let peripherals = unsafe { PERIPHERALS.unwrap() };

peripherals.gpio_port[6].make_output();
peripherals.gpio_port[6].clear();

// The ATECC508A requires the SDA line to be low for at least 60us
// to wake up.
for _i in 0..700 {
cortexm4::support::nop();
}

// Enable SDA and SCL for I2C (exposed via Qwiic)
let _ = &peripherals
.gpio_port
.enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]);
}

#[cfg(feature = "atecc508a")]
unsafe fn setup_atecc508a(
board_kernel: &'static kernel::Kernel,
memory_allocation_cap: &dyn capabilities::MemoryAllocationCapability,
mux_i2c: &'static MuxI2C<'static, apollo3::iom::Iom<'static>>,
) -> &'static capsules_core::rng::RngDriver<
'static,
capsules_core::rng::Entropy32ToRandom<'static, capsules_extra::atecc508a::Atecc508a<'static>>,
> {
let atecc508a = Atecc508aComponent::new(mux_i2c, 0x60, atecc508a_wakeup).finalize(
components::atecc508a_component_static!(apollo3::iom::Iom<'static>),
);
ATECC508A = Some(atecc508a);

// Convert hardware RNG to the Random interface.
let entropy_to_random = static_init!(
capsules_core::rng::Entropy32ToRandom<
'static,
capsules_extra::atecc508a::Atecc508a<'static>,
>,
capsules_core::rng::Entropy32ToRandom::new(atecc508a)
);
atecc508a.set_client(entropy_to_random);
// Setup RNG for userspace
let rng_local = static_init!(
capsules_core::rng::RngDriver<
'static,
capsules_core::rng::Entropy32ToRandom<
'static,
capsules_extra::atecc508a::Atecc508a<'static>,
>,
>,
capsules_core::rng::RngDriver::new(
entropy_to_random,
board_kernel.create_grant(capsules_core::rng::DRIVER_NUM, memory_allocation_cap)
)
);
entropy_to_random.set_client(rng_local);

rng_local
}

/// Mapping of integer syscalls to objects that implement syscalls.
impl SyscallDriverLookup for LoRaThingsPlus {
fn with_driver<F, R>(&self, driver_num: usize, f: F) -> R
Expand All @@ -178,6 +258,13 @@ impl SyscallDriverLookup for LoRaThingsPlus {
capsules_extra::temperature::DRIVER_NUM => f(Some(self.temperature)),
capsules_extra::humidity::DRIVER_NUM => f(Some(self.humidity)),
capsules_extra::air_quality::DRIVER_NUM => f(Some(self.air_quality)),
capsules_core::rng::DRIVER_NUM => {
if let Some(rng) = self.rng {
f(Some(rng))
} else {
f(None)
}
}
_ => f(None),
}
}
Expand Down Expand Up @@ -222,9 +309,9 @@ unsafe fn setup() -> (
&'static kernel::Kernel,
&'static LoRaThingsPlus,
&'static apollo3::chip::Apollo3<Apollo3DefaultPeripherals>,
&'static Apollo3DefaultPeripherals,
) {
let peripherals = static_init!(Apollo3DefaultPeripherals, Apollo3DefaultPeripherals::new());
PERIPHERALS = Some(peripherals);

// No need to statically allocate mcu/pwr/clk_ctrl because they are only used in main!
let mcu_ctrl = apollo3::mcuctrl::McuCtrl::new();
Expand All @@ -249,10 +336,6 @@ unsafe fn setup() -> (
peripherals
.gpio_port
.enable_uart(&peripherals.gpio_port[48], &peripherals.gpio_port[49]);
// Enable SDA and SCL for I2C (exposed via Qwiic)
peripherals
.gpio_port
.enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]);
// Enable Main SPI
peripherals.gpio_port.enable_spi(
&peripherals.gpio_port[27],
Expand Down Expand Up @@ -327,6 +410,11 @@ unsafe fn setup() -> (
.finalize(components::process_printer_text_component_static!());
PROCESS_PRINTER = Some(process_printer);

// Enable SDA and SCL for I2C (exposed via Qwiic)
peripherals
.gpio_port
.enable_i2c(&peripherals.gpio_port[6], &peripherals.gpio_port[5]);

// Init the I2C device attached via Qwiic
let i2c_master_buffer = static_init!(
[u8; capsules_core::i2c_master::BUFFER_LENGTH],
Expand Down Expand Up @@ -379,6 +467,15 @@ unsafe fn setup() -> (
.finalize(components::air_quality_component_static!());
CCS811 = Some(ccs811);

#[cfg(feature = "atecc508a")]
let rng = Some(setup_atecc508a(
board_kernel,
&memory_allocation_cap,
mux_i2c,
));
#[cfg(not(feature = "atecc508a"))]
let rng = None;

// Init the broken out SPI controller
let external_mux_spi = components::spi::SpiMuxComponent::new(&peripherals.iom2).finalize(
components::spi_mux_component_static!(apollo3::iom::Iom<'static>),
Expand Down Expand Up @@ -483,6 +580,7 @@ unsafe fn setup() -> (
temperature,
humidity,
air_quality,
rng,
scheduler,
systick,
}
Expand Down Expand Up @@ -514,7 +612,7 @@ unsafe fn setup() -> (
debug!("{:?}", err);
});

(board_kernel, artemis_nano, chip, peripherals)
(board_kernel, artemis_nano, chip)
}

/// Main function.
Expand All @@ -530,7 +628,7 @@ pub unsafe fn main() {

#[cfg(not(test))]
{
let (board_kernel, sf_lora_thing_plus_board, chip, _peripherals) = setup();
let (board_kernel, sf_lora_thing_plus_board, chip) = setup();

let main_loop_cap = create_capability!(capabilities::MainLoopCapability);

Expand All @@ -549,11 +647,10 @@ use kernel::platform::watchdog::WatchDog;
#[cfg(test)]
fn test_runner(tests: &[&dyn Fn()]) {
unsafe {
let (board_kernel, sf_lora_thing_plus_board, _chip, peripherals) = setup();
let (board_kernel, sf_lora_thing_plus_board, _chip) = setup();

BOARD = Some(board_kernel);
PLATFORM = Some(&sf_lora_thing_plus_board);
PERIPHERALS = Some(peripherals);
MAIN_CAP = Some(&create_capability!(capabilities::MainLoopCapability));

PLATFORM.map(|p| {
Expand Down
86 changes: 86 additions & 0 deletions boards/apollo3/lora_things_plus/src/tests/atecc508a.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,86 @@
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2023.

//! Test that the Atecc508a works
use crate::tests::run_kernel_op;
use crate::ATECC508A;
use kernel::debug;

#[test_case]
fn read_config() {
run_kernel_op(100_000);

debug!("check run ATECC508A config... ");
run_kernel_op(100);

unsafe {
let atecc508a = ATECC508A.unwrap();

atecc508a.read_config_zone().unwrap();
}

run_kernel_op(150_000);
debug!(" [ok]");
run_kernel_op(100);
}

#[test_case]
fn setup_and_lock_tock_config() {
run_kernel_op(100_000);

debug!("Lock the Tock config...");
run_kernel_op(100);

unsafe {
let atecc508a = ATECC508A.unwrap();

atecc508a.read_config_zone().unwrap();
run_kernel_op(150_000);

if atecc508a.device_locked() {
debug!(" [ok] - Already locked");
return;
}

debug!("This can not be undone!");
run_kernel_op(100);
debug!("Power off the board now to stop the process!");
run_kernel_op(100);

// Provide a chance for the user to stop the process
run_kernel_op(1_000_000);

debug!("Setting up config");
atecc508a.setup_tock_config().unwrap();
run_kernel_op(150_000);

debug!("Locking zone config");
atecc508a.lock_zone_config().unwrap();
run_kernel_op(200_000);

debug!("Generating public key");
atecc508a.create_key_pair(0).unwrap();
run_kernel_op(300_000);

let public_key = atecc508a.get_public_key(0).unwrap();
debug!("public_key: {:x?}", public_key.get());

debug!("Locking data and OTP");
atecc508a.lock_data_and_otp().unwrap();
run_kernel_op(300_000);

debug!("Locking slot 0");
atecc508a.lock_slot0().unwrap();
run_kernel_op(300_000);

debug!("Reading new config");
atecc508a.read_config_zone().unwrap();
run_kernel_op(100_000);
}

run_kernel_op(100_000);
debug!(" [ok]");
run_kernel_op(100);
}
33 changes: 33 additions & 0 deletions boards/apollo3/lora_things_plus/src/tests/csrng.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
// Licensed under the Apache License, Version 2.0 or the MIT License.
// SPDX-License-Identifier: Apache-2.0 OR MIT
// Copyright Tock Contributors 2022.

//! Test that the RNG works
use crate::tests::run_kernel_op;
use crate::ATECC508A;
use capsules_core::test::rng::TestEntropy32;
use kernel::debug;
use kernel::hil::entropy::Entropy32;
use kernel::static_init;

#[test_case]
fn run_csrng_entropy32() {
// We need to make sure the device is setup
run_kernel_op(10_000);

debug!("check run CSRNG Entropy 32... ");
run_kernel_op(100);

unsafe {
let rng = ATECC508A.unwrap();

let t = static_init!(TestEntropy32<'static>, TestEntropy32::new(rng));
rng.set_client(t);

t.run();
}
run_kernel_op(10_000);
debug!(" [ok]");
run_kernel_op(100);
}
5 changes: 5 additions & 0 deletions boards/apollo3/lora_things_plus/src/tests/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,11 @@ fn trivial_assertion() {
run_kernel_op(10000);
}

#[cfg(feature = "atecc508a")]
mod atecc508a;
#[cfg(feature = "atecc508a")]
mod csrng;

mod environmental_sensors;
mod multi_alarm;
mod spi_controller;

0 comments on commit b5e1764

Please sign in to comment.