Skip to content

Commit

Permalink
Merge pull request #45 from Foundation-Devices/SFT-4073-aesb
Browse files Browse the repository at this point in the history
SFT-4073: AESB
  • Loading branch information
eupn committed Aug 18, 2024
2 parents 4f16998 + 5dc4abe commit 5879bd4
Show file tree
Hide file tree
Showing 8 changed files with 327 additions and 9 deletions.
4 changes: 4 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,10 @@ required-features = ["usb-host"]
name = "shdwc"
required-features = []

[[bin]]
name = "aesb"
required-features = []

[dependencies]
armv7 = { git = "https://github.com/Foundation-Devices/armv7.git", branch = "update" }
bitflags = "2.4.1"
Expand Down
6 changes: 6 additions & 0 deletions scripts/debug-aesb.sh
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
#!/usr/bin/env bash

set -e

cargo build --release --bin aesb
arm-none-eabi-gdb -q ../target/armv7a-none-eabi/release/aesb -x init.gdb
96 changes: 96 additions & 0 deletions src/aesb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,96 @@
// SPDX-FileCopyrightText: 2024 Foundation Devices, Inc. <[email protected]>
// SPDX-License-Identifier: MIT OR Apache-2.0

//! AES Bridge (AESB)

use utralib::{utra::aesb::*, HW_AESB_BASE, *};

const CKEY: u32 = 0xE;

pub enum AesMode {
Ecb { key: [u32; 4] },

Cbc { key: [u32; 4], iv: [u32; 4] },

Counter { nonce: [u32; 4] },
}

pub struct Aesb {
base_addr: u32,
}

impl Default for Aesb {
fn default() -> Self {
Aesb::new()
}
}

impl Aesb {
pub fn new() -> Self {
Self {
base_addr: HW_AESB_BASE as u32,
}
}

/// Creates `AESB` instance with a different base address. Used with virtual memory
pub fn with_alt_base_addr(base_addr: u32) -> Self {
Self { base_addr }
}

pub fn init(&self, mode: AesMode, procdly: u32) {
self.reset();

let mut csr = CSR::new(self.base_addr as *mut u32);
let (opmod, aahb) = match mode {
AesMode::Ecb { key } => {
self.set_key(&key);
(csr.ms(MR_OPMOD, 0), csr.ms(MR_AAHB, 0))
}
AesMode::Cbc { key, iv } => {
self.set_key(&key);
self.set_iv(&iv);
(csr.ms(MR_OPMOD, 1), csr.ms(MR_AAHB, 0))
}
AesMode::Counter { nonce } => {
self.set_iv(&nonce);
(csr.ms(MR_OPMOD, 0x4), csr.ms(MR_AAHB, 1))
}
};

let smod = csr.ms(MR_SMOD, 1); // auto-start
let ckey = csr.ms(MR_CKEY, CKEY);
let dualbuff = csr.ms(MR_DUALBUFF, 1);
let procdly = csr.ms(MR_PROCDLY, procdly);
csr.wo(MR, ckey | opmod | smod | procdly | dualbuff | aahb);
}

fn set_key(&self, key: &[u32; 4]) {
const AESB_KEYWR_OFFSET: usize = 0x20; // TODO: change to utralib when `AESB` registers are fixed in the SVD
let ivr_base = self.base_addr as usize + AESB_KEYWR_OFFSET;

for (i, key) in key.iter().enumerate() {
unsafe {
let ptr = (ivr_base + i * 4) as *mut u32;
ptr.write_volatile(*key);
}
}
}

fn set_iv(&self, iv: &[u32; 4]) {
const AESB_IVR_OFFSET: usize = 0x60; // TODO: change to utralib when `AESB` registers are fixed in the SVD
let ivr_base = self.base_addr as usize + AESB_IVR_OFFSET;

for (i, iv) in iv.iter().enumerate() {
unsafe {
let ptr = (ivr_base + i * 4) as *mut u32;
ptr.write_volatile(*iv);
}
}
}

/// Performs the software reset of the `AESB`.
fn reset(&self) {
let mut csr = CSR::new(self.base_addr as *mut u32);
csr.wfo(CR_SWRST, 1);
}
}
188 changes: 188 additions & 0 deletions src/bin/aesb.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,188 @@
// SPDX-FileCopyrightText: 2024 Foundation Devices, Inc. <[email protected]>
// SPDX-License-Identifier: MIT OR Apache-2.0

#![no_std]
#![no_main]

use {
atsama5d27::{
aesb::{AesMode, Aesb},
aic::{Aic, InterruptEntry, SourceKind},
pit::{Pit, PIV_MAX},
pmc::{PeripheralId, Pmc},
tc::Tc,
trng::Trng,
uart::{Uart, Uart1},
},
core::{
arch::global_asm,
fmt::Write,
panic::PanicInfo,
sync::atomic::{compiler_fence, Ordering::SeqCst},
},
};

