use core::mem::{size_of, MaybeUninit}; use core::ptr; use crate::bindings::atom_common_table_header; pub use crate::bindings::ppt::{ smu_v11_0_0_ppt::{smu_11_0_powerplay_table, PPTable_t as PPTable_smu_11_0_t}, smu_v11_0_7_ppt::{smu_11_0_7_powerplay_table, PPTable_t as PPTable_smu_11_0_7_t, PPTable_beige_goby_t}, smu_v13_0_0_ppt::{smu_13_0_0_powerplay_table, PPTable_t as PPTable_smu_13_0_0_t}, smu_v13_0_7_ppt::{smu_13_0_7_powerplay_table, PPTable_t as PPTable_smu_13_0_7_t}, }; #[derive(Clone, Copy, Debug, Eq, Hash, Ord, PartialEq, PartialOrd)] pub enum PPTableDecodeError { SmallerThanHeader, SmallerThanStructureSizeInHeader, } #[derive(Debug, Clone)] pub enum PPTable { V11_0_0(smu_11_0_powerplay_table), V11_0_7(smu_11_0_7_powerplay_table), V13_0_0(smu_13_0_0_powerplay_table), V13_0_7(smu_13_0_7_powerplay_table), Unknown(atom_common_table_header), Invalid, } impl PPTable { fn get_header(bytes: &[u8]) -> Option { const HEADER_SIZE: usize = size_of::(); let bin = bytes.get(0..HEADER_SIZE)?; unsafe { let mut h = MaybeUninit::::zeroed(); ptr::copy_nonoverlapping( bin.as_ptr(), h.as_mut_ptr() as *mut u8, HEADER_SIZE, ); Some(h.assume_init()) } } fn check_length(header: &atom_common_table_header, len: usize) -> bool { header.structuresize as usize <= len } pub fn decode(bytes: &[u8]) -> Result { let Some(header) = Self::get_header(bytes) else { return Err(PPTableDecodeError::SmallerThanHeader) }; if !Self::check_length(&header, bytes.len()) { return Err(PPTableDecodeError::SmallerThanStructureSizeInHeader); } // ref: https://github.com/sibradzic/upp/blob/master/src/upp/decode.py let ppt = match header.format_revision { // Navi10: 12 // Navi12: 14 // Navi14: 12? 12 | 14 => Self::V11_0_0(Self::to_pptable(bytes)), // Navi21: 15 // Navi22: 16? // Navi23: 18 // Navi24: 19? 15 | 16 | 18 | 19 => Self::V11_0_7(Self::to_pptable(bytes)), // Navi31: 20 // Navi32: ? // Navi33: ? 20 => Self::V13_0_0(Self::to_pptable(bytes)), _ => Self::Unknown(header), }; Ok(ppt) } pub fn decode_with_smu_version(bytes: &[u8], smu_ver: (u8, u8, u8)) -> Result { let Some(header) = Self::get_header(bytes) else { return Err(PPTableDecodeError::SmallerThanHeader) }; if !Self::check_length(&header, bytes.len()) { return Err(PPTableDecodeError::SmallerThanStructureSizeInHeader); } // ref: https://github.com/sibradzic/upp/blob/master/src/upp/decode.py let ppt = match smu_ver { (11, 0, 0) | /* Navi10 */ (11, 0, 5) | /* Navi14 */ (11, 0, 9) /* Navi12 */ => Self::V11_0_0(Self::to_pptable(bytes)), (11, 0, 7) | /* Navi21 */ (11, 0, 11) | /* Navi22 */ (11, 0, 12) | /* Navi23 */ (11, 0, 13) /* Navi24 */ => Self::V11_0_7(Self::to_pptable(bytes)), (13, 0, 0) | (13, 0, 10) => Self::V13_0_0(Self::to_pptable(bytes)), (13, 0, 7) => Self::V13_0_7(Self::to_pptable(bytes)), _ => Self::Unknown(header), }; Ok(ppt) } fn to_pptable(bytes: &[u8]) -> T { unsafe { let mut t = MaybeUninit::::zeroed(); ptr::copy_nonoverlapping( bytes.as_ptr(), t.as_mut_ptr() as *mut u8, size_of::(), ); t.assume_init() } } pub fn is_valid(&self) -> bool { match self { Self::Unknown(_) | Self::Invalid => false, _ => true, } } }