use crate::pm;
use crate::scif;
use core::cell::Cell;
use kernel::debug;
use kernel::hil;
use kernel::hil::symmetric_encryption::{AES128_BLOCK_SIZE, AES128_KEY_SIZE};
use kernel::utilities::cells::{OptionalCell, TakeCell};
use kernel::utilities::registers::interfaces::{Readable, Writeable};
use kernel::utilities::registers::{register_bitfields, ReadOnly, ReadWrite, WriteOnly};
use kernel::utilities::StaticRef;
use kernel::ErrorCode;
#[allow(dead_code)]
#[derive(Copy, Clone)]
enum ConfidentialityMode {
ECB = 0,
CBC = 1,
CFB = 2,
OFB = 3,
CTR = 4,
}
#[repr(C)]
struct AesRegisters {
ctrl: ReadWrite<u32, Control::Register>, mode: ReadWrite<u32, Mode::Register>, databufptr: ReadWrite<u32, DataBuf::Register>, sr: ReadOnly<u32, Status::Register>, ier: WriteOnly<u32, Interrupt::Register>, idr: WriteOnly<u32, Interrupt::Register>, imr: ReadOnly<u32, Interrupt::Register>, _reserved0: [u32; 1], key0: WriteOnly<u32, Key::Register>, key1: WriteOnly<u32, Key::Register>, key2: WriteOnly<u32, Key::Register>, key3: WriteOnly<u32, Key::Register>, key4: WriteOnly<u32, Key::Register>, key5: WriteOnly<u32, Key::Register>, key6: WriteOnly<u32, Key::Register>, key7: WriteOnly<u32, Key::Register>, initvect0: WriteOnly<u32, InitVector::Register>, initvect1: WriteOnly<u32, InitVector::Register>, initvect2: WriteOnly<u32, InitVector::Register>, initvect3: WriteOnly<u32, InitVector::Register>, idata: WriteOnly<u32, Data::Register>, _reserved1: [u32; 3], odata: ReadOnly<u32, Data::Register>, _reserved2: [u32; 3], drngseed: WriteOnly<u32, DrngSeed::Register>, parameter: ReadOnly<u32, Parameter::Register>, version: ReadOnly<u32, Version::Register>, }
register_bitfields![u32,
Control [
ENABLE 0,
DKEYGEN 1,
NEWMSG 2,
SWSRT 8
],
Mode [
CTYPE4 OFFSET(19) NUMBITS(1) [],
CTYPE3 OFFSET(18) NUMBITS(1) [],
CTYPE2 OFFSET(17) NUMBITS(1) [],
CTYPE1 OFFSET(16) NUMBITS(1) [],
CFBS OFFSET(8) NUMBITS(3) [
Bits128 = 0,
Bits64 = 1,
Bits32 = 2,
Bits16 = 3,
Bits8 = 4
],
OPMODE OFFSET(4) NUMBITS(3) [
ECB = 0,
CBC = 1,
CFB = 2,
OFB = 3,
CTR = 4
],
DMA OFFSET(3) NUMBITS(1) [],
ENCRYPT OFFSET(0) NUMBITS(1) []
],
DataBuf [
ODATAW OFFSET(4) NUMBITS(2) [],
IDATAW OFFSET(0) NUMBITS(2) []
],
Status [
IBUFRDY 16,
ODATARDY 0
],
Interrupt [
IBUFRDY 16,
ODATARDY 0
],
Key [
KEY OFFSET(0) NUMBITS(32) []
],
InitVector [
VECTOR OFFSET(0) NUMBITS(32) []
],
Data [
DATA OFFSET(0) NUMBITS(32) []
],
DrngSeed [
SEED OFFSET(0) NUMBITS(32) []
],
Parameter [
CTRMEAS OFFSET(8) NUMBITS(1) [
Implemented = 0,
NotImplemented = 1
],
OPMODE OFFSET(2) NUMBITS(3) [
ECB = 0,
ECB_CBC = 1,
ECB_CBC_CFB = 2,
ECB_CBC_CFB_OFB = 3,
ECB_CBC_CFB_OFB_CTR = 4
],
MAXKEYSIZE OFFSET(0) NUMBITS(2) [
Bits128 = 0,
Bits192 = 1,
Bits256 = 2
]
],
Version [
VARIANT OFFSET(16) NUMBITS(4),
VERSION OFFSET(0) NUMBITS(12)
]
];
const AES_BASE: StaticRef<AesRegisters> =
unsafe { StaticRef::new(0x400B0000 as *const AesRegisters) };
pub struct Aes<'a> {
registers: StaticRef<AesRegisters>,
client: OptionalCell<&'a dyn hil::symmetric_encryption::Client<'a>>,
source: TakeCell<'static, [u8]>,
dest: TakeCell<'static, [u8]>,
write_index: Cell<usize>,
read_index: Cell<usize>,
stop_index: Cell<usize>,
}
impl<'a> Aes<'a> {
pub fn new() -> Aes<'a> {
Aes {
registers: AES_BASE,
client: OptionalCell::empty(),
source: TakeCell::empty(),
dest: TakeCell::empty(),
write_index: Cell::new(0),
read_index: Cell::new(0),
stop_index: Cell::new(0),
}
}
fn enable_clock(&self) {
pm::enable_clock(pm::Clock::HSB(pm::HSBClock::AESA));
scif::generic_clock_enable_divided(
scif::GenericClock::GCLK4,
scif::ClockSource::CLK_CPU,
1,
);
scif::generic_clock_enable(scif::GenericClock::GCLK4, scif::ClockSource::CLK_CPU);
}
fn disable_clock(&self) {
scif::generic_clock_disable(scif::GenericClock::GCLK4);
pm::disable_clock(pm::Clock::HSB(pm::HSBClock::AESA));
}
fn enable_interrupts(&self) {
self.registers
.ier
.write(Interrupt::IBUFRDY.val(1) + Interrupt::ODATARDY.val(1));
}
fn disable_interrupts(&self) {
self.registers
.idr
.write(Interrupt::IBUFRDY.val(1) + Interrupt::ODATARDY.val(1));
}
fn disable_input_interrupt(&self) {
self.registers.idr.write(Interrupt::IBUFRDY.val(1));
}
fn busy(&self) -> bool {
(self.registers.imr.read(Interrupt::IBUFRDY) | self.registers.imr.read(Interrupt::ODATARDY))
!= 0
}
fn set_mode(&self, encrypting: bool, mode: ConfidentialityMode) {
let encrypt = u32::from(encrypting);
let dma = 0;
self.registers.mode.write(
Mode::ENCRYPT.val(encrypt)
+ Mode::DMA.val(dma)
+ Mode::OPMODE.val(mode as u32)
+ Mode::CTYPE4.val(1)
+ Mode::CTYPE3.val(1)
+ Mode::CTYPE2.val(1)
+ Mode::CTYPE1.val(1),
);
}
fn input_buffer_ready(&self) -> bool {
self.registers.sr.read(Status::IBUFRDY) != 0
}
fn output_data_ready(&self) -> bool {
self.registers.sr.read(Status::ODATARDY) != 0
}
fn try_set_indices(&self, start_index: usize, stop_index: usize) -> bool {
stop_index.checked_sub(start_index).is_some_and(|sublen| {
sublen % AES128_BLOCK_SIZE == 0 && {
self.source.map_or_else(
|| {
if self.dest.map_or(false, |dest| stop_index <= dest.len()) {
self.write_index.set(start_index);
self.read_index.set(start_index);
self.stop_index.set(stop_index);
true
} else {
false
}
},
|source| {
if sublen == source.len()
&& self.dest.map_or(false, |dest| stop_index <= dest.len())
{
self.write_index.set(0);
self.read_index.set(start_index);
self.stop_index.set(stop_index);
true
} else {
false
}
},
)
}
})
}
fn write_block(&self) -> bool {
self.source.map_or_else(
|| {
self.dest.map_or_else(
|| {
debug!("Called write_block() with no data");
false
},
|dest| {
let index = self.write_index.get();
let more = index + AES128_BLOCK_SIZE <= self.stop_index.get();
if !more {
return false;
}
for i in 0..4 {
let mut v = dest[index + (i * 4) + 0] as usize;
v |= (dest[index + (i * 4) + 1] as usize) << 8;
v |= (dest[index + (i * 4) + 2] as usize) << 16;
v |= (dest[index + (i * 4) + 3] as usize) << 24;
self.registers.idata.set(v as u32);
}
self.write_index.set(index + AES128_BLOCK_SIZE);
let more =
self.write_index.get() + AES128_BLOCK_SIZE <= self.stop_index.get();
more
},
)
},
|source| {
let index = self.write_index.get();
let more = index + AES128_BLOCK_SIZE <= source.len();
if !more {
return false;
}
for i in 0..4 {
let mut v = source[index + (i * 4) + 0] as usize;
v |= (source[index + (i * 4) + 1] as usize) << 8;
v |= (source[index + (i * 4) + 2] as usize) << 16;
v |= (source[index + (i * 4) + 3] as usize) << 24;
self.registers.idata.set(v as u32);
}
self.write_index.set(index + AES128_BLOCK_SIZE);
let more = self.write_index.get() + AES128_BLOCK_SIZE <= source.len();
more
},
)
}
fn read_block(&self) -> bool {
self.dest.map_or_else(
|| {
debug!("Called read_block() with no data");
false
},
|dest| {
let index = self.read_index.get();
let more = index + AES128_BLOCK_SIZE <= self.stop_index.get();
if !more {
return false;
}
for i in 0..4 {
let v = self.registers.odata.get();
dest[index + (i * 4) + 0] = (v >> 0) as u8;
dest[index + (i * 4) + 1] = (v >> 8) as u8;
dest[index + (i * 4) + 2] = (v >> 16) as u8;
dest[index + (i * 4) + 3] = (v >> 24) as u8;
}
self.read_index.set(index + AES128_BLOCK_SIZE);
let more = self.read_index.get() + AES128_BLOCK_SIZE <= self.stop_index.get();
more
},
)
}
pub fn handle_interrupt(&self) {
if !self.busy() {
return;
}
if self.input_buffer_ready() {
if !self.write_block() {
self.disable_input_interrupt();
}
}
if self.output_data_ready() {
if !self.read_block() {
self.disable_interrupts();
self.client.map(|client| {
client.crypt_done(self.source.take(), self.dest.take().unwrap());
});
}
}
}
}
impl<'a> hil::symmetric_encryption::AES128<'a> for Aes<'a> {
fn enable(&self) {
self.enable_clock();
self.registers.ctrl.write(Control::ENABLE.val(1));
}
fn disable(&self) {
self.registers.ctrl.set(0);
self.disable_clock();
}
fn set_client(&'a self, client: &'a dyn hil::symmetric_encryption::Client<'a>) {
self.client.set(client);
}
fn set_key(&self, key: &[u8]) -> Result<(), ErrorCode> {
if key.len() != AES128_KEY_SIZE {
return Err(ErrorCode::INVAL);
}
for i in 0..4 {
let mut k = key[i * 4 + 0] as usize;
k |= (key[i * 4 + 1] as usize) << 8;
k |= (key[i * 4 + 2] as usize) << 16;
k |= (key[i * 4 + 3] as usize) << 24;
match i {
0 => self.registers.key0.set(k as u32),
1 => self.registers.key1.set(k as u32),
2 => self.registers.key2.set(k as u32),
3 => self.registers.key3.set(k as u32),
_ => {}
}
}
Ok(())
}
fn set_iv(&self, iv: &[u8]) -> Result<(), ErrorCode> {
if iv.len() != AES128_BLOCK_SIZE {
return Err(ErrorCode::INVAL);
}
for i in 0..4 {
let mut c = iv[i * 4 + 0] as usize;
c |= (iv[i * 4 + 1] as usize) << 8;
c |= (iv[i * 4 + 2] as usize) << 16;
c |= (iv[i * 4 + 3] as usize) << 24;
match i {
0 => self.registers.initvect0.set(c as u32),
1 => self.registers.initvect1.set(c as u32),
2 => self.registers.initvect2.set(c as u32),
3 => self.registers.initvect3.set(c as u32),
_ => {}
}
}
Ok(())
}
fn start_message(&self) {
if self.busy() {
return;
}
self.registers
.ctrl
.write(Control::NEWMSG.val(1) + Control::ENABLE.val(1));
}
fn crypt(
&self,
source: Option<&'static mut [u8]>,
dest: &'static mut [u8],
start_index: usize,
stop_index: usize,
) -> Option<(
Result<(), ErrorCode>,
Option<&'static mut [u8]>,
&'static mut [u8],
)> {
if self.busy() {
Some((Err(ErrorCode::BUSY), source, dest))
} else {
self.source.put(source);
self.dest.replace(dest);
if self.try_set_indices(start_index, stop_index) {
self.enable_interrupts();
None
} else {
Some((
Err(ErrorCode::INVAL),
self.source.take(),
self.dest.take().unwrap(),
))
}
}
}
}
impl hil::symmetric_encryption::AES128Ctr for Aes<'_> {
fn set_mode_aes128ctr(&self, encrypting: bool) -> Result<(), ErrorCode> {
self.set_mode(encrypting, ConfidentialityMode::CTR);
Ok(())
}
}
impl hil::symmetric_encryption::AES128CBC for Aes<'_> {
fn set_mode_aes128cbc(&self, encrypting: bool) -> Result<(), ErrorCode> {
self.set_mode(encrypting, ConfidentialityMode::CBC);
Ok(())
}
}
impl kernel::hil::symmetric_encryption::AES128ECB for Aes<'_> {
fn set_mode_aes128ecb(&self, encrypting: bool) -> Result<(), ErrorCode> {
self.set_mode(encrypting, ConfidentialityMode::ECB);
Ok(())
}
}