Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix approtect #130

Merged
merged 5 commits into from
Jan 7, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions firmware/build.rs
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,7 @@ fn memoryx(memoryx: String) {
);
let memoryx = memoryx.replace("SD_RAM_SIZE", &format!("{:#x}", layout.sd_ram_size));

// panic!("{}", memoryx); // for debugging
let out = path::PathBuf::from(env::var("OUT_DIR").unwrap());
fs::write(out.join("memory.x"), memoryx).unwrap();
println!("cargo:rustc-link-search={}", out.display());
Expand Down
31 changes: 0 additions & 31 deletions firmware/src/globals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,37 +32,6 @@ use defmt_rtt as _;

/// Sets up any global state
pub fn setup() {
// https://github.com/probe-rs/probe-rs/issues/1324#issuecomment-1356273774
// This is done because APProtect is enabled in some devices which basically
// disables writing and reading the flash.
// More info on the register:
// https://infocenter.nordicsemi.com/topic/com.nordic.infocenter.nrf52832.ps.v1.1/uicr.html
#[cfg(feature = "mcu-nrf52840")] // TODO: Add nrf52832 support
unsafe {
use nrf52840_pac as pac;
let ficr = &*pac::FICR::ptr();

// Get third character of the variant and check if it's the 'F' (0x46) character
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fficr.html&cp=4_0_0_3_3_0_8&anchor=register.INFO.VARIANT
if (ficr.info.variant.read().bits() & 0xff00) != 0x4600 {
let nvmc = &*pac::NVMC::ptr();

// UICR.APPROTECT = HwDisabled
if *(0x10001208 as *mut u32) != 0x0000_005a {
nvmc.config.write(|w| w.wen().wen());
while nvmc.ready.read().ready().is_busy() {}
core::ptr::write_volatile(0x10001208 as *mut u32, 0x0000_005a);
while nvmc.ready.read().ready().is_busy() {}
nvmc.config.reset();
while nvmc.ready.read().ready().is_busy() {}
cortex_m::peripheral::SCB::sys_reset();
}

// APPROTECT.DISABLE = SwDisabled
(0x4000_0558 as *mut u32).write_volatile(0x0000_005a);
}
}

// Initialize the global allocator BEFORE you use it
{
const HEAP_SIZE: usize = 10 * 1024;
Expand Down
79 changes: 79 additions & 0 deletions firmware/src/peripherals/nrf52.rs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,85 @@ pub fn get_peripherals() -> Peripherals<
UsbDriverConcrete<'static>,
> {
let p = embassy_nrf::init(Default::default());

// Fix issue on rev 3 boards where AP is protected, preventing debugging/rtt.
#[cfg(feature = "mcu-nrf52840")] // TODO: Add nrf52832 support
{
use defmt::{error, info};
use nrf52840_pac as pac;

let code = {
// Safety: should not have any references held elsewhere
let ficr = unsafe { &*pac::FICR::ptr() };
ficr.info.variant.read().bits().to_be_bytes()
};

// Get third character of the variant to determine hardware revision
// https://infocenter.nordicsemi.com/index.jsp?topic=%2Fps_nrf52840%2Fficr.html&cp=4_0_0_3_3_0_8&anchor=register.INFO.VARIANT
let rev = Revision::from_variant(code);
if let Some(rev) = rev {
info!("Chip revision: {}", rev);
if rev == Revision::Rev3 {
// Set UICR.APPROTECT to HwDisable and APPROTECT.DISABLE to SwDisable
// todo: Use an updated pac or hal to do this, when it comes out.
// This is dangerous because of the lack of proper atomics or against race conditions.
unsafe {
let nvmc = &*pac::NVMC::ptr();
let approtect = &mut (*pac::UICR::ptr().cast_mut()).approtect;
const HW_DISABLED: u32 = 0x05a;
const SW_DISABLED: u32 = 0x05a;

if approtect.read().bits() != HW_DISABLED {
nvmc.config.write(|w| w.wen().wen());
while nvmc.ready.read().ready().is_busy() {}
core::ptr::write_volatile(approtect.as_ptr(), HW_DISABLED);
while nvmc.ready.read().ready().is_busy() {}
nvmc.config.reset();
while nvmc.ready.read().ready().is_busy() {}
cortex_m::peripheral::SCB::sys_reset();
}

// APPROTECT.DISABLE = SwDisabled
(0x4000_0558 as *mut u32).write_volatile(SW_DISABLED);
}
}
} else {
error!("Unknown hardware revision!");
}

/// The hardware revision of the chip.
/// See https://devzone.nordicsemi.com/f/nordic-q-a/55614/how-to-apply-nordic-software-workarounds-errata-for-a-given-hardware-revision-in-the-field
#[derive(defmt::Format, Eq, PartialEq, Copy, Clone)]
#[non_exhaustive]
enum Revision {
EngA,
EngB,
EngC,
EngD,
Rev1,
Rev2,
Rev3,
}
impl Revision {
fn from_variant(bytes: [u8; 4]) -> Option<Revision> {
let prefix = bytes[2];
let suffix = bytes[3];

let digit = suffix.is_ascii_digit();
Some(match prefix {
b'A' => Self::EngA,
b'B' => Self::EngB,
b'C' if !digit => Self::EngC,
b'D' if !digit => Self::EngD,
b'C' if digit => Self::Rev1,
b'D' if digit => Self::Rev2,
b'F' if digit => Self::Rev3,
_ => return None,
})
}
}
}

debug!("Initializing TWIM (I2C controller)");

// IDK how this works, code is from here:
Expand Down