Adds SHA256 Cryptocell code to bootloader (#432)
* adds bootloader code * fix header and typos
This commit is contained in:
@@ -15,6 +15,7 @@ cortex-m-rt = "*"
|
|||||||
cortex-m-rt-macros = "*"
|
cortex-m-rt-macros = "*"
|
||||||
panic-abort = "0.3.2"
|
panic-abort = "0.3.2"
|
||||||
rtt-target = { version = "*", features = ["cortex-m"] }
|
rtt-target = { version = "*", features = ["cortex-m"] }
|
||||||
|
tock-registers = { version = "0.6.0", features = ["no_std_unit_tests"] }
|
||||||
|
|
||||||
[profile.dev]
|
[profile.dev]
|
||||||
panic = "abort"
|
panic = "abort"
|
||||||
|
|||||||
118
bootloader/src/bitfields.rs
Normal file
118
bootloader/src/bitfields.rs
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2020-2022 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use tock_registers::register_bitfields;
|
||||||
|
|
||||||
|
register_bitfields! [u32,
|
||||||
|
// Generic or shared bitfields
|
||||||
|
pub Task [
|
||||||
|
ENABLE OFFSET(0) NUMBITS(1)
|
||||||
|
],
|
||||||
|
|
||||||
|
pub Byte [
|
||||||
|
VALUE OFFSET(0) NUMBITS(8)
|
||||||
|
],
|
||||||
|
|
||||||
|
pub Busy [
|
||||||
|
/// Asserted when AES_BUSY or DES_BUSY or HASH_BUSY are asserted or when the DIN FIFO is not empty
|
||||||
|
BUSY OFFSET(0) NUMBITS(1) [
|
||||||
|
Ready = 0,
|
||||||
|
Busy = 1
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
// CC_CTL register bitfields
|
||||||
|
pub CryptoMode [
|
||||||
|
/// Determines the active cryptographic engine
|
||||||
|
MODE OFFSET(0) NUMBITS(5) [
|
||||||
|
Bypass = 0,
|
||||||
|
Aes = 1,
|
||||||
|
AesToHash = 2,
|
||||||
|
AesAndHash = 3,
|
||||||
|
Des = 4,
|
||||||
|
DesToHash = 5,
|
||||||
|
DesAndHash = 6,
|
||||||
|
Hash = 7,
|
||||||
|
AesMacAndBypass = 9,
|
||||||
|
AesToHashAndDout = 10
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
// HOST_RGF register bitfields
|
||||||
|
pub Interrupts [
|
||||||
|
/// This interrupt is asserted when all data was delivered to DIN buffer from SRAM
|
||||||
|
SRAM_TO_DIN OFFSET(4) NUMBITS(1),
|
||||||
|
/// This interrupt is asserted when all data was delivered to SRAM buffer from DOUT
|
||||||
|
DOUT_TO_SRAM OFFSET(5) NUMBITS(1),
|
||||||
|
/// This interrupt is asserted when all data was delivered to DIN buffer from memory
|
||||||
|
MEM_TO_DIN OFFSET(6) NUMBITS(1),
|
||||||
|
/// This interrupt is asserted when all data was delivered to memory buffer from DOUT
|
||||||
|
DOUT_TO_MEM OFFSET(7) NUMBITS(1),
|
||||||
|
AXI_ERROR OFFSET(8) NUMBITS(1),
|
||||||
|
/// The PKA end of operation interrupt status
|
||||||
|
PKA_EXP OFFSET(9) NUMBITS(1),
|
||||||
|
/// The RNG interrupt status
|
||||||
|
RNG OFFSET(10) NUMBITS(1),
|
||||||
|
/// The GPR interrupt status
|
||||||
|
SYM_DMA_COMPLETED OFFSET(11) NUMBITS(1)
|
||||||
|
],
|
||||||
|
|
||||||
|
pub RgfEndianness [
|
||||||
|
/// DOUT write endianness
|
||||||
|
DOUT_WR_BG OFFSET(3) NUMBITS(1) [
|
||||||
|
LittleEndian = 0,
|
||||||
|
BigEndian = 1
|
||||||
|
],
|
||||||
|
/// DIN write endianness
|
||||||
|
DIN_RD_BG OFFSET(7) NUMBITS(1) [
|
||||||
|
LittleEndian = 0,
|
||||||
|
BigEndian = 1
|
||||||
|
],
|
||||||
|
/// DOUT write word endianness
|
||||||
|
DOUT_WR_WBG OFFSET(11) NUMBITS(1) [
|
||||||
|
LittleEndian = 0,
|
||||||
|
BigEndian = 1
|
||||||
|
],
|
||||||
|
/// DIN write word endianness
|
||||||
|
DIN_RD_WBG OFFSET(15) NUMBITS(1) [
|
||||||
|
LittleEndian = 0,
|
||||||
|
BigEndian = 1
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
// DIN and DOUT register bitfields
|
||||||
|
pub LliWord1 [
|
||||||
|
/// Total number of bytes to read using DMA in this entry
|
||||||
|
BYTES_NUM OFFSET(0) NUMBITS(30),
|
||||||
|
/// Indicates the first LLI entry
|
||||||
|
FIRST OFFSET(30) NUMBITS(1),
|
||||||
|
/// Indicates the last LLI entry
|
||||||
|
LAST OFFSET(31) NUMBITS(1)
|
||||||
|
],
|
||||||
|
|
||||||
|
pub HashControl [
|
||||||
|
// bit 2 is reserved but to simplify the logic we include it in the bitfield.
|
||||||
|
MODE OFFSET(0) NUMBITS(4) [
|
||||||
|
MD5 = 0,
|
||||||
|
SHA1 = 1,
|
||||||
|
SHA256 = 2,
|
||||||
|
SHA224 = 10
|
||||||
|
]
|
||||||
|
],
|
||||||
|
|
||||||
|
pub PaddingConfig [
|
||||||
|
/// Enable Padding generation. must be reset upon completion of padding.
|
||||||
|
DO_PAD OFFSET(2) NUMBITS(1)
|
||||||
|
]
|
||||||
|
];
|
||||||
283
bootloader/src/crypto_cell.rs
Normal file
283
bootloader/src/crypto_cell.rs
Normal file
@@ -0,0 +1,283 @@
|
|||||||
|
// Copyright 2019-2022 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
//! CryptoCell 310
|
||||||
|
//!
|
||||||
|
//! Author
|
||||||
|
//! -------------------
|
||||||
|
//!
|
||||||
|
//! * Author: Jean-Michel Picod <jmichel@google.com>
|
||||||
|
//! * Date: October 1 2019
|
||||||
|
|
||||||
|
use super::bitfields;
|
||||||
|
use super::registers::{CryptoCellRegisters, NordicCC310Registers};
|
||||||
|
use super::static_ref::StaticRef;
|
||||||
|
use core::cell::Cell;
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
use rtt_target::rprintln;
|
||||||
|
|
||||||
|
const SHA256_INIT_VALUE: [u32; 8] = [
|
||||||
|
0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A, 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19,
|
||||||
|
];
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum DigestAlgorithm {
|
||||||
|
Sha256 = 2,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone)]
|
||||||
|
enum OperationMode {
|
||||||
|
Idle,
|
||||||
|
Hash,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CryptoCell310 {
|
||||||
|
registers: StaticRef<CryptoCellRegisters>,
|
||||||
|
power: StaticRef<NordicCC310Registers>,
|
||||||
|
current_op: Cell<OperationMode>,
|
||||||
|
|
||||||
|
hash_ctx: Cell<[u32; 8]>,
|
||||||
|
hash_total_size: Cell<u64>,
|
||||||
|
}
|
||||||
|
|
||||||
|
const CC310_BASE: StaticRef<CryptoCellRegisters> =
|
||||||
|
unsafe { StaticRef::new(0x5002B000 as *const CryptoCellRegisters) };
|
||||||
|
const CC310_POWER: StaticRef<NordicCC310Registers> =
|
||||||
|
unsafe { StaticRef::new(0x5002A500 as *const NordicCC310Registers) };
|
||||||
|
|
||||||
|
// Identification "signature" for CryptoCell. According to the documentation, the value
|
||||||
|
// held by this register is a fixed value, used by Host driver to verify CryptoCell presence
|
||||||
|
// at this address.
|
||||||
|
// This value was read from a CryptoCell-310 on a nRF52840-dongle kit.
|
||||||
|
const CC310_SIGNATURE: u32 = 0x20E00000;
|
||||||
|
|
||||||
|
impl CryptoCell310 {
|
||||||
|
/// Creates a new instance of cryptocell state.
|
||||||
|
pub const fn new() -> Self {
|
||||||
|
CryptoCell310 {
|
||||||
|
registers: CC310_BASE,
|
||||||
|
power: CC310_POWER,
|
||||||
|
current_op: Cell::new(OperationMode::Idle),
|
||||||
|
|
||||||
|
hash_ctx: Cell::new(SHA256_INIT_VALUE),
|
||||||
|
hash_total_size: Cell::new(0),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn enable(&self) {
|
||||||
|
self.power.enable.write(bitfields::Task::ENABLE::SET);
|
||||||
|
for _i in 1..10 {
|
||||||
|
let read_signature = self.registers.host_rgf.signature.get();
|
||||||
|
if read_signature != CC310_SIGNATURE {
|
||||||
|
#[cfg(debug_assertions)]
|
||||||
|
rprintln!(
|
||||||
|
"[loop {}] Invalid CC310 signature. Expected {}, got {}\n",
|
||||||
|
_i,
|
||||||
|
CC310_SIGNATURE,
|
||||||
|
read_signature
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if self.registers.host_rgf.signature.get() != CC310_SIGNATURE {
|
||||||
|
panic!("Failed to initialize CC310");
|
||||||
|
}
|
||||||
|
// Make sure everything is set to little endian
|
||||||
|
self.registers.host_rgf.endian.write(
|
||||||
|
bitfields::RgfEndianness::DOUT_WR_BG::LittleEndian
|
||||||
|
+ bitfields::RgfEndianness::DIN_RD_BG::LittleEndian
|
||||||
|
+ bitfields::RgfEndianness::DOUT_WR_WBG::LittleEndian
|
||||||
|
+ bitfields::RgfEndianness::DIN_RD_WBG::LittleEndian,
|
||||||
|
);
|
||||||
|
// Always start the clock for DMA engine. It's too hard to keep
|
||||||
|
// track of which submodule needs DMA otherwise.
|
||||||
|
self.registers
|
||||||
|
.misc
|
||||||
|
.dma_clk_enable
|
||||||
|
.write(bitfields::Task::ENABLE::SET);
|
||||||
|
self.registers.host_rgf.interrupt_mask.write(
|
||||||
|
bitfields::Interrupts::SRAM_TO_DIN::CLEAR
|
||||||
|
+ bitfields::Interrupts::DOUT_TO_SRAM::CLEAR
|
||||||
|
+ bitfields::Interrupts::MEM_TO_DIN::CLEAR
|
||||||
|
+ bitfields::Interrupts::DOUT_TO_MEM::CLEAR
|
||||||
|
+ bitfields::Interrupts::AXI_ERROR::SET
|
||||||
|
+ bitfields::Interrupts::PKA_EXP::SET
|
||||||
|
+ bitfields::Interrupts::RNG::SET
|
||||||
|
+ bitfields::Interrupts::SYM_DMA_COMPLETED::CLEAR,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn disable(&self) {
|
||||||
|
self.registers.host_rgf.interrupt_mask.set(0);
|
||||||
|
self.power.enable.write(bitfields::Task::ENABLE::CLEAR);
|
||||||
|
self.registers
|
||||||
|
.misc
|
||||||
|
.dma_clk_enable
|
||||||
|
.write(bitfields::Task::ENABLE::CLEAR);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn clear_data(&self) {
|
||||||
|
let mut ctx = self.hash_ctx.get();
|
||||||
|
ctx.iter_mut().for_each(|b| *b = 0);
|
||||||
|
self.hash_ctx.set(ctx);
|
||||||
|
self.hash_total_size.set(0);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Adds data to the current hash computation.
|
||||||
|
///
|
||||||
|
/// You have to know in advance if is this is going to be the last block, and indicate that
|
||||||
|
/// correctly. Sizes of chunks before the last need to be multiples of 64.
|
||||||
|
pub fn update(&self, data: &[u8], is_last_block: bool) {
|
||||||
|
// Start CryptoCell
|
||||||
|
self.enable();
|
||||||
|
|
||||||
|
while self.registers.ctrl.hash_busy.is_set(bitfields::Busy::BUSY) {}
|
||||||
|
while self
|
||||||
|
.registers
|
||||||
|
.ctrl
|
||||||
|
.crypto_busy
|
||||||
|
.is_set(bitfields::Busy::BUSY)
|
||||||
|
{}
|
||||||
|
while self
|
||||||
|
.registers
|
||||||
|
.din
|
||||||
|
.mem_dma_busy
|
||||||
|
.is_set(bitfields::Busy::BUSY)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Start HASH module and configure it
|
||||||
|
self.current_op.set(OperationMode::Hash);
|
||||||
|
self.registers
|
||||||
|
.misc
|
||||||
|
.hash_clk_enable
|
||||||
|
.write(bitfields::Task::ENABLE::SET);
|
||||||
|
self.registers
|
||||||
|
.ctrl
|
||||||
|
.crypto_ctl
|
||||||
|
.write(bitfields::CryptoMode::MODE::Hash);
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.padding
|
||||||
|
.write(bitfields::Task::ENABLE::SET);
|
||||||
|
let size = self.hash_total_size.get();
|
||||||
|
self.registers.hash.hash_len_lsb.set(size as u32);
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.hash_len_msb
|
||||||
|
.set(size.wrapping_shr(32) as u32);
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.control
|
||||||
|
.set(DigestAlgorithm::Sha256 as u32);
|
||||||
|
|
||||||
|
// Digest must be set backwards because writing to HASH[0]
|
||||||
|
// starts computation
|
||||||
|
let mut digest = self.hash_ctx.get();
|
||||||
|
for i in (0..digest.len()).rev() {
|
||||||
|
self.registers.hash.hash[i].set(digest[i]);
|
||||||
|
}
|
||||||
|
while self.registers.ctrl.hash_busy.is_set(bitfields::Busy::BUSY) {}
|
||||||
|
|
||||||
|
// Process data
|
||||||
|
if !data.is_empty() {
|
||||||
|
if is_last_block {
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.auto_hw_padding
|
||||||
|
.write(bitfields::Task::ENABLE::SET);
|
||||||
|
}
|
||||||
|
self.registers.din.src_lli_word0.set(data.as_ptr() as u32);
|
||||||
|
self.registers
|
||||||
|
.din
|
||||||
|
.src_lli_word1
|
||||||
|
.write(bitfields::LliWord1::BYTES_NUM.val(data.len() as u32));
|
||||||
|
while !self
|
||||||
|
.registers
|
||||||
|
.host_rgf
|
||||||
|
.interrupts
|
||||||
|
.is_set(bitfields::Interrupts::MEM_TO_DIN)
|
||||||
|
{}
|
||||||
|
self.registers
|
||||||
|
.host_rgf
|
||||||
|
.interrupt_clear
|
||||||
|
.write(bitfields::Interrupts::MEM_TO_DIN::SET);
|
||||||
|
} else {
|
||||||
|
// use DO_PAD to complete padding of previous operation
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.pad_config
|
||||||
|
.write(bitfields::PaddingConfig::DO_PAD::SET);
|
||||||
|
}
|
||||||
|
while self
|
||||||
|
.registers
|
||||||
|
.ctrl
|
||||||
|
.crypto_busy
|
||||||
|
.is_set(bitfields::Busy::BUSY)
|
||||||
|
{}
|
||||||
|
while self
|
||||||
|
.registers
|
||||||
|
.din
|
||||||
|
.mem_dma_busy
|
||||||
|
.is_set(bitfields::Busy::BUSY)
|
||||||
|
{}
|
||||||
|
|
||||||
|
// Update context and total size
|
||||||
|
for i in (0..digest.len()).rev() {
|
||||||
|
digest[i] = self.registers.hash.hash[i].get();
|
||||||
|
}
|
||||||
|
self.hash_ctx.set(digest);
|
||||||
|
let new_size: u64 = ((self.registers.hash.hash_len_msb.get() as u64) << 32)
|
||||||
|
+ (self.registers.hash.hash_len_lsb.get() as u64);
|
||||||
|
self.hash_total_size.set(new_size);
|
||||||
|
|
||||||
|
// Disable HASH module
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.padding
|
||||||
|
.write(bitfields::Task::ENABLE::SET);
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.auto_hw_padding
|
||||||
|
.write(bitfields::Task::ENABLE::CLEAR);
|
||||||
|
self.registers
|
||||||
|
.hash
|
||||||
|
.pad_config
|
||||||
|
.write(bitfields::PaddingConfig::DO_PAD::CLEAR);
|
||||||
|
while self
|
||||||
|
.registers
|
||||||
|
.ctrl
|
||||||
|
.crypto_busy
|
||||||
|
.is_set(bitfields::Busy::BUSY)
|
||||||
|
{}
|
||||||
|
self.registers
|
||||||
|
.misc
|
||||||
|
.hash_clk_enable
|
||||||
|
.write(bitfields::Task::ENABLE::CLEAR);
|
||||||
|
|
||||||
|
self.disable();
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Clears the data for potential reuse, and returns the result.
|
||||||
|
pub fn finalize_and_clear(&self) -> [u8; 32] {
|
||||||
|
use byteorder::{BigEndian, ByteOrder};
|
||||||
|
let words = self.hash_ctx.get();
|
||||||
|
let mut bytes = [0u8; 32];
|
||||||
|
for (i, word) in words.iter().enumerate() {
|
||||||
|
BigEndian::write_u32(&mut bytes[4 * i..4 * i + 4], *word);
|
||||||
|
}
|
||||||
|
self.clear_data();
|
||||||
|
bytes
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,4 +1,4 @@
|
|||||||
// Copyright 2021 Google LLC
|
// Copyright 2021-2022 Google LLC
|
||||||
//
|
//
|
||||||
// Licensed under the Apache License, Version 2.0 (the "License");
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
// you may not use this file except in compliance with the License.
|
// you may not use this file except in compliance with the License.
|
||||||
@@ -15,6 +15,11 @@
|
|||||||
#![no_main]
|
#![no_main]
|
||||||
#![no_std]
|
#![no_std]
|
||||||
|
|
||||||
|
mod bitfields;
|
||||||
|
mod crypto_cell;
|
||||||
|
mod registers;
|
||||||
|
mod static_ref;
|
||||||
|
|
||||||
extern crate cortex_m;
|
extern crate cortex_m;
|
||||||
extern crate cortex_m_rt as rt;
|
extern crate cortex_m_rt as rt;
|
||||||
|
|
||||||
@@ -69,7 +74,7 @@ struct BootPartition {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl BootPartition {
|
impl BootPartition {
|
||||||
const _FIRMWARE_LENGTH: usize = 0x00040000;
|
const FIRMWARE_LENGTH: usize = 0x00040000;
|
||||||
|
|
||||||
/// Reads the metadata, returns the timestamp if all checks pass.
|
/// Reads the metadata, returns the timestamp if all checks pass.
|
||||||
pub fn read_timestamp(&self) -> Result<u32, ()> {
|
pub fn read_timestamp(&self) -> Result<u32, ()> {
|
||||||
@@ -93,18 +98,40 @@ impl BootPartition {
|
|||||||
Ok(metadata.timestamp)
|
Ok(metadata.timestamp)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Placeholder for the SHA256 implementation.
|
/// Computes the SHA256 of metadata information and partition data.
|
||||||
///
|
///
|
||||||
/// TODO implemented in next PR
|
/// Assumes that firmware address and length are divisible by the page size.
|
||||||
/// Without it, the bootloader will never boot anything.
|
/// This is the hardware implementation on the cryptocell.
|
||||||
fn compute_upgrade_hash(&self, _metadata_page: &[u8]) -> [u8; 32] {
|
#[allow(clippy::assertions_on_constants)]
|
||||||
[0; 32]
|
fn compute_upgrade_hash(&self, metadata_page: &[u8]) -> [u8; 32] {
|
||||||
|
debug_assert!(self.firmware_address % PAGE_SIZE == 0);
|
||||||
|
debug_assert!(BootPartition::FIRMWARE_LENGTH % PAGE_SIZE == 0);
|
||||||
|
let cc310 = crypto_cell::CryptoCell310::new();
|
||||||
|
for page_offset in (0..BootPartition::FIRMWARE_LENGTH).step_by(PAGE_SIZE) {
|
||||||
|
let page = unsafe { read_page(self.firmware_address + page_offset) };
|
||||||
|
cc310.update(&page, false);
|
||||||
|
}
|
||||||
|
cc310.update(&metadata_page[32..Metadata::DATA_LEN], true);
|
||||||
|
cc310.finalize_and_clear()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Jump to the firmware.
|
/// Jump to the firmware.
|
||||||
pub fn boot(&self) -> ! {
|
pub fn boot(&self) -> ! {
|
||||||
let address = self.firmware_address;
|
let address = self.firmware_address;
|
||||||
|
|
||||||
|
// Clear any pending Cryptocell interrupt in NVIC
|
||||||
|
let peripherals = cortex_m::Peripherals::take().unwrap();
|
||||||
|
unsafe {
|
||||||
|
// We could only clear cryptocell interrupts, but let's clean up before booting.
|
||||||
|
// Example code to clear more specifically:
|
||||||
|
// const CC310_IRQ: u16 = 42;
|
||||||
|
// peripherals.NVIC.icpr[usize::from(CC310_IRQ / 32)].write(1 << (CC310_IRQ % 32));
|
||||||
|
peripherals.NVIC.icer[0].write(0xffff_ffff);
|
||||||
|
peripherals.NVIC.icpr[0].write(0xffff_ffff);
|
||||||
|
peripherals.NVIC.icer[1].write(0xffff_ffff);
|
||||||
|
peripherals.NVIC.icpr[1].write(0xffff_ffff);
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(debug_assertions)]
|
#[cfg(debug_assertions)]
|
||||||
rprintln!("Boot jump to {:08X}", address);
|
rprintln!("Boot jump to {:08X}", address);
|
||||||
let address_pointer = address as *const u32;
|
let address_pointer = address as *const u32;
|
||||||
|
|||||||
139
bootloader/src/registers.rs
Normal file
139
bootloader/src/registers.rs
Normal file
@@ -0,0 +1,139 @@
|
|||||||
|
// Copyright 2020-2022 Google LLC
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
|
||||||
|
use super::bitfields::{
|
||||||
|
Busy, CryptoMode, HashControl, Interrupts, LliWord1, PaddingConfig, RgfEndianness, Task,
|
||||||
|
};
|
||||||
|
use tock_registers::{
|
||||||
|
register_structs,
|
||||||
|
registers::{ReadOnly, ReadWrite, WriteOnly},
|
||||||
|
};
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub CryptoCellControlRegisters {
|
||||||
|
/// Defines the cryptographic flow
|
||||||
|
(0x0000 => pub crypto_ctl: WriteOnly<u32, CryptoMode::Register>),
|
||||||
|
(0x0004 => _reserved0),
|
||||||
|
/// This register is set whent the cryptographic core is busy
|
||||||
|
(0x0010 => pub crypto_busy: ReadOnly<u32, Busy::Register>),
|
||||||
|
(0x0014 => _reserved1),
|
||||||
|
/// This register is set when the Hash engine is busy
|
||||||
|
(0x001C => pub hash_busy: ReadOnly<u32, Busy::Register>),
|
||||||
|
(0x0020 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub CryptoCellDinRegisters {
|
||||||
|
(0x0000 => _reserved0),
|
||||||
|
/// Indicates whether memoty (AXI) source DMA (DIN) is busy
|
||||||
|
(0x0020 => pub mem_dma_busy: ReadOnly<u32, Busy::Register>),
|
||||||
|
(0x0024 => _reserved1),
|
||||||
|
/// This register is used in direct LLI mode - holds the location of the data source
|
||||||
|
/// in the memory (AXI)
|
||||||
|
(0x0028 => pub src_lli_word0: WriteOnly<u32>),
|
||||||
|
/// This register is used in direct LLI mode - holds the number of bytes to be read
|
||||||
|
/// from the memory (AXI).
|
||||||
|
/// Writing to this register triggers the DMA.
|
||||||
|
(0x002C => pub src_lli_word1: WriteOnly<u32, LliWord1::Register>),
|
||||||
|
(0x0030 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub CryptoCellHashRegisters {
|
||||||
|
/// Write initial hash value or read final hash value
|
||||||
|
(0x0000 => pub hash: [ReadWrite<u32>; 9]),
|
||||||
|
(0x0024 => _reserved0),
|
||||||
|
/// HW padding automatically activated by engine.
|
||||||
|
/// For the special case of ZERO bytes data vector this register should not be used! instead use HASH_PAD_CFG
|
||||||
|
(0x0044 => pub auto_hw_padding: WriteOnly<u32, Task::Register>),
|
||||||
|
(0x0048 => _reserved1),
|
||||||
|
/// Selects which HASH mode to run
|
||||||
|
(0x0180 => pub control: ReadWrite<u32, HashControl::Register>),
|
||||||
|
/// This register enables the hash hw padding.
|
||||||
|
(0x0184 => pub padding: ReadWrite<u32, Task::Register>),
|
||||||
|
/// HASH_PAD_CFG Register.
|
||||||
|
(0x0188 => pub pad_config: ReadWrite<u32, PaddingConfig::Register>),
|
||||||
|
/// This register hold the length of current hash operation
|
||||||
|
(0x018C => pub hash_len_lsb: ReadWrite<u32>),
|
||||||
|
/// This register hold the length of current hash operation
|
||||||
|
(0x0190 => pub hash_len_msb: ReadWrite<u32>),
|
||||||
|
(0x0194 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub CryptoCellHostRgfRegisters {
|
||||||
|
/// The Interrupt Request register.
|
||||||
|
/// Each bit of this register holds the interrupt status of a single interrupt source.
|
||||||
|
(0x0000 => pub interrupts: ReadOnly<u32, Interrupts::Register>),
|
||||||
|
/// The Interrupt Mask register. Each bit of this register holds the mask of a single
|
||||||
|
/// interrupt source.
|
||||||
|
(0x0004 => pub interrupt_mask: ReadWrite<u32, Interrupts::Register>),
|
||||||
|
/// Interrupt Clear Register
|
||||||
|
(0x0008 => pub interrupt_clear: WriteOnly<u32, Interrupts::Register>),
|
||||||
|
/// This register defines the endianness of the Host-accessible registers.
|
||||||
|
(0x000C => pub endian: ReadWrite<u32, RgfEndianness::Register>),
|
||||||
|
(0x0010 => _reserved0),
|
||||||
|
/// This register holds the CryptoCell product signature.
|
||||||
|
(0x0024 => pub signature: ReadOnly<u32>),
|
||||||
|
(0x0028 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub CryptoCellMiscRegisters {
|
||||||
|
(0x0000 => _reserved0),
|
||||||
|
/// The HASH clock enable register
|
||||||
|
(0x0018 => pub hash_clk_enable: ReadWrite<u32, Task::Register>),
|
||||||
|
/// The PKA clock enable register
|
||||||
|
(0x001C => _reserved1),
|
||||||
|
/// The DMA clock enable register
|
||||||
|
(0x0020 => pub dma_clk_enable: ReadWrite<u32, Task::Register>),
|
||||||
|
/// the CryptoCell clocks' status register
|
||||||
|
(0x0024 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
register_structs! {
|
||||||
|
pub NordicCC310Registers {
|
||||||
|
(0x0000 => pub enable: ReadWrite<u32, Task::Register>),
|
||||||
|
(0x0004 => @END),
|
||||||
|
},
|
||||||
|
|
||||||
|
pub CryptoCellRegisters {
|
||||||
|
(0x0000 => _reserved0),
|
||||||
|
/// HASH registers
|
||||||
|
/// - Base address: 0x0640
|
||||||
|
(0x0640 => pub hash: CryptoCellHashRegisters),
|
||||||
|
(0x07D4 => _reserved1),
|
||||||
|
/// Misc registers
|
||||||
|
/// - Base address: 0x0800
|
||||||
|
(0x0800 => pub misc: CryptoCellMiscRegisters),
|
||||||
|
(0x0824 => _reserved2),
|
||||||
|
/// CryptoCell control registers
|
||||||
|
/// - Base address: 0x0900
|
||||||
|
(0x0900 => pub ctrl: CryptoCellControlRegisters),
|
||||||
|
(0x0920 => _reserved3),
|
||||||
|
/// HOST_RGF registers
|
||||||
|
/// - Base address: 0x0A00
|
||||||
|
(0x0A00 => pub host_rgf: CryptoCellHostRgfRegisters),
|
||||||
|
(0x0A28 => _reserved4),
|
||||||
|
/// DIN registers
|
||||||
|
/// - Base address: 0x0C00
|
||||||
|
(0x0C00 => pub din: CryptoCellDinRegisters),
|
||||||
|
(0x0C30 => @END),
|
||||||
|
}
|
||||||
|
}
|
||||||
46
bootloader/src/static_ref.rs
Normal file
46
bootloader/src/static_ref.rs
Normal file
@@ -0,0 +1,46 @@
|
|||||||
|
//! Wrapper type for safe pointers to static memory.
|
||||||
|
//!
|
||||||
|
//! Imported from:
|
||||||
|
//! https://github.com/tock/tock/blob/master/kernel/src/utilities/static_ref.rs
|
||||||
|
|
||||||
|
use core::ops::Deref;
|
||||||
|
|
||||||
|
/// A pointer to statically allocated mutable data such as memory mapped I/O
|
||||||
|
/// registers.
|
||||||
|
///
|
||||||
|
/// This is a simple wrapper around a raw pointer that encapsulates an unsafe
|
||||||
|
/// dereference in a safe manner. It serve the role of creating a `&'static T`
|
||||||
|
/// given a raw address and acts similarly to `extern` definitions, except
|
||||||
|
/// `StaticRef` is subject to module and crate boundaries, while `extern`
|
||||||
|
/// definitions can be imported anywhere.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct StaticRef<T> {
|
||||||
|
ptr: *const T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> StaticRef<T> {
|
||||||
|
/// Create a new `StaticRef` from a raw pointer
|
||||||
|
///
|
||||||
|
/// ## Safety
|
||||||
|
///
|
||||||
|
/// Callers must pass in a reference to statically allocated memory which
|
||||||
|
/// does not overlap with other values.
|
||||||
|
pub const unsafe fn new(ptr: *const T) -> StaticRef<T> {
|
||||||
|
StaticRef { ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Clone for StaticRef<T> {
|
||||||
|
fn clone(&self) -> Self {
|
||||||
|
StaticRef { ptr: self.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T> Copy for StaticRef<T> {}
|
||||||
|
|
||||||
|
impl<T> Deref for StaticRef<T> {
|
||||||
|
type Target = T;
|
||||||
|
fn deref(&self) -> &'static T {
|
||||||
|
unsafe { &*self.ptr }
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user