mirror of
https://github.com/saymrwulf/xous-core.git
synced 2026-11-15 08:30:02 +00:00
Merge branch 'main' into source-date-epoch
This commit is contained in:
commit
4aba11df5f
8 changed files with 240 additions and 48 deletions
|
|
@ -20,7 +20,9 @@ use bao1x_api::{
|
|||
};
|
||||
use bao1x_api::{PARANOID_MODE, PARANOID_MODE_DUPE};
|
||||
use bao1x_hal::acram::OneWayCounter;
|
||||
use bao1x_hal::hardening::{check_pll, die, mesh_setup};
|
||||
use bao1x_hal::hardening::{
|
||||
check_pll, die, disable_clock_skipping, mesh_setup, reseed_skipping, setup_clock_skipping,
|
||||
};
|
||||
use bao1x_hal::sigcheck::{hardened_erase_policy, jump_to};
|
||||
#[cfg(feature = "unsafe-dev")]
|
||||
use critical_section::Mutex;
|
||||
|
|
@ -276,6 +278,7 @@ pub unsafe extern "C" fn rust_entry() -> ! {
|
|||
}
|
||||
}
|
||||
|
||||
let use_skipping = setup_clock_skipping(csprng.get_u32());
|
||||
let (paranoid1, paranoid2) = owc.hardened_get2(PARANOID_MODE, PARANOID_MODE_DUPE).unwrap();
|
||||
|
||||
// == self-validate the image with the keys we put in, just to make sure our code wasn't tampered with ==
|
||||
|
|
@ -332,6 +335,9 @@ pub unsafe extern "C" fn rust_entry() -> ! {
|
|||
for configuration in boot_order {
|
||||
bollard!(die, 4);
|
||||
csprng.random_delay();
|
||||
if use_skipping {
|
||||
reseed_skipping(csprng.get_u32());
|
||||
}
|
||||
match bao1x_hal::sigcheck::validate_image(configuration, None, Some(&mut csprng)) {
|
||||
Ok((key, key_inv, tag, target)) => {
|
||||
if key != !key_inv {
|
||||
|
|
@ -352,6 +358,9 @@ pub unsafe extern "C" fn rust_entry() -> ! {
|
|||
}
|
||||
csprng.random_delay();
|
||||
bollard!(die, 4);
|
||||
if use_skipping {
|
||||
disable_clock_skipping();
|
||||
}
|
||||
jump_to((target ^ u32::from_le_bytes(tag)) as usize);
|
||||
}
|
||||
Err(e) => {
|
||||
|
|
|
|||
|
|
@ -48,6 +48,7 @@ print-ifr = []
|
|||
|
||||
test-boot0-keys = []
|
||||
alt-boot1 = []
|
||||
test-clock-skipping = []
|
||||
|
||||
oem = []
|
||||
oem-baosec-lite = ["oem", "bao1x-hal/oem-baosec-lite"]
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ use alloc::vec::Vec;
|
|||
use bao1x_api::pubkeys::BOOT0_TO_BOOT1;
|
||||
#[allow(unused_imports)]
|
||||
use bao1x_api::*;
|
||||
use bao1x_hal::acram::OneWayCounter;
|
||||
use bao1x_hal::hardening::Csprng;
|
||||
use bao1x_hal::acram::{OneWayCounter, SlotManager};
|
||||
use bao1x_hal::hardening::{Csprng, skipping_enabled};
|
||||
use utralib::*;
|
||||
|
||||
pub struct Error {
|
||||
|
|
@ -240,6 +240,65 @@ impl Repl {
|
|||
));
|
||||
}
|
||||
}
|
||||
"skipping" => {
|
||||
let slot_mgr = SlotManager::new();
|
||||
if args.len() != 1 {
|
||||
return Err(Error::help("skipping [check | enable | disable]"));
|
||||
}
|
||||
if args[0] == "check" {
|
||||
let skipping_cfg = slot_mgr.read(&bao1x_api::CLOCK_SCRAMBLE_PARAMS).unwrap();
|
||||
crate::println!("Clock skipping: {:?}", skipping_enabled(skipping_cfg));
|
||||
} else if args[0] == "enable" {
|
||||
bao1x_hal::hardening::enable_skipping();
|
||||
} else if args[0] == "disable" {
|
||||
bao1x_hal::hardening::disable_skipping();
|
||||
} else {
|
||||
return Err(Error::help("skipping [check | enable | disable]"));
|
||||
}
|
||||
}
|
||||
#[cfg(feature = "test-clock-skipping")]
|
||||
"bogomips" => {
|
||||
crate::println!("start test");
|
||||
bao1x_hal::hardening::enable_skipping();
|
||||
// start the RTC
|
||||
let mut ao_sysctrl = CSR::new(utralib::HW_AO_SYSCTRL_BASE as *mut u32);
|
||||
ao_sysctrl.wo(utra::ao_sysctrl::CR_CLK1HZFD, 0x3fff);
|
||||
unsafe { (0x4006100c as *mut u32).write_volatile(1) };
|
||||
let mut count: usize;
|
||||
unsafe {
|
||||
#[rustfmt::skip]
|
||||
core::arch::asm!(
|
||||
// grab the RTC value
|
||||
"li t0, 0x40061000",
|
||||
"lw t1, 0x0(t0)",
|
||||
"li t3, 0",
|
||||
// wait until the next second
|
||||
"10:",
|
||||
"lw t2, 0x0(t0)",
|
||||
"beq t1, t2, 10b",
|
||||
// start of test
|
||||
"20:",
|
||||
// count outer loops
|
||||
"addi t3, t3, 1",
|
||||
// inner loop 10,000 times
|
||||
"li t4, 10000",
|
||||
"30:",
|
||||
"addi t4, t4, -1",
|
||||
"bne x0, t4, 30b",
|
||||
// after inner loop, check current time; do another outer loop if time is same
|
||||
"lw t1, 0x0(t0)",
|
||||
"beq t1, t2, 20b",
|
||||
out("t0") _,
|
||||
out("t1") _,
|
||||
out("t2") _,
|
||||
out("t3") count,
|
||||
out("t4") _,
|
||||
);
|
||||
}
|
||||
crate::println!("{}.{} bogomips", (count * 2 * 10_000) / 1_000_000, (count * 2) % 10_000);
|
||||
bao1x_hal::hardening::disable_skipping();
|
||||
ao_sysctrl.wo(utra::ao_sysctrl::CR_CLK1HZFD, 15);
|
||||
}
|
||||
"boardtype" => {
|
||||
let one_way = OneWayCounter::new();
|
||||
if args.len() == 0 {
|
||||
|
|
@ -581,7 +640,7 @@ impl Repl {
|
|||
_ => {
|
||||
crate::println!("Command not recognized: {}", cmd);
|
||||
crate::print!(
|
||||
"Commands include: reset, echo, altboot, boot, bootwait, idmode, localecho, uf2, boardtype, audit, lockdown, paranoid, self_destruct, ifr"
|
||||
"Commands include: reset, echo, altboot, boot, bootwait, idmode, localecho, uf2, boardtype, audit, lockdown, paranoid, self_destruct, ifr, skipping"
|
||||
);
|
||||
#[cfg(feature = "test-boot0-keys")]
|
||||
crate::print!(", publock");
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
use bao1x_api::{
|
||||
DEVELOPER_MODE, PARANOID_MODE, PARANOID_MODE_DUPE, bollard, pubkeys::BOOT1_TO_LOADER_OR_BAREMETAL,
|
||||
};
|
||||
use bao1x_hal::hardening::Csprng;
|
||||
use bao1x_hal::hardening::{Csprng, disable_clock_skipping, reseed_skipping, setup_clock_skipping};
|
||||
|
||||
#[inline(always)]
|
||||
fn seal_boot1_keys() {
|
||||
|
|
@ -19,6 +19,7 @@ fn seal_boot1_keys() {
|
|||
}
|
||||
|
||||
pub fn try_boot(or_die: bool, csprng: &mut Csprng) {
|
||||
let use_skipping = setup_clock_skipping(csprng.get_u32());
|
||||
let one_way = bao1x_hal::acram::OneWayCounter::new();
|
||||
bollard!(bao1x_hal::sigcheck::die_no_std, 4);
|
||||
|
||||
|
|
@ -96,6 +97,9 @@ pub fn try_boot(or_die: bool, csprng: &mut Csprng) {
|
|||
// double up the security check if in paranoid mode
|
||||
csprng.random_delay();
|
||||
if paranoid1 != 0 || paranoid2 != 0 {
|
||||
if use_skipping {
|
||||
reseed_skipping(csprng.get_u32());
|
||||
}
|
||||
bollard!(bao1x_hal::sigcheck::die_no_std, 4);
|
||||
bao1x_hal::sigcheck::validate_image(BOOT1_TO_LOADER_OR_BAREMETAL, None, Some(csprng))
|
||||
.unwrap_or_else(|_| bao1x_hal::hardening::die());
|
||||
|
|
@ -108,6 +112,9 @@ pub fn try_boot(or_die: bool, csprng: &mut Csprng) {
|
|||
// like we do in boot0.
|
||||
seal_boot1_keys();
|
||||
bollard!(bao1x_hal::sigcheck::die_no_std, 4);
|
||||
if use_skipping {
|
||||
disable_clock_skipping();
|
||||
}
|
||||
bao1x_hal::sigcheck::jump_to((target ^ u32::from_le_bytes(tag)) as usize);
|
||||
}
|
||||
Err(e) => crate::println!("Image did not validate: {:?}", e),
|
||||
|
|
@ -116,4 +123,7 @@ pub fn try_boot(or_die: bool, csprng: &mut Csprng) {
|
|||
crate::println!("No valid loader or baremetal image found. Halting!");
|
||||
bao1x_hal::sigcheck::die_no_std();
|
||||
}
|
||||
if use_skipping {
|
||||
disable_clock_skipping();
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -42,33 +42,6 @@ pub const CPU_VDD_LDO_BOOT_MV: u32 = 810;
|
|||
pub const DEFAULT_FCLK_FREQUENCY: u32 = 700_000_000;
|
||||
|
||||
// =========== KEY SLOTS ==============
|
||||
/// The `ROOT_SEED` is the "mothership" secret that all device identity and secrets
|
||||
/// are derived from. The seed may be blended with other bits of data scattered about
|
||||
/// the RRAM array, other device identifiers and hardware measurements to create the final
|
||||
/// device secret key.
|
||||
pub const ROOT_SEED: SlotIndex = SlotIndex::Data(256, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// The `RMA_KEY` is a secret parameter that is unique per-device secret which is recorded
|
||||
/// at manufacturing time. Its purpose is to facilitate the creation of a signed RMA
|
||||
/// authorization certificate which upon receipt would blank the device and unlock various
|
||||
/// features for debugging failed hardware.
|
||||
pub const RMA_KEY: SlotIndex = SlotIndex::Data(257, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// Reserved for use as a CP to FT tracking cookie. This is used to help track inventory
|
||||
/// between CP and FT, if such a feature is desired in the supply chain. Blanked on entry
|
||||
/// to developer mode.
|
||||
pub const CP_COOKIE: SlotIndex = SlotIndex::Data(258, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// The swap encryption key. Used to protect swap images beyond the signing key, if we so desire.
|
||||
pub const SWAP_KEY: SlotIndex = SlotIndex::Data(259, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// A test value placed by FT into the memory array. If you can read the original value, you've captured a
|
||||
/// flag!
|
||||
/// There is a second flag stored somewhere else. Can you find it?
|
||||
pub const THE_FLAG_1: SlotIndex = SlotIndex::Data(260, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
// NOTE: COLLATERAL is from 261..265, but it is in the "common" page
|
||||
|
||||
/// `NUISANCE_KEYS` are hashed together with `ROOT_SEED` to derive the core secret.
|
||||
/// Their primary purpose is to annoy microscopists trying to read the secret key by
|
||||
/// directly imaging the RRAM array. They also exist to reduce power side channels
|
||||
|
|
@ -89,15 +62,14 @@ pub const THE_FLAG_1: SlotIndex = SlotIndex::Data(260, PartitionAccess::Fw0, RwP
|
|||
/// is convenient because that's the natural page size over which the key range will be carved up before
|
||||
/// handing to other processes.
|
||||
///
|
||||
/// The first 8 keys in bank 0 of NUISANCE_KEYS is not used. This is because due to an ECO in the A1
|
||||
/// spin of silicon, the JTAG-wired access control on these is going to be tied to those on the similarly
|
||||
/// numbered data slots. Some of the data slots in the first 8 slots will be read-only at CP time, and
|
||||
/// thus they can't be initialized with random data and be used as a nuisance key. This is a minor degradation
|
||||
/// in security margin.
|
||||
/// The first 8 keys in bank 0 of NUISANCE_KEYS alias with data slots 0..7. This is because due to an ECO in
|
||||
/// the A1 spin of silicon that effectively removes the key bank, meaning only data banks exist.
|
||||
/// The IFR-managed access control on these is going to be tied to those on the similarly numbered data slots,
|
||||
/// and the control happens on a stride of 8 slots at a time.
|
||||
///
|
||||
/// Notice there is a second range of nuisance keys at the end of the slot range (1920..2048), stuck there
|
||||
/// to force spatial diversity in the nuisance keys.
|
||||
pub const NUISANCE_KEYS_0: SlotIndex = SlotIndex::DataRange(8..128, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
pub const NUISANCE_KEYS_1: SlotIndex =
|
||||
SlotIndex::DataRange(1920..2048, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
pub const NUISANCE_KEYS: [SlotIndex; 2] = [NUISANCE_KEYS_0, NUISANCE_KEYS_1];
|
||||
|
||||
/// `CHAFF_KEYS` are a bank of keys that are hashed into the key array, but instead of
|
||||
/// being read out in strict order, they are read in a random permutation every time.
|
||||
|
|
@ -131,7 +103,41 @@ pub const CHAFF_KEYS: SlotIndex = SlotIndex::DataRange(128..256, PartitionAccess
|
|||
/// Placing this at the end of the key array ostensibly means that all the keys before it were
|
||||
/// erased; it might be possible to glitch all the way to the end and just have this one erased
|
||||
/// but I think that is reasonably unlikely...
|
||||
pub const ERASE_PROOF: SlotIndex = SlotIndex::Data(256, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
pub const ERASE_PROOF: SlotIndex = SlotIndex::Data(255, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// The `ROOT_SEED` is the "mothership" secret that all device identity and secrets
|
||||
/// are derived from. The seed may be blended with other bits of data scattered about
|
||||
/// the RRAM array, other device identifiers and hardware measurements to create the final
|
||||
/// device secret key.
|
||||
pub const ROOT_SEED: SlotIndex = SlotIndex::Data(256, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// The `RMA_KEY` is a secret parameter that is unique per-device secret which is recorded
|
||||
/// at manufacturing time. Its purpose is to facilitate the creation of a signed RMA
|
||||
/// authorization certificate which upon receipt would blank the device and unlock various
|
||||
/// features for debugging failed hardware.
|
||||
pub const RMA_KEY: SlotIndex = SlotIndex::Data(257, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// Reserved for use as a CP to FT tracking cookie. This is used to help track inventory
|
||||
/// between CP and FT, if such a feature is desired in the supply chain. Blanked on entry
|
||||
/// to developer mode.
|
||||
pub const CP_COOKIE: SlotIndex = SlotIndex::Data(258, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// The swap encryption key. Used to protect swap images beyond the signing key, if we so desire.
|
||||
pub const SWAP_KEY: SlotIndex = SlotIndex::Data(259, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
/// A test value placed by FT into the memory array. If you can read the original value, you've captured a
|
||||
/// flag!
|
||||
/// There is a second flag stored somewhere else. Can you find it?
|
||||
pub const THE_FLAG_1: SlotIndex = SlotIndex::Data(260, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
|
||||
// [261..=383] reserved for Baochip data slot usage, see the "common" page for more details
|
||||
// NOTE: COLLATERAL is from 261..265, but it is in the "common" page
|
||||
|
||||
// [384..=1919] are unused and available for third party use
|
||||
|
||||
pub const NUISANCE_KEYS_1: SlotIndex =
|
||||
SlotIndex::DataRange(1920..2048, PartitionAccess::Fw0, RwPerms::ReadWrite);
|
||||
pub const NUISANCE_KEYS: [SlotIndex; 2] = [NUISANCE_KEYS_0, NUISANCE_KEYS_1];
|
||||
|
||||
/// All the slots of concern located in a single iterator. The idea is that everything is
|
||||
/// condensed here and used to check for access integrity using the array below.
|
||||
|
|
|
|||
|
|
@ -237,6 +237,8 @@ pub const BAO2_PUBKEY: SlotIndex = SlotIndex::Data(5, PartitionAccess::All, RwPe
|
|||
pub const BETA_PUBKEY: SlotIndex = SlotIndex::Data(6, PartitionAccess::All, RwPerms::ReadOnly);
|
||||
pub const DEV_PUBKEY: SlotIndex = SlotIndex::Data(7, PartitionAccess::All, RwPerms::ReadOnly);
|
||||
|
||||
// [8..=260 used as nuisance and master keys]
|
||||
|
||||
/// Collateral is a data range that is *always* erased every time the system transitions from boot0
|
||||
/// to a Baochip-signed boot1. The only condition under which it is not erased is if *all* the boot1 keys
|
||||
/// in slots 0, 1, *and* 2 do *not* match the Baochip set.
|
||||
|
|
@ -269,6 +271,14 @@ pub const BOOT1_PK_RECEIPT_SLOT3: SlotIndex = SlotIndex::Data(268, PartitionAcce
|
|||
pub const BOOT1_RECEIPT_SLOTS: [SlotIndex; 4] =
|
||||
[BOOT1_PK_RECEIPT_SLOT0, BOOT1_PK_RECEIPT_SLOT1, BOOT1_PK_RECEIPT_SLOT2, BOOT1_PK_RECEIPT_SLOT3];
|
||||
|
||||
// [269..=271] reserved for future use
|
||||
|
||||
// 32 bytes reserved to configure/set up clock scrambling
|
||||
pub const CLOCK_SCRAMBLE_PARAMS: SlotIndex = SlotIndex::Data(272, PartitionAccess::Open, RwPerms::ReadWrite);
|
||||
|
||||
// [273..=383] available for future data slot usage - in particular opentitan provisioning block (2k of data)
|
||||
// can fit in this with some margin.
|
||||
|
||||
// Notes on defining the boot0 IFR region.
|
||||
// RISC-V boot0 region start is defined by IFR slot 6, bits [55:48]
|
||||
// RISC-V boot1 region start (which is boot0 end) is defined by IFR slot 6, bits[47:40]
|
||||
|
|
|
|||
|
|
@ -133,6 +133,8 @@ impl Csprng {
|
|||
bao1x_api::bollard!(die, 4);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn get_u32(&mut self) -> u32 { self.csprng.next_u32() }
|
||||
}
|
||||
|
||||
#[inline(always)]
|
||||
|
|
@ -145,6 +147,81 @@ pub fn paranoid_mode() {
|
|||
sensor.wo(utra::sensorc::SFR_VDMASK1, 0); // putting 0 here makes the chip reset on glitch detect
|
||||
}
|
||||
|
||||
// getters to unpack the data slot
|
||||
pub fn skipping_enabled(cfg: &[u8]) -> bool { cfg[0] != 0 }
|
||||
pub fn skipping_config(cfg: &[u8]) -> u32 { u32::from_le_bytes(cfg[4..8].try_into().unwrap_or([0u8; 4])) }
|
||||
|
||||
pub fn enable_skipping() {
|
||||
let slot_mgr = crate::acram::SlotManager::new();
|
||||
let mut rram = crate::rram::Reram::new();
|
||||
// hard-coded config:
|
||||
// [0] => enable if != 0
|
||||
// [4] => bits [7:0] of cgu_sec
|
||||
// [5] => bits [15:8] of cgu_sec
|
||||
// enable for main clock:
|
||||
// assign clkcipherlevel = cgusec[3:0];
|
||||
// assign clkcipheren = cgusec[4];
|
||||
// enable for PKE engine:
|
||||
// assign clkpkecipherlevel = cgusec[11:8];
|
||||
// assign clkpkecipheren = cgusec[12];
|
||||
//
|
||||
// Pseudocode:
|
||||
// let prng: u8 = lfsr.get_u8();
|
||||
// if prng >= ((cipher_level as u8) << 4) {
|
||||
// clock_run
|
||||
// } else {
|
||||
// clock_skip
|
||||
// }
|
||||
//
|
||||
// A value of 2 for cipherlevel means, on average, 12.5% of clocks are skipped. This means the CPU
|
||||
// runs effectively this much slower.
|
||||
slot_mgr
|
||||
.write(
|
||||
&mut rram,
|
||||
&bao1x_api::CLOCK_SCRAMBLE_PARAMS,
|
||||
// tested
|
||||
// - skipping on PKE is OK
|
||||
// - skipping on CPU has some instability
|
||||
&[
|
||||
1, 0, 0, 0, 0b0_0010, 0b1_0010, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
|
||||
0, 0, 0, 0, 0, 0,
|
||||
],
|
||||
)
|
||||
.ok();
|
||||
}
|
||||
|
||||
pub fn disable_skipping() {
|
||||
let slot_mgr = crate::acram::SlotManager::new();
|
||||
let mut rram = crate::rram::Reram::new();
|
||||
slot_mgr.write(&mut rram, &bao1x_api::CLOCK_SCRAMBLE_PARAMS, &[0u8; 32]).ok();
|
||||
}
|
||||
|
||||
pub fn setup_clock_skipping(seed: u32) -> bool {
|
||||
let slot_mgr = crate::acram::SlotManager::new();
|
||||
let scramble_cfg = slot_mgr.read(&bao1x_api::CLOCK_SCRAMBLE_PARAMS).unwrap_or(&[0u8; 32]);
|
||||
let use_scrambling = skipping_enabled(scramble_cfg);
|
||||
if use_scrambling {
|
||||
let cgu_sec = skipping_config(scramble_cfg);
|
||||
let mut cgu = CSR::new(utra::sysctrl::HW_SYSCTRL_BASE as *mut u32);
|
||||
cgu.wo(utra::sysctrl::SFR_SEED, seed);
|
||||
cgu.wo(utra::sysctrl::SFR_SEEDAR, 0x5a);
|
||||
cgu.wo(utra::sysctrl::SFR_CGUSEC, cgu_sec);
|
||||
}
|
||||
use_scrambling
|
||||
}
|
||||
|
||||
pub fn disable_clock_skipping() {
|
||||
let mut cgu = CSR::new(utra::sysctrl::HW_SYSCTRL_BASE as *mut u32);
|
||||
cgu.wo(utra::sysctrl::SFR_CGUSEC, 0);
|
||||
cgu.wo(utra::sysctrl::SFR_CGUSEC, 0);
|
||||
}
|
||||
|
||||
pub fn reseed_skipping(seed: u32) {
|
||||
let mut cgu = CSR::new(utra::sysctrl::HW_SYSCTRL_BASE as *mut u32);
|
||||
cgu.wo(utra::sysctrl::SFR_SEED, seed);
|
||||
cgu.wo(utra::sysctrl::SFR_SEEDAR, 0x5a);
|
||||
}
|
||||
|
||||
/// This call clears any current alarms and resets sensors, but does not
|
||||
/// enable (or re-enable) interrupts
|
||||
pub fn reset_sensors() {
|
||||
|
|
@ -182,6 +259,12 @@ pub fn reset_sensors() {
|
|||
sensor.wo(utra::sensorc::SFR_LDCFG, 0xc);
|
||||
sensor.wo(utra::sensorc::SFR_LDMASK, 0x0); // turn on both sensors
|
||||
bao1x_api::bollard!(die, 4);
|
||||
|
||||
// enable SRAM parity alarms
|
||||
let mut sramtrm = CSR::new(utra::coresub_sramtrm::HW_CORESUB_SRAMTRM_BASE as *mut u32);
|
||||
// enables for all SRAM types:
|
||||
// assign { aorameven, iframeven, tcmeven, srameven } = ramsec;
|
||||
sramtrm.wo(utra::coresub_sramtrm::SFR_RAMSEC, 0xF);
|
||||
}
|
||||
|
||||
/// Mesh is a bit challenging to check on a fast-boot system. This is because it
|
||||
|
|
|
|||
|
|
@ -270,16 +270,30 @@ pub(crate) fn ensure_compiler(
|
|||
},
|
||||
};
|
||||
|
||||
let first_asset = match assets.first() {
|
||||
None => continue,
|
||||
Some(s) => s,
|
||||
};
|
||||
// Find the asset that matches the target architecture
|
||||
let matching_asset = assets.iter().find(|asset| {
|
||||
asset
|
||||
.get("name")
|
||||
.and_then(|n| n.as_str())
|
||||
.map(|name| {
|
||||
// Extract the toolchain prefix (everything before the version number)
|
||||
if let Some(toolchain_prefix) = name.split('_').next() {
|
||||
target.starts_with(toolchain_prefix)
|
||||
} else {
|
||||
false
|
||||
}
|
||||
})
|
||||
.unwrap_or(false)
|
||||
});
|
||||
|
||||
let download_url = match first_asset.get("browser_download_url") {
|
||||
let download_url = match matching_asset {
|
||||
None => continue,
|
||||
Some(s) => match s.as_str() {
|
||||
Some(asset) => match asset.get("browser_download_url") {
|
||||
None => continue,
|
||||
Some(s) => s,
|
||||
Some(s) => match s.as_str() {
|
||||
None => continue,
|
||||
Some(s) => s,
|
||||
},
|
||||
},
|
||||
};
|
||||
// println!("Candidate Release: {}", download_url);
|
||||
|
|
|
|||
Loading…
Reference in a new issue