use crate::driver::Bar0;
use crate::firmware::fwsec::Bcrt30Rsa3kSignature;
use crate::firmware::FalconUCodeDescV3;
use core::convert::TryFrom;
use kernel::device;
use kernel::error::Result;
use kernel::pci;
use kernel::prelude::*;
const ROM_OFFSET: usize = 0x300000;
const BIOS_MAX_SCAN_LEN: usize = 0x100000;
const BIOS_READ_AHEAD_SIZE: usize = 1024;
const LAST_IMAGE_BIT_MASK: u8 = 0x80;
#[expect(dead_code)]
const FALCON_UCODE_ENTRY_APPID_FIRMWARE_SEC_LIC: u8 = 0x05;
#[expect(dead_code)]
const FALCON_UCODE_ENTRY_APPID_FWSEC_DBG: u8 = 0x45;
const FALCON_UCODE_ENTRY_APPID_FWSEC_PROD: u8 = 0x85;
struct VbiosIterator<'a> {
pdev: &'a pci::Device,
bar0: &'a Bar0,
data: KVec<u8>,
current_offset: usize,
last_found: bool,
}
impl<'a> VbiosIterator<'a> {
fn new(pdev: &'a pci::Device, bar0: &'a Bar0) -> Result<Self> {
Ok(Self {
pdev,
bar0,
data: KVec::new(),
current_offset: 0,
last_found: false,
})
}
fn read_more(&mut self, len: usize) -> Result {
let current_len = self.data.len();
let start = ROM_OFFSET + current_len;
if len % core::mem::size_of::<u32>() != 0 {
dev_err!(
self.pdev.as_ref(),
"VBIOS read length {} is not a multiple of 4\n",
len
);
return Err(EINVAL);
}
self.data.reserve(len, GFP_KERNEL)?;
for addr in (start..start + len).step_by(core::mem::size_of::<u32>()) {
let word = self.bar0.try_read32(addr)?;
word.to_ne_bytes()
.iter()
.try_for_each(|&b| self.data.push(b, GFP_KERNEL))?;
}
Ok(())
}
fn read_more_at_offset(&mut self, offset: usize, len: usize) -> Result {
if offset > BIOS_MAX_SCAN_LEN {
dev_err!(self.pdev.as_ref(), "Error: exceeded BIOS scan limit.\n");
return Err(EINVAL);
}
let current_len = self.data.len();
let gap_bytes = offset.saturating_sub(current_len);
self.read_more(gap_bytes + len)
}
fn read_bios_image_at_offset(
&mut self,
offset: usize,
len: usize,
context: &str,
) -> Result<BiosImage> {
let data_len = self.data.len();
if offset + len > data_len {
self.read_more_at_offset(offset, len).inspect_err(|e| {
dev_err!(
self.pdev.as_ref(),
"Failed to read more at offset {:#x}: {:?}\n",
offset,
e
)
})?;
}
BiosImage::new(self.pdev, &self.data[offset..offset + len]).inspect_err(|err| {
dev_err!(
self.pdev.as_ref(),
"Failed to {} at offset {:#x}: {:?}\n",
context,
offset,
err
)
})
}
}
impl<'a> Iterator for VbiosIterator<'a> {
type Item = Result<BiosImage>;
fn next(&mut self) -> Option<Self::Item> {
if self.last_found {
return None;
}
if self.current_offset > BIOS_MAX_SCAN_LEN {
dev_err!(
self.pdev.as_ref(),
"Error: exceeded BIOS scan limit, stopping scan\n"
);
return None;
}
let image_size = match self.read_bios_image_at_offset(
self.current_offset,
BIOS_READ_AHEAD_SIZE,
"parse initial BIOS image headers",
) {
Ok(image) => image.image_size_bytes(),
Err(e) => return Some(Err(e)),
};
let full_image = match self.read_bios_image_at_offset(
self.current_offset,
image_size,
"parse full BIOS image",
) {
Ok(image) => image,
Err(e) => return Some(Err(e)),
};
self.last_found = full_image.is_last();
self.current_offset += image_size;
self.current_offset = self.current_offset.next_multiple_of(512);
Some(Ok(full_image))
}
}
pub(crate) struct Vbios {
fwsec_image: FwSecBiosImage,
}
impl Vbios {
pub(crate) fn new(pdev: &pci::Device, bar0: &Bar0) -> Result<Vbios> {
let mut pci_at_image: Option<PciAtBiosImage> = None;
let mut first_fwsec_image: Option<FwSecBiosBuilder> = None;
let mut second_fwsec_image: Option<FwSecBiosBuilder> = None;
for image_result in VbiosIterator::new(pdev, bar0)? {
let full_image = image_result?;
dev_dbg!(
pdev.as_ref(),
"Found BIOS image: size: {:#x}, type: {}, last: {}\n",
full_image.image_size_bytes(),
full_image.image_type_str(),
full_image.is_last()
);
match full_image {
BiosImage::PciAt(image) => {
pci_at_image = Some(image);
}
BiosImage::FwSec(image) => {
if first_fwsec_image.is_none() {
first_fwsec_image = Some(image);
} else {
second_fwsec_image = Some(image);
}
}
BiosImage::Efi(_image) => {}
BiosImage::Nbsi(_image) => {}
}
}
if let (Some(mut second), Some(first), Some(pci_at)) =
(second_fwsec_image, first_fwsec_image, pci_at_image)
{
second
.setup_falcon_data(pdev, &pci_at, &first)
.inspect_err(|e| dev_err!(pdev.as_ref(), "Falcon data setup failed: {:?}\n", e))?;
Ok(Vbios {
fwsec_image: second.build(pdev)?,
})
} else {
dev_err!(
pdev.as_ref(),
"Missing required images for falcon data setup, skipping\n"
);
Err(EINVAL)
}
}
pub(crate) fn fwsec_image(&self) -> &FwSecBiosImage {
&self.fwsec_image
}
}
#[derive(Debug, Clone)]
#[repr(C)]
struct PcirStruct {
signature: [u8; 4],
vendor_id: u16,
device_id: u16,
device_list_ptr: u16,
pci_data_struct_len: u16,
pci_data_struct_rev: u8,
class_code: [u8; 3],
image_len: u16,
vendor_rom_rev: u16,
code_type: u8,
last_image: u8,
max_runtime_image_len: u16,
}
impl PcirStruct {
fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
if data.len() < core::mem::size_of::<PcirStruct>() {
dev_err!(pdev.as_ref(), "Not enough data for PcirStruct\n");
return Err(EINVAL);
}
let mut signature = [0u8; 4];
signature.copy_from_slice(&data[0..4]);
if &signature != b"PCIR" && &signature != b"NPDS" {
dev_err!(
pdev.as_ref(),
"Invalid signature for PcirStruct: {:?}\n",
signature
);
return Err(EINVAL);
}
let mut class_code = [0u8; 3];
class_code.copy_from_slice(&data[13..16]);
let image_len = u16::from_le_bytes([data[16], data[17]]);
if image_len == 0 {
dev_err!(pdev.as_ref(), "Invalid image length: 0\n");
return Err(EINVAL);
}
Ok(PcirStruct {
signature,
vendor_id: u16::from_le_bytes([data[4], data[5]]),
device_id: u16::from_le_bytes([data[6], data[7]]),
device_list_ptr: u16::from_le_bytes([data[8], data[9]]),
pci_data_struct_len: u16::from_le_bytes([data[10], data[11]]),
pci_data_struct_rev: data[12],
class_code,
image_len,
vendor_rom_rev: u16::from_le_bytes([data[18], data[19]]),
code_type: data[20],
last_image: data[21],
max_runtime_image_len: u16::from_le_bytes([data[22], data[23]]),
})
}
fn is_last(&self) -> bool {
self.last_image & LAST_IMAGE_BIT_MASK != 0
}
fn image_size_bytes(&self) -> usize {
self.image_len as usize * 512
}
}
#[derive(Debug, Clone, Copy)]
#[expect(dead_code)]
struct BitHeader {
id: u16,
signature: [u8; 4],
bcd_version: u16,
header_size: u8,
token_size: u8,
token_entries: u8,
checksum: u8,
}
impl BitHeader {
fn new(data: &[u8]) -> Result<Self> {
if data.len() < 12 {
return Err(EINVAL);
}
let mut signature = [0u8; 4];
signature.copy_from_slice(&data[2..6]);
let id = u16::from_le_bytes([data[0], data[1]]);
if id != 0xB8FF || &signature != b"BIT\0" {
return Err(EINVAL);
}
Ok(BitHeader {
id,
signature,
bcd_version: u16::from_le_bytes([data[6], data[7]]),
header_size: data[8],
token_size: data[9],
token_entries: data[10],
checksum: data[11],
})
}
}
#[derive(Debug, Clone, Copy)]
#[expect(dead_code)]
struct BitToken {
id: u8,
data_version: u8,
data_size: u16,
data_offset: u16,
}
const BIT_TOKEN_ID_FALCON_DATA: u8 = 0x70;
impl BitToken {
fn from_id(image: &PciAtBiosImage, token_id: u8) -> Result<Self> {
let header = &image.bit_header;
let tokens_start = image.bit_offset + header.header_size as usize;
for i in 0..header.token_entries as usize {
let entry_offset = tokens_start + (i * header.token_size as usize);
if entry_offset + header.token_size as usize > image.base.data.len() {
return Err(EINVAL);
}
if image.base.data[entry_offset] == token_id {
return Ok(BitToken {
id: image.base.data[entry_offset],
data_version: image.base.data[entry_offset + 1],
data_size: u16::from_le_bytes([
image.base.data[entry_offset + 2],
image.base.data[entry_offset + 3],
]),
data_offset: u16::from_le_bytes([
image.base.data[entry_offset + 4],
image.base.data[entry_offset + 5],
]),
});
}
}
Err(ENOENT)
}
}
#[derive(Debug, Clone, Copy)]
#[expect(dead_code)]
struct PciRomHeader {
signature: u16,
reserved: [u8; 20],
nbsi_data_offset: Option<u16>,
pci_data_struct_offset: u16,
size_of_block: Option<u32>,
}
impl PciRomHeader {
fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
if data.len() < 26 {
return Err(EINVAL);
}
let signature = u16::from_le_bytes([data[0], data[1]]);
match signature {
0xAA55 | 0xBB77 | 0x4E56 => {}
_ => {
dev_err!(pdev.as_ref(), "ROM signature unknown {:#x}\n", signature);
return Err(EINVAL);
}
}
let pci_data_struct_ptr = u16::from_le_bytes([data[24], data[25]]);
let mut size_of_block = None;
let mut nbsi_data_offset = None;
if data.len() >= 30 {
size_of_block = Some(
u32::from(data[29]) << 24
| u32::from(data[28]) << 16
| u32::from(data[27]) << 8
| u32::from(data[26]),
);
}
if data.len() >= 24 {
nbsi_data_offset = Some(u16::from_le_bytes([data[22], data[23]]));
}
Ok(PciRomHeader {
signature,
reserved: [0u8; 20],
pci_data_struct_offset: pci_data_struct_ptr,
size_of_block,
nbsi_data_offset,
})
}
}
#[derive(Debug, Clone)]
#[repr(C)]
struct NpdeStruct {
signature: [u8; 4],
npci_data_ext_rev: u16,
npci_data_ext_len: u16,
subimage_len: u16,
last_image: u8,
}
impl NpdeStruct {
fn new(pdev: &pci::Device, data: &[u8]) -> Option<Self> {
if data.len() < core::mem::size_of::<Self>() {
dev_dbg!(pdev.as_ref(), "Not enough data for NpdeStruct\n");
return None;
}
let mut signature = [0u8; 4];
signature.copy_from_slice(&data[0..4]);
if &signature != b"NPDE" {
dev_dbg!(
pdev.as_ref(),
"Invalid signature for NpdeStruct: {:?}\n",
signature
);
return None;
}
let subimage_len = u16::from_le_bytes([data[8], data[9]]);
if subimage_len == 0 {
dev_dbg!(pdev.as_ref(), "Invalid subimage length: 0\n");
return None;
}
Some(NpdeStruct {
signature,
npci_data_ext_rev: u16::from_le_bytes([data[4], data[5]]),
npci_data_ext_len: u16::from_le_bytes([data[6], data[7]]),
subimage_len,
last_image: data[10],
})
}
fn is_last(&self) -> bool {
self.last_image & LAST_IMAGE_BIT_MASK != 0
}
fn image_size_bytes(&self) -> usize {
self.subimage_len as usize * 512
}
fn find_in_data(
pdev: &pci::Device,
data: &[u8],
rom_header: &PciRomHeader,
pcir: &PcirStruct,
) -> Option<Self> {
let pcir_offset = rom_header.pci_data_struct_offset as usize;
let npde_start = (pcir_offset + pcir.pci_data_struct_len as usize + 0x0F) & !0x0F;
if npde_start + core::mem::size_of::<Self>() > data.len() {
dev_dbg!(pdev.as_ref(), "Not enough data for NPDE\n");
return None;
}
NpdeStruct::new(pdev, &data[npde_start..])
}
}
macro_rules! bios_image {
(
$($variant:ident: $class:ident),* $(,)?
) => {
enum BiosImage {
$($variant($class)),*
}
impl BiosImage {
fn base(&self) -> &BiosImageBase {
match self {
$(Self::$variant(img) => &img.base),*
}
}
fn image_type_str(&self) -> &'static str {
match self {
$(Self::$variant(_) => stringify!($variant)),*
}
}
}
}
}
impl BiosImage {
fn is_last(&self) -> bool {
let base = self.base();
if matches!(self, Self::Nbsi(_)) {
return true;
}
if let Some(ref npde) = base.npde {
return npde.is_last();
}
base.pcir.is_last()
}
fn image_size_bytes(&self) -> usize {
let base = self.base();
if let Some(ref npde) = base.npde {
return npde.image_size_bytes();
}
base.pcir.image_size_bytes()
}
fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
let base = BiosImageBase::new(pdev, data)?;
let image = base.into_image().inspect_err(|e| {
dev_err!(pdev.as_ref(), "Failed to create BiosImage: {:?}\n", e);
})?;
Ok(image)
}
}
bios_image! {
PciAt: PciAtBiosImage,
Efi: EfiBiosImage,
Nbsi: NbsiBiosImage,
FwSec: FwSecBiosBuilder,
}
struct PciAtBiosImage {
base: BiosImageBase,
bit_header: BitHeader,
bit_offset: usize,
}
struct EfiBiosImage {
base: BiosImageBase,
}
struct NbsiBiosImage {
base: BiosImageBase,
}
struct FwSecBiosBuilder {
base: BiosImageBase,
falcon_data_offset: Option<usize>,
pmu_lookup_table: Option<PmuLookupTable>,
falcon_ucode_offset: Option<usize>,
}
pub(crate) struct FwSecBiosImage {
base: BiosImageBase,
falcon_ucode_offset: usize,
}
impl TryFrom<BiosImageBase> for BiosImage {
type Error = Error;
fn try_from(base: BiosImageBase) -> Result<Self> {
match base.pcir.code_type {
0x00 => Ok(BiosImage::PciAt(base.try_into()?)),
0x03 => Ok(BiosImage::Efi(EfiBiosImage { base })),
0x70 => Ok(BiosImage::Nbsi(NbsiBiosImage { base })),
0xE0 => Ok(BiosImage::FwSec(FwSecBiosBuilder {
base,
falcon_data_offset: None,
pmu_lookup_table: None,
falcon_ucode_offset: None,
})),
_ => Err(EINVAL),
}
}
}
#[derive(Debug)]
#[expect(dead_code)]
struct BiosImageBase {
rom_header: PciRomHeader,
pcir: PcirStruct,
npde: Option<NpdeStruct>,
data: KVec<u8>,
}
impl BiosImageBase {
fn into_image(self) -> Result<BiosImage> {
BiosImage::try_from(self)
}
fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
if data.len() < 26 {
dev_err!(pdev.as_ref(), "Not enough data for ROM header\n");
return Err(EINVAL);
}
let rom_header = PciRomHeader::new(pdev, &data[0..26])
.inspect_err(|e| dev_err!(pdev.as_ref(), "Failed to create PciRomHeader: {:?}\n", e))?;
let pcir_offset = rom_header.pci_data_struct_offset as usize;
let pcir_data = data
.get(pcir_offset..pcir_offset + core::mem::size_of::<PcirStruct>())
.ok_or(EINVAL)
.inspect_err(|_| {
dev_err!(
pdev.as_ref(),
"PCIR offset {:#x} out of bounds (data length: {})\n",
pcir_offset,
data.len()
);
dev_err!(
pdev.as_ref(),
"Consider reading more data for construction of BiosImage\n"
);
})?;
let pcir = PcirStruct::new(pdev, pcir_data)
.inspect_err(|e| dev_err!(pdev.as_ref(), "Failed to create PcirStruct: {:?}\n", e))?;
let npde = NpdeStruct::find_in_data(pdev, data, &rom_header, &pcir);
let mut data_copy = KVec::new();
data_copy.extend_from_slice(data, GFP_KERNEL)?;
Ok(BiosImageBase {
rom_header,
pcir,
npde,
data: data_copy,
})
}
}
impl PciAtBiosImage {
fn find_byte_pattern(haystack: &[u8], needle: &[u8]) -> Result<usize> {
haystack
.windows(needle.len())
.position(|window| window == needle)
.ok_or(EINVAL)
}
fn find_bit_header(data: &[u8]) -> Result<(BitHeader, usize)> {
let bit_pattern = [0xff, 0xb8, b'B', b'I', b'T', 0x00];
let bit_offset = Self::find_byte_pattern(data, &bit_pattern)?;
let bit_header = BitHeader::new(&data[bit_offset..])?;
Ok((bit_header, bit_offset))
}
fn get_bit_token(&self, token_id: u8) -> Result<BitToken> {
BitToken::from_id(self, token_id)
}
fn falcon_data_ptr(&self, pdev: &pci::Device) -> Result<u32> {
let token = self.get_bit_token(BIT_TOKEN_ID_FALCON_DATA)?;
if token.data_offset as usize + 4 > self.base.data.len() {
return Err(EINVAL);
}
let offset = token.data_offset as usize;
let bytes: [u8; 4] = self.base.data[offset..offset + 4].try_into().map_err(|_| {
dev_err!(pdev.as_ref(), "Failed to convert data slice to array");
EINVAL
})?;
let data_ptr = u32::from_le_bytes(bytes);
if (data_ptr as usize) < self.base.data.len() {
dev_err!(pdev.as_ref(), "Falcon data pointer out of bounds\n");
return Err(EINVAL);
}
Ok(data_ptr)
}
}
impl TryFrom<BiosImageBase> for PciAtBiosImage {
type Error = Error;
fn try_from(base: BiosImageBase) -> Result<Self> {
let data_slice = &base.data;
let (bit_header, bit_offset) = PciAtBiosImage::find_bit_header(data_slice)?;
Ok(PciAtBiosImage {
base,
bit_header,
bit_offset,
})
}
}
#[expect(dead_code)]
struct PmuLookupTableEntry {
application_id: u8,
target_id: u8,
data: u32,
}
impl PmuLookupTableEntry {
fn new(data: &[u8]) -> Result<Self> {
if data.len() < 6 {
return Err(EINVAL);
}
Ok(PmuLookupTableEntry {
application_id: data[0],
target_id: data[1],
data: u32::from_le_bytes(data[2..6].try_into().map_err(|_| EINVAL)?),
})
}
}
#[expect(dead_code)]
struct PmuLookupTable {
version: u8,
header_len: u8,
entry_len: u8,
entry_count: u8,
table_data: KVec<u8>,
}
impl PmuLookupTable {
fn new(pdev: &pci::Device, data: &[u8]) -> Result<Self> {
if data.len() < 4 {
return Err(EINVAL);
}
let header_len = data[1] as usize;
let entry_len = data[2] as usize;
let entry_count = data[3] as usize;
let required_bytes = header_len + (entry_count * entry_len);
if data.len() < required_bytes {
dev_err!(
pdev.as_ref(),
"PmuLookupTable data length less than required\n"
);
return Err(EINVAL);
}
let table_data = {
let mut ret = KVec::new();
ret.extend_from_slice(&data[header_len..required_bytes], GFP_KERNEL)?;
ret
};
for i in (header_len..required_bytes).step_by(entry_len) {
dev_dbg!(
pdev.as_ref(),
"PMU entry: {:02x?}\n",
&data[i..][..entry_len]
);
}
Ok(PmuLookupTable {
version: data[0],
header_len: header_len as u8,
entry_len: entry_len as u8,
entry_count: entry_count as u8,
table_data,
})
}
fn lookup_index(&self, idx: u8) -> Result<PmuLookupTableEntry> {
if idx >= self.entry_count {
return Err(EINVAL);
}
let index = (idx as usize) * self.entry_len as usize;
PmuLookupTableEntry::new(&self.table_data[index..])
}
fn find_entry_by_type(&self, entry_type: u8) -> Result<PmuLookupTableEntry> {
for i in 0..self.entry_count {
let entry = self.lookup_index(i)?;
if entry.application_id == entry_type {
return Ok(entry);
}
}
Err(EINVAL)
}
}
impl FwSecBiosBuilder {
fn setup_falcon_data(
&mut self,
pdev: &pci::Device,
pci_at_image: &PciAtBiosImage,
first_fwsec: &FwSecBiosBuilder,
) -> Result {
let mut offset = pci_at_image.falcon_data_ptr(pdev)? as usize;
let mut pmu_in_first_fwsec = false;
offset -= pci_at_image.base.data.len();
if offset < first_fwsec.base.data.len() {
pmu_in_first_fwsec = true;
} else {
offset -= first_fwsec.base.data.len();
}
self.falcon_data_offset = Some(offset);
if pmu_in_first_fwsec {
self.pmu_lookup_table =
Some(PmuLookupTable::new(pdev, &first_fwsec.base.data[offset..])?);
} else {
self.pmu_lookup_table = Some(PmuLookupTable::new(pdev, &self.base.data[offset..])?);
}
match self
.pmu_lookup_table
.as_ref()
.ok_or(EINVAL)?
.find_entry_by_type(FALCON_UCODE_ENTRY_APPID_FWSEC_PROD)
{
Ok(entry) => {
let mut ucode_offset = entry.data as usize;
ucode_offset -= pci_at_image.base.data.len();
if ucode_offset < first_fwsec.base.data.len() {
dev_err!(pdev.as_ref(), "Falcon Ucode offset not in second Fwsec.\n");
return Err(EINVAL);
}
ucode_offset -= first_fwsec.base.data.len();
self.falcon_ucode_offset = Some(ucode_offset);
}
Err(e) => {
dev_err!(
pdev.as_ref(),
"PmuLookupTableEntry not found, error: {:?}\n",
e
);
return Err(EINVAL);
}
}
Ok(())
}
fn build(self, pdev: &pci::Device) -> Result<FwSecBiosImage> {
let ret = FwSecBiosImage {
base: self.base,
falcon_ucode_offset: self.falcon_ucode_offset.ok_or(EINVAL)?,
};
if cfg!(debug_assertions) {
let desc = ret.header(pdev.as_ref())?;
dev_dbg!(pdev.as_ref(), "PmuLookupTableEntry desc: {:#?}\n", desc);
}
Ok(ret)
}
}
impl FwSecBiosImage {
pub(crate) fn header(&self, dev: &device::Device) -> Result<&FalconUCodeDescV3> {
let falcon_ucode_offset = self.falcon_ucode_offset;
if falcon_ucode_offset + core::mem::size_of::<FalconUCodeDescV3>() > self.base.data.len() {
dev_err!(dev, "fwsec-frts header not contained within BIOS bounds\n");
return Err(ERANGE);
}
let hdr_bytes: [u8; 4] = self.base.data[falcon_ucode_offset..falcon_ucode_offset + 4]
.try_into()
.map_err(|_| EINVAL)?;
let hdr = u32::from_le_bytes(hdr_bytes);
let ver = (hdr & 0xff00) >> 8;
if ver != 3 {
dev_err!(dev, "invalid fwsec firmware version: {:?}\n", ver);
return Err(EINVAL);
}
Ok(unsafe {
&*(self
.base
.data
.as_ptr()
.add(falcon_ucode_offset)
.cast::<FalconUCodeDescV3>())
})
}
pub(crate) fn ucode(&self, dev: &device::Device, desc: &FalconUCodeDescV3) -> Result<&[u8]> {
let falcon_ucode_offset = self.falcon_ucode_offset;
let ucode_data_offset = falcon_ucode_offset + desc.size();
let size = (desc.imem_load_size + desc.dmem_load_size) as usize;
self.base
.data
.get(ucode_data_offset..ucode_data_offset + size)
.ok_or(ERANGE)
.inspect_err(|_| dev_err!(dev, "fwsec ucode data not contained within BIOS bounds\n"))
}
pub(crate) fn sigs(
&self,
dev: &device::Device,
desc: &FalconUCodeDescV3,
) -> Result<&[Bcrt30Rsa3kSignature]> {
let sigs_data_offset = self.falcon_ucode_offset + core::mem::size_of::<FalconUCodeDescV3>();
let sigs_size =
desc.signature_count as usize * core::mem::size_of::<Bcrt30Rsa3kSignature>();
if sigs_data_offset + sigs_size > self.base.data.len() {
dev_err!(
dev,
"fwsec signatures data not contained within BIOS bounds\n"
);
return Err(ERANGE);
}
Ok(unsafe {
core::slice::from_raw_parts(
self.base
.data
.as_ptr()
.add(sigs_data_offset)
.cast::<Bcrt30Rsa3kSignature>(),
desc.signature_count as usize,
)
})
}
}