use serde::{Deserialize, Serialize};
use crate::util::is_default;
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum DebugAccess {
Default,
Disabled,
Enabled,
Authenticate,
Custom(DebugSettings),
}
#[derive(Clone, Copy, Debug, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize)]
pub enum DebugSetting {
Default,
Disabled,
Enabled,
Illegal,
Authenticate,
}
impl Default for DebugAccess {
fn default() -> Self {
Self::Default
}
}
impl Default for DebugSetting {
fn default() -> Self {
Self::Enabled
}
}
impl DebugSetting {
fn fixed_bit(&self) -> u32 {
use DebugSetting::*;
match *self {
Authenticate | Default | Illegal => 0,
Disabled | Enabled => 1,
}
}
fn enabled_bit(&self) -> u32 {
use DebugSetting::*;
match *self {
Disabled | Default | Authenticate => 0,
Enabled | Illegal => 1,
}
}
}
impl From<[bool; 2]> for DebugSetting {
fn from(bits: [bool; 2]) -> Self {
let [fixed, enabled] = bits;
use DebugSetting::*;
match (fixed, enabled) {
(true, true) => Enabled,
(false, false) => Authenticate,
(false, true) => Illegal,
(true, false) => Disabled,
}
}
}
#[derive(
Clone, Copy, Debug, Default, Deserialize, Eq, Hash, Ord, PartialEq, PartialOrd, Serialize,
)]
#[serde(rename_all = "kebab-case")]
pub struct DebugSettings {
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub nonsecure_noninvasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub nonsecure_invasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub secure_noninvasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub secure_invasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub cpu1_noninvasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub cpu1_invasive: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub jtag_tap: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub flash_mass_erase_command: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub isp_boot_command: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub fault_analysis_command: DebugSetting,
#[serde(default)]
#[serde(skip_serializing_if = "is_default")]
pub check_uuid: bool,
}
impl DebugSettings {
pub fn are_all_legal(&self) -> bool {
[
self.nonsecure_noninvasive,
self.nonsecure_invasive,
self.secure_noninvasive,
self.secure_invasive,
self.cpu1_noninvasive,
self.cpu1_invasive,
self.jtag_tap,
self.flash_mass_erase_command,
self.isp_boot_command,
self.fault_analysis_command,
]
.iter()
.all(|&setting| setting != DebugSetting::Illegal)
}
pub fn are_all_non_default(&self) -> bool {
[
self.nonsecure_noninvasive,
self.nonsecure_invasive,
self.secure_noninvasive,
self.secure_invasive,
self.cpu1_noninvasive,
self.cpu1_invasive,
self.jtag_tap,
self.flash_mass_erase_command,
self.isp_boot_command,
self.fault_analysis_command,
]
.iter()
.all(|&setting| setting != DebugSetting::Default)
}
pub fn are_all_default(&self) -> bool {
*self == DebugAccess::Default.into()
}
}
impl From<DebugAccess> for DebugSettings {
fn from(value: DebugAccess) -> Self {
use DebugSetting::*;
fn filled_with(setting: DebugSetting, check_uuid: bool) -> DebugSettings {
DebugSettings {
nonsecure_noninvasive: setting,
nonsecure_invasive: setting,
secure_noninvasive: setting,
secure_invasive: setting,
cpu1_noninvasive: setting,
cpu1_invasive: setting,
jtag_tap: setting,
flash_mass_erase_command: setting,
isp_boot_command: setting,
fault_analysis_command: setting,
check_uuid,
}
}
match value {
DebugAccess::Default => filled_with(Default, false),
DebugAccess::Disabled => filled_with(Disabled, true),
DebugAccess::Enabled => filled_with(Enabled, false),
DebugAccess::Authenticate => filled_with(Authenticate, false),
DebugAccess::Custom(settings) => settings,
}
}
}
impl From<DebugSettings> for DebugAccess {
fn from(settings: DebugSettings) -> Self {
if settings.are_all_default() {
return DebugAccess::Default;
};
if settings == DebugAccess::Authenticate.into() {
return DebugAccess::Authenticate;
}
if settings == DebugAccess::Disabled.into() {
return DebugAccess::Disabled;
}
if settings == DebugAccess::Enabled.into() {
return DebugAccess::Enabled;
}
DebugAccess::Custom(settings)
}
}
impl From<[u32; 2]> for DebugSettings {
fn from(value: [u32; 2]) -> Self {
let [fix, set] = value;
if (fix, set) == (0, 0) {
Self::from(DebugAccess::Default)
} else {
let from_bit =
|bit: usize| DebugSetting::from([((fix >> bit) & 1) != 0, ((set >> bit) & 1) != 0]);
Self {
nonsecure_noninvasive: from_bit(0),
nonsecure_invasive: from_bit(1),
secure_noninvasive: from_bit(2),
secure_invasive: from_bit(3),
jtag_tap: from_bit(4),
cpu1_invasive: from_bit(5),
isp_boot_command: from_bit(6),
fault_analysis_command: from_bit(7),
flash_mass_erase_command: from_bit(8),
cpu1_noninvasive: from_bit(9),
check_uuid: ((fix >> 15) & 1) != 0,
}
}
}
}
impl From<DebugSettings> for [u32; 2] {
fn from(settings: DebugSettings) -> [u32; 2] {
if settings.are_all_default() {
return [0, 0];
};
assert!(settings.are_all_legal());
assert!(settings.are_all_non_default());
let mut fixed: u32 = 0;
let mut enabled: u32 = 0;
let mut set_bits = |setting: DebugSetting, bit: usize| {
fixed |= setting.fixed_bit() << bit;
enabled |= setting.enabled_bit() << bit;
};
set_bits(settings.nonsecure_noninvasive, 0);
set_bits(settings.nonsecure_invasive, 1);
set_bits(settings.secure_noninvasive, 2);
set_bits(settings.secure_invasive, 3);
set_bits(settings.jtag_tap, 4);
set_bits(settings.cpu1_invasive, 5);
set_bits(settings.isp_boot_command, 6);
set_bits(settings.fault_analysis_command, 7);
set_bits(settings.flash_mass_erase_command, 8);
set_bits(settings.cpu1_noninvasive, 9);
fixed |= (settings.check_uuid as u32) << 15;
fixed |= ((!fixed) & 0xffff) << 16;
enabled |= ((!enabled) & 0xffff) << 16;
[fixed, enabled]
}
}