global_asm!(include_str!("../start.S"));

type UartType = Uart<Uart1>;
const UART_PERIPH_ID: PeripheralId = PeripheralId::Uart1;

// MCK: 164MHz
// Clock frequency is divided by 2 because of the default `h32mxdiv` PMC setting
const MASTER_CLOCK_SPEED: u32 = 164000000 / 2;

#[no_mangle]
fn _entry() -> ! {
extern "C" {
// These symbols come from `link.ld`
static mut _sbss: u32;
static mut _ebss: u32;
}

// Initialize RAM
unsafe {
r0::zero_bss(&mut _sbss, &mut _ebss);
}

atsama5d27::l1cache::disable_dcache();

let mut pmc = Pmc::new();
pmc.enable_peripheral_clock(PeripheralId::Pit);
pmc.enable_peripheral_clock(PeripheralId::Aic);
pmc.enable_peripheral_clock(PeripheralId::Pioa);
pmc.enable_peripheral_clock(PeripheralId::Piob);
pmc.enable_peripheral_clock(PeripheralId::Pioc);
pmc.enable_peripheral_clock(PeripheralId::Piod);
pmc.enable_peripheral_clock(PeripheralId::Aesb);
pmc.enable_peripheral_clock(PeripheralId::Trng);

let mut tc0 = Tc::new();
tc0.init();

let mut aic = Aic::new();
aic.init();
aic.set_spurious_handler_fn_ptr(aic_spurious_handler as unsafe extern "C" fn() as usize);

let uart_irq_ptr = uart_irq_handler as unsafe extern "C" fn() as usize;
aic.set_interrupt_handler(InterruptEntry {
peripheral_id: UART_PERIPH_ID,
vector_fn_ptr: uart_irq_ptr,
kind: SourceKind::LevelSensitive,
priority: 0,
});

// Enable interrupts
unsafe {
core::arch::asm!("cpsie if");
}

// Timer for delays
let mut pit = Pit::new();
pit.set_interval(PIV_MAX);
pit.set_enabled(true);
pit.set_clock_speed(MASTER_CLOCK_SPEED);
pit.busy_wait_ms(MASTER_CLOCK_SPEED, 500);

let mut uart = UartType::new();
uart.set_rx_interrupt(true);
uart.set_rx(true);
writeln!(uart, "Running").ok();

let trng = Trng::new().enable();

// The IV (Initialization Vector) field of the AESB Initialization Vector register x
// (AESB_IVRx) can be used to add a nonce in the encryption process in order to bring
// even more security (ignored if not filled). In this case, any value encrypted with
// a given nonce can only be decrypted with this nonce. If another nonce is set for
// the AESB_IVRx.IV, any value encrypted with the previous nonce can no longer be
// decrypted (see AESB Initialization Vector Register x)
let mut nonce = [0u32; 4];
nonce.fill_with(|| trng.read_u32());

writeln!(uart, "AESB CTR nonce: {:08x?}", &nonce).ok();
let aesb = Aesb::new();

writeln!(uart, "Initializing AESB").ok();
aesb.init(AesMode::Counter { nonce }, 0);

const TEST_MEM_BASE: usize = 0x10000;

/// This physical address is the `AESB` DRAM chip select.
/// This means that accesses to this memory addresses will go through the AES to be
/// transparently encrypted (writes) or decrypted (reads).
const AES_CS_BASE: usize = 0x4000_0000 + TEST_MEM_BASE;

/// This address allows the direct access to the DRAM.
/// Accessing this memory will return the data encrypted by the `AESB` as ciphertext,
/// and it won't be automatically decrypted which makes it unreadable.
const DRAM_CS_BASE: usize = 0x2000_0000 + TEST_MEM_BASE;

let aes_dram_ptr = AES_CS_BASE as *mut u32;
let dram_ptr = DRAM_CS_BASE as *mut u32;

// Test writing a single word
writeln!(uart, "AESB: single word test").ok();
unsafe {
const TEST_VAL: u32 = 0x55555555;
aes_dram_ptr.write_volatile(TEST_VAL);
assert_ne!(
dram_ptr.read_volatile(),
aes_dram_ptr.read_volatile(),
"AES encryption failed"
);
assert_eq!(
aes_dram_ptr.read_volatile(),
TEST_VAL,
"AES decryption failed"
);
}

// Test with an array
writeln!(uart, "AESB: array test").ok();
unsafe {
const EMPTY_ARRAY: [u8; 256] = [0u8; 256];
let aes_dram_slice =
core::slice::from_raw_parts_mut(aes_dram_ptr as *mut u8, EMPTY_ARRAY.len());
let dram_slice = core::slice::from_raw_parts_mut(dram_ptr as *mut u8, EMPTY_ARRAY.len());
aes_dram_slice.copy_from_slice(&EMPTY_ARRAY);

writeln!(uart, "AESB: {:02x?}", aes_dram_slice).ok();
writeln!(uart, "DRAM: {:02x?}", dram_slice).ok();

assert_ne!(aes_dram_slice, dram_slice, "AES encryption failed");
assert_eq!(aes_dram_slice, EMPTY_ARRAY, "AES decryption failed");
}

writeln!(uart, "AESB: tests passed").ok();

loop {
armv7::asm::wfi();
}
}

#[no_mangle]
unsafe extern "C" fn aic_spurious_handler() {
core::arch::asm!("bkpt");
}

#[no_mangle]
unsafe extern "C" fn uart_irq_handler() {
let mut uart = UartType::new();
let char = uart.getc() as char;
writeln!(uart, "Received character: {}", char).ok();
}

#[inline(never)]
#[panic_handler]
fn panic(_info: &PanicInfo) -> ! {
let mut console = Uart::<Uart1>::new();

compiler_fence(SeqCst);
writeln!(console, "{}", _info).ok();

loop {
unsafe {
core::arch::asm!("bkpt");
}
}
}
25 changes: 20 additions & 5 deletions src/bin/charger.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,8 +236,16 @@ fn _entry() -> ! {

//////////////////////////////////
let mut fuel_gauge = bq27421::Bq27421::new(Twi::twi0());
assert!(fuel_gauge.verify_chip_id().unwrap(), "unexpected fuel gauge chip ID");
writeln!(console, "Fuel gauge status: {:?}", fuel_gauge.status().unwrap()).ok();
assert!(
fuel_gauge.verify_chip_id().unwrap(),
"unexpected fuel gauge chip ID"
);
writeln!(
console,
"Fuel gauge status: {:?}",
fuel_gauge.status().unwrap()
)
.ok();

loop {
let status = bq.status().unwrap();
Expand All @@ -249,15 +257,22 @@ fn _entry() -> ! {
"fault chg: {:?} fault boost: {:?}",
status.charge_fault().unwrap(),
status.boost_fault().unwrap(),
).ok();
writeln!(console, "Fuel gauge flags: {:?}", fuel_gauge.flags().unwrap()).ok();
)
.ok();
writeln!(
console,
"Fuel gauge flags: {:?}",
fuel_gauge.flags().unwrap()
)
.ok();
writeln!(
console,
"State of charge: {} Charge current: {} Capacity: {}",
fuel_gauge.state_of_charge().unwrap(),
fuel_gauge.charge_current().unwrap(),
fuel_gauge.capacity().unwrap(),
).ok();
)
.ok();

pit.busy_wait_ms(MASTER_CLOCK_SPEED, 1000);
}
Expand Down
7 changes: 6 additions & 1 deletion src/bin/uart-dma.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,12 @@ use {
atsama5d27::{
aic::{Aic, InterruptEntry, SourceKind},
dma::{
DmaChannel, DmaChunkSize, DmaDataWidth, DmaPeripheralId, DmaTransferDirection, Xdmac,
DmaChannel,
DmaChunkSize,
DmaDataWidth,
DmaPeripheralId,
DmaTransferDirection,
Xdmac,
},
pit::{Pit, PIV_MAX},
pmc::{PeripheralId, Pmc},
Expand Down
1 change: 1 addition & 0 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@

pub mod adc;
pub mod aes;
pub mod aesb;
pub mod aic;
pub mod cache;
#[cfg(feature = "lcd-console")]
Expand Down
9 changes: 6 additions & 3 deletions src/sha.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,11 @@

use {
crate::dma::{
DmaChannel, DmaChunkSize, DmaDataWidth, DmaPeripheralId, DmaTransferDirection, XdmacChannel,
DmaChunkSize,
DmaDataWidth,
DmaPeripheralId,
DmaTransferDirection,
XdmacChannel,
},
bitflags::bitflags,
utralib::{utra::sha::*, HW_SHA_BASE, *},
Expand Down Expand Up @@ -225,8 +229,7 @@ impl Sha {
self.set_message_size(data.len() as u32);
self.set_byte_count(data.len() as u32);
self.first();
let total_blocks = data.chunks(SHA256_BLOCK_SIZE_BYTES).len();
for (i, block) in data.chunks(SHA256_BLOCK_SIZE_BYTES).enumerate() {
for block in data.chunks(SHA256_BLOCK_SIZE_BYTES) {
self.write_sha256_block(block);
self.start();
self.wait_data_ready();
Expand Down

0 comments on commit 5879bd4

Please sign in to comment.