mirror of
https://github.com/torvalds/linux.git
synced 2026-04-22 00:33:58 -04:00
Pull drm updates from Dave Airlie:
"Highlights:
- amdgpu support for lots of new IP blocks which means newer GPUs
- xe has a lot of SR-IOV and SVM improvements
- lots of intel display refactoring across i915/xe
- msm has more support for gen8 platforms
- Given up on kgdb/kms integration, it's too hard on modern hw
core:
- drop kgdb support
- replace system workqueue with percpu
- account for property blobs in memcg
- MAINTAINERS updates for xe + buddy
rust:
- Fix documentation for Registration constructors
- Use pin_init::zeroed() for fops initialization
- Annotate DRM helpers with __rust_helper
- Improve safety documentation for gem::Object::new()
- Update AlwaysRefCounted imports
- mm: Prevent integer overflow in page_align()
atomic:
- add drm_device pointer to drm_private_obj
- introduce gamma/degamma LUT size check
buddy:
- fix free_trees memory leak
- prevent BUG_ON
bridge:
- introduce drm_bridge_unplug/enter/exit
- add connector argument to .hpd_notify
- lots of recounting conversions
- convert rockchip inno hdmi to bridge
- lontium-lt9611uxc: switch to HDMI audio helpers
- dw-hdmi-qp: add support for HPD-less setups
- Algoltek AG6311 support
panels:
- edp: CSW MNE007QB3-1, AUO B140HAN06.4, AUO B140QAX01.H
- st75751: add SPI support
- Sitronix ST7920, Samsung LTL106HL02
- LG LH546WF1-ED01, HannStar HSD156J
- BOE NV130WUM-T08
- Innolux G150XGE-L05
- Anbernic RG-DS
dma-buf:
- improve sg_table debugging
- add tracepoints
- call clear_page instead of memset
- start to introduce cgroup memory accounting in heaps
- remove sysfs stats
dma-fence:
- add new helpers
dp:
- mst: avoid oob access with vcpi=0
hdmi:
- limit infoframes exposure to userspace
gem:
- reduce page table overhead with THP
- fix leak in drm_gem_get_unmapped_area
gpuvm:
- API sanitation for rust bindings
sched:
- introduce new helpers
panic:
- report invalid panic modes
- add kunit tests
i915/xe display:
- Expose sharpness only if num_scalers is >= 2
- Add initial Xe3P_LPD for NVL
- BMG FBC support
- Add MTL+ platforms to support dpll framework
_ fix DIMM_S DRM decoding on ICL
- Return to using AUX interrupts
- PSR/Panel replay refactoring
- use consolidation HDMI tables
- Xe3_LPD CD2X dividier changes
xe:
- vfio: add vfio_pci for intel GPU
- multi queue support
- dynamic pagemaps and multi-device SVM
- expose temp attribs in hwmon
- NO_COMPRESSION bo flag
- expose MERT OA unit
- sysfs survivability refactor
- SRIOV PF: add MERT support
- enable SR-IOV VF migration
- Enable I2C/NVM on Crescent Island
- Xe3p page reclaimation support
- introduce SRIOV scheduler groups
- add SoC remappt support in system controller
- insert compiler barriers in GuC code
- define NVL GuC firmware
- handle GT resume failure
- fix drm scheduler layering violations
- enable GSC loading and PXP for PTL
- disable GuC Power DCC strategy on PTL
- unregister drm device on probe error
i915:
- move to kernel standard fault injection
- bump recommended GuC version for DG2 and MTL
amdgpu:
- SMUIO 15.x, PSP 15.x support
- IH 6.1.1/7.1 support
- MMHUB 3.4/4.2 support
- GC 11.5.4/12.1 support
- SDMA 6.1.4/7.1/7.11.4 support
- JPEG 5.3 support
- UserQ updates
- GC 9 gfx queue reset support
- TTM memory ops parallelization
- convert legacy logging to new helpers
- DC analog fixes
amdkfd:
- GC 11.5.4/12.1 suppport
- SDMA 6.1.4/7.1 support
- per context support
- increase kfd process hash table
- Reserved SDMA rework
radeon:
- convert legacy logging to new helpers
- use devm for i2c adapters
msm:
- GPU
- Document a612/RGMU dt bindings
- UBWC 6.0 support (for A840 / Kaanapali)
- a225 support
- DPU:
- Switch to use virtual planes by default
- Fix DSI CMD panels on DPU 3.x
- Rewrite format handling to remove intermediate representation
- Fix watchdog on DPU 8.x+
- Fix TE / Vsync source setting on DPU 8.x+
- Add 3D_Mux on SC7280
- Kaanapali platform support
- Fix UBWC register programming
- Make RM reserve DSPP-enabled mixers for CRTCs with LMs
- Gamma correction support
- DP:
- Enable support for eDP 1.4+ link rate tables
- Fix MDSS1 DP indices on SA8775P, making them to work
- Fix msm_dp_ctrl_config_msa() to work with LLVM 20
- DSI:
- Document QCS8300 as compatible with SA8775P
- Kaanapali platform support
- DSI PHY:
- switch to divider_determine_rate()
- MDP5:
- Drop support for MSM8998, SDM660 and SDM630 (switch over to DPU)
- MDSS:
- Kaanapali platform support
- Fixed UBWC register programming
nova-core:
- Prepare for Turing support. This includes parsing and handling
Turing-specific firmware headers and sections as well as a Turing
Falcon HAL implementation
- Get rid of the Result<impl PinInit<T, E>> anti-pattern
- Relocate initializer-specific code into the appropriate initializer
- Use CStr::from_bytes_until_nul() to remove custom helpers
- Improve handling of unexpected firmware values
- Clean up redundant debug prints
- Replace c_str!() with native Rust C-string literals
- Update nova-core task list
nova:
- Align GEM object size to system page size
tyr:
- Use generated uAPI bindings for GpuInfo
- Replace manual sleeps with read_poll_timeout()
- Replace c_str!() with native Rust C-string literals
- Suppress warnings for unread fields
- Fix incorrect register name in print statement
nouveau:
- fix big page table support races in PTE management
- improve reclocking on tegra 186+
amdxdna:
- fix suspend race conditions
- improve handling of zero tail pointers
- fix cu_idx overwritten during command setup
- enable hardware context priority
- remove NPU2 support
- update message buffer allocation requirements
- update firmware version check
ast:
- support imported cursor buffers
- big endian fixes
etnaviv:
- add PPU flop reset support
imagination:
- add AM62P support
- introduce hw version checks
ivpu:
- implement warm boot flow
panfrost:
- add bo sync ioctl
- add GPU_PM_RT support for RZ/G3E SoC
panthor:
- add bo sync ioctl
- enable timestamp propagation
- scheduler robustness improvements
- VM termination fixes
- huge page support
rockchip:
- RK3368 HDMI Support
- get rid of atomic_check fixups
- RK3506 support
- RK3576/RK3588 improved HPD handling
rz-du:
- RZ/V2H(P) MIPI-DSI Support
v3d:
- fix DMA segment size
- convert to new logging helpers
mediatek:
- move DP training to hotplug thread
- convert logging to new helpers
- add support for HS speed DSI
- Genio 510/700/1200-EVK, Radxa NIO-12L HDMI support
atmel-hlcdc:
- switch to drmm resource
- support nomodeset
- use newer helpers
hisilicon:
- fix various DP bugs
renesas:
- fix kernel panic on reboot
exynos:
- fix vidi_connection_ioctl using wrong device
- fix vidi_connection deref user ptr
- fix concurrency regression with vidi_context
vkms:
- add configfs support for display configuration
* tag 'drm-next-2026-02-11' of https://gitlab.freedesktop.org/drm/kernel: (1610 commits)
drm/xe/pm: Disable D3Cold for BMG only on specific platforms
drm/xe: Fix kerneldoc for xe_tlb_inval_job_alloc_dep
drm/xe: Fix kerneldoc for xe_gt_tlb_inval_init_early
drm/xe: Fix kerneldoc for xe_migrate_exec_queue
drm/xe/query: Fix topology query pointer advance
drm/xe/guc: Fix kernel-doc warning in GuC scheduler ABI header
drm/xe/guc: Fix CFI violation in debugfs access.
accel/amdxdna: Move RPM resume into job run function
accel/amdxdna: Fix incorrect DPM level after suspend/resume
nouveau/vmm: start tracking if the LPT PTE is valid. (v6)
nouveau/vmm: increase size of vmm pte tracker struct to u32 (v2)
nouveau/vmm: rewrite pte tracker using a struct and bitfields.
accel/amdxdna: Fix incorrect error code returned for failed chain command
accel/amdxdna: Remove hardware context status
drm/bridge: imx8qxp-pixel-combiner: Fix bailout for imx8qxp_pc_bridge_probe()
drm/panel: ilitek-ili9882t: Remove duplicate initializers in tianma_il79900a_dsc
drm/i915/display: fix the pixel normalization handling for xe3p_lpd
drm/exynos: vidi: use ctx->lock to protect struct vidi_context member variables related to memory alloc/free
drm/exynos: vidi: fix to avoid directly dereferencing user pointer
drm/exynos: vidi: use priv->vidi_dev for ctx lookup in vidi_connection_ioctl()
...
435 lines
14 KiB
Rust
435 lines
14 KiB
Rust
// SPDX-License-Identifier: GPL-2.0
|
|
|
|
//! FWSEC is a High Secure firmware that is extracted from the BIOS and performs the first step of
|
|
//! the GSP startup by creating the WPR2 memory region and copying critical areas of the VBIOS into
|
|
//! it after authenticating them, ensuring they haven't been tampered with. It runs on the GSP
|
|
//! falcon.
|
|
//!
|
|
//! Before being run, it needs to be patched in two areas:
|
|
//!
|
|
//! - The command to be run, as this firmware can perform several tasks ;
|
|
//! - The ucode signature, so the GSP falcon can run FWSEC in HS mode.
|
|
|
|
use core::{
|
|
marker::PhantomData,
|
|
ops::Deref, //
|
|
};
|
|
|
|
use kernel::{
|
|
device::{
|
|
self,
|
|
Device, //
|
|
},
|
|
prelude::*,
|
|
transmute::{
|
|
AsBytes,
|
|
FromBytes, //
|
|
},
|
|
};
|
|
|
|
use crate::{
|
|
dma::DmaObject,
|
|
driver::Bar0,
|
|
falcon::{
|
|
gsp::Gsp,
|
|
Falcon,
|
|
FalconBromParams,
|
|
FalconFirmware,
|
|
FalconLoadParams,
|
|
FalconLoadTarget, //
|
|
},
|
|
firmware::{
|
|
FalconUCodeDesc,
|
|
FirmwareDmaObject,
|
|
FirmwareSignature,
|
|
Signed,
|
|
Unsigned, //
|
|
},
|
|
num::{
|
|
FromSafeCast,
|
|
IntoSafeCast, //
|
|
},
|
|
vbios::Vbios,
|
|
};
|
|
|
|
const NVFW_FALCON_APPIF_ID_DMEMMAPPER: u32 = 0x4;
|
|
|
|
#[repr(C)]
|
|
#[derive(Debug)]
|
|
struct FalconAppifHdrV1 {
|
|
version: u8,
|
|
header_size: u8,
|
|
entry_size: u8,
|
|
entry_count: u8,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for FalconAppifHdrV1 {}
|
|
|
|
#[repr(C, packed)]
|
|
#[derive(Debug)]
|
|
struct FalconAppifV1 {
|
|
id: u32,
|
|
dmem_base: u32,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for FalconAppifV1 {}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(C, packed)]
|
|
struct FalconAppifDmemmapperV3 {
|
|
signature: u32,
|
|
version: u16,
|
|
size: u16,
|
|
cmd_in_buffer_offset: u32,
|
|
cmd_in_buffer_size: u32,
|
|
cmd_out_buffer_offset: u32,
|
|
cmd_out_buffer_size: u32,
|
|
nvf_img_data_buffer_offset: u32,
|
|
nvf_img_data_buffer_size: u32,
|
|
printf_buffer_hdr: u32,
|
|
ucode_build_time_stamp: u32,
|
|
ucode_signature: u32,
|
|
init_cmd: u32,
|
|
ucode_feature: u32,
|
|
ucode_cmd_mask0: u32,
|
|
ucode_cmd_mask1: u32,
|
|
multi_tgt_tbl: u32,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for FalconAppifDmemmapperV3 {}
|
|
// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability.
|
|
unsafe impl AsBytes for FalconAppifDmemmapperV3 {}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(C, packed)]
|
|
struct ReadVbios {
|
|
ver: u32,
|
|
hdr: u32,
|
|
addr: u64,
|
|
size: u32,
|
|
flags: u32,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for ReadVbios {}
|
|
// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability.
|
|
unsafe impl AsBytes for ReadVbios {}
|
|
|
|
#[derive(Debug)]
|
|
#[repr(C, packed)]
|
|
struct FrtsRegion {
|
|
ver: u32,
|
|
hdr: u32,
|
|
addr: u32,
|
|
size: u32,
|
|
ftype: u32,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for FrtsRegion {}
|
|
// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability.
|
|
unsafe impl AsBytes for FrtsRegion {}
|
|
|
|
const NVFW_FRTS_CMD_REGION_TYPE_FB: u32 = 2;
|
|
|
|
#[repr(C, packed)]
|
|
struct FrtsCmd {
|
|
read_vbios: ReadVbios,
|
|
frts_region: FrtsRegion,
|
|
}
|
|
// SAFETY: Any byte sequence is valid for this struct.
|
|
unsafe impl FromBytes for FrtsCmd {}
|
|
// SAFETY: This struct doesn't contain uninitialized bytes and doesn't have interior mutability.
|
|
unsafe impl AsBytes for FrtsCmd {}
|
|
|
|
const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS: u32 = 0x15;
|
|
const NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB: u32 = 0x19;
|
|
|
|
/// Command for the [`FwsecFirmware`] to execute.
|
|
pub(crate) enum FwsecCommand {
|
|
/// Asks [`FwsecFirmware`] to carve out the WPR2 area and place a verified copy of the VBIOS
|
|
/// image into it.
|
|
Frts { frts_addr: u64, frts_size: u64 },
|
|
/// Asks [`FwsecFirmware`] to load pre-OS apps on the PMU.
|
|
#[expect(dead_code)]
|
|
Sb,
|
|
}
|
|
|
|
/// Size of the signatures used in FWSEC.
|
|
const BCRT30_RSA3K_SIG_SIZE: usize = 384;
|
|
|
|
/// A single signature that can be patched into a FWSEC image.
|
|
#[repr(transparent)]
|
|
pub(crate) struct Bcrt30Rsa3kSignature([u8; BCRT30_RSA3K_SIG_SIZE]);
|
|
|
|
/// SAFETY: A signature is just an array of bytes.
|
|
unsafe impl FromBytes for Bcrt30Rsa3kSignature {}
|
|
|
|
impl From<[u8; BCRT30_RSA3K_SIG_SIZE]> for Bcrt30Rsa3kSignature {
|
|
fn from(sig: [u8; BCRT30_RSA3K_SIG_SIZE]) -> Self {
|
|
Self(sig)
|
|
}
|
|
}
|
|
|
|
impl AsRef<[u8]> for Bcrt30Rsa3kSignature {
|
|
fn as_ref(&self) -> &[u8] {
|
|
&self.0
|
|
}
|
|
}
|
|
|
|
impl FirmwareSignature<FwsecFirmware> for Bcrt30Rsa3kSignature {}
|
|
|
|
/// Reinterpret the area starting from `offset` in `fw` as an instance of `T` (which must implement
|
|
/// [`FromBytes`]) and return a reference to it.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// * Callers must ensure that the device does not read/write to/from memory while the returned
|
|
/// reference is live.
|
|
/// * Callers must ensure that this call does not race with a write to the same region while
|
|
/// the returned reference is live.
|
|
unsafe fn transmute<T: Sized + FromBytes>(fw: &DmaObject, offset: usize) -> Result<&T> {
|
|
// SAFETY: The safety requirements of the function guarantee the device won't read
|
|
// or write to memory while the reference is alive and that this call won't race
|
|
// with writes to the same memory region.
|
|
T::from_bytes(unsafe { fw.as_slice(offset, size_of::<T>())? }).ok_or(EINVAL)
|
|
}
|
|
|
|
/// Reinterpret the area starting from `offset` in `fw` as a mutable instance of `T` (which must
|
|
/// implement [`FromBytes`]) and return a reference to it.
|
|
///
|
|
/// # Safety
|
|
///
|
|
/// * Callers must ensure that the device does not read/write to/from memory while the returned
|
|
/// slice is live.
|
|
/// * Callers must ensure that this call does not race with a read or write to the same region
|
|
/// while the returned slice is live.
|
|
unsafe fn transmute_mut<T: Sized + FromBytes + AsBytes>(
|
|
fw: &mut DmaObject,
|
|
offset: usize,
|
|
) -> Result<&mut T> {
|
|
// SAFETY: The safety requirements of the function guarantee the device won't read
|
|
// or write to memory while the reference is alive and that this call won't race
|
|
// with writes or reads to the same memory region.
|
|
T::from_bytes_mut(unsafe { fw.as_slice_mut(offset, size_of::<T>())? }).ok_or(EINVAL)
|
|
}
|
|
|
|
/// The FWSEC microcode, extracted from the BIOS and to be run on the GSP falcon.
|
|
///
|
|
/// It is responsible for e.g. carving out the WPR2 region as the first step of the GSP bootflow.
|
|
pub(crate) struct FwsecFirmware {
|
|
/// Descriptor of the firmware.
|
|
desc: FalconUCodeDesc,
|
|
/// GPU-accessible DMA object containing the firmware.
|
|
ucode: FirmwareDmaObject<Self, Signed>,
|
|
}
|
|
|
|
impl FalconLoadParams for FwsecFirmware {
|
|
fn imem_sec_load_params(&self) -> FalconLoadTarget {
|
|
self.desc.imem_sec_load_params()
|
|
}
|
|
|
|
fn imem_ns_load_params(&self) -> Option<FalconLoadTarget> {
|
|
self.desc.imem_ns_load_params()
|
|
}
|
|
|
|
fn dmem_load_params(&self) -> FalconLoadTarget {
|
|
self.desc.dmem_load_params()
|
|
}
|
|
|
|
fn brom_params(&self) -> FalconBromParams {
|
|
FalconBromParams {
|
|
pkc_data_offset: self.desc.pkc_data_offset(),
|
|
engine_id_mask: self.desc.engine_id_mask(),
|
|
ucode_id: self.desc.ucode_id(),
|
|
}
|
|
}
|
|
|
|
fn boot_addr(&self) -> u32 {
|
|
0
|
|
}
|
|
}
|
|
|
|
impl Deref for FwsecFirmware {
|
|
type Target = DmaObject;
|
|
|
|
fn deref(&self) -> &Self::Target {
|
|
&self.ucode.0
|
|
}
|
|
}
|
|
|
|
impl FalconFirmware for FwsecFirmware {
|
|
type Target = Gsp;
|
|
}
|
|
|
|
impl FirmwareDmaObject<FwsecFirmware, Unsigned> {
|
|
fn new_fwsec(dev: &Device<device::Bound>, bios: &Vbios, cmd: FwsecCommand) -> Result<Self> {
|
|
let desc = bios.fwsec_image().header()?;
|
|
let ucode = bios.fwsec_image().ucode(&desc)?;
|
|
let mut dma_object = DmaObject::from_data(dev, ucode)?;
|
|
|
|
let hdr_offset = usize::from_safe_cast(desc.imem_load_size() + desc.interface_offset());
|
|
// SAFETY: we have exclusive access to `dma_object`.
|
|
let hdr: &FalconAppifHdrV1 = unsafe { transmute(&dma_object, hdr_offset) }?;
|
|
|
|
if hdr.version != 1 {
|
|
return Err(EINVAL);
|
|
}
|
|
|
|
// Find the DMEM mapper section in the firmware.
|
|
for i in 0..usize::from(hdr.entry_count) {
|
|
// SAFETY: we have exclusive access to `dma_object`.
|
|
let app: &FalconAppifV1 = unsafe {
|
|
transmute(
|
|
&dma_object,
|
|
hdr_offset + usize::from(hdr.header_size) + i * usize::from(hdr.entry_size),
|
|
)
|
|
}?;
|
|
|
|
if app.id != NVFW_FALCON_APPIF_ID_DMEMMAPPER {
|
|
continue;
|
|
}
|
|
let dmem_base = app.dmem_base;
|
|
|
|
// SAFETY: we have exclusive access to `dma_object`.
|
|
let dmem_mapper: &mut FalconAppifDmemmapperV3 = unsafe {
|
|
transmute_mut(
|
|
&mut dma_object,
|
|
(desc.imem_load_size() + dmem_base).into_safe_cast(),
|
|
)
|
|
}?;
|
|
|
|
dmem_mapper.init_cmd = match cmd {
|
|
FwsecCommand::Frts { .. } => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_FRTS,
|
|
FwsecCommand::Sb => NVFW_FALCON_APPIF_DMEMMAPPER_CMD_SB,
|
|
};
|
|
let cmd_in_buffer_offset = dmem_mapper.cmd_in_buffer_offset;
|
|
|
|
// SAFETY: we have exclusive access to `dma_object`.
|
|
let frts_cmd: &mut FrtsCmd = unsafe {
|
|
transmute_mut(
|
|
&mut dma_object,
|
|
(desc.imem_load_size() + cmd_in_buffer_offset).into_safe_cast(),
|
|
)
|
|
}?;
|
|
|
|
frts_cmd.read_vbios = ReadVbios {
|
|
ver: 1,
|
|
hdr: u32::try_from(size_of::<ReadVbios>())?,
|
|
addr: 0,
|
|
size: 0,
|
|
flags: 2,
|
|
};
|
|
if let FwsecCommand::Frts {
|
|
frts_addr,
|
|
frts_size,
|
|
} = cmd
|
|
{
|
|
frts_cmd.frts_region = FrtsRegion {
|
|
ver: 1,
|
|
hdr: u32::try_from(size_of::<FrtsRegion>())?,
|
|
addr: u32::try_from(frts_addr >> 12)?,
|
|
size: u32::try_from(frts_size >> 12)?,
|
|
ftype: NVFW_FRTS_CMD_REGION_TYPE_FB,
|
|
};
|
|
}
|
|
|
|
// Return early as we found and patched the DMEMMAPPER region.
|
|
return Ok(Self(dma_object, PhantomData));
|
|
}
|
|
|
|
Err(ENOTSUPP)
|
|
}
|
|
}
|
|
|
|
impl FwsecFirmware {
|
|
/// Extract the Fwsec firmware from `bios` and patch it to run on `falcon` with the `cmd`
|
|
/// command.
|
|
pub(crate) fn new(
|
|
dev: &Device<device::Bound>,
|
|
falcon: &Falcon<Gsp>,
|
|
bar: &Bar0,
|
|
bios: &Vbios,
|
|
cmd: FwsecCommand,
|
|
) -> Result<Self> {
|
|
let ucode_dma = FirmwareDmaObject::<Self, _>::new_fwsec(dev, bios, cmd)?;
|
|
|
|
// Patch signature if needed.
|
|
let desc = bios.fwsec_image().header()?;
|
|
let ucode_signed = if desc.signature_count() != 0 {
|
|
let sig_base_img =
|
|
usize::from_safe_cast(desc.imem_load_size() + desc.pkc_data_offset());
|
|
let desc_sig_versions = u32::from(desc.signature_versions());
|
|
let reg_fuse_version =
|
|
falcon.signature_reg_fuse_version(bar, desc.engine_id_mask(), desc.ucode_id())?;
|
|
dev_dbg!(
|
|
dev,
|
|
"desc_sig_versions: {:#x}, reg_fuse_version: {}\n",
|
|
desc_sig_versions,
|
|
reg_fuse_version
|
|
);
|
|
let signature_idx = {
|
|
let reg_fuse_version_bit = 1 << reg_fuse_version;
|
|
|
|
// Check if the fuse version is supported by the firmware.
|
|
if desc_sig_versions & reg_fuse_version_bit == 0 {
|
|
dev_err!(
|
|
dev,
|
|
"no matching signature: {:#x} {:#x}\n",
|
|
reg_fuse_version_bit,
|
|
desc_sig_versions,
|
|
);
|
|
return Err(EINVAL);
|
|
}
|
|
|
|
// `desc_sig_versions` has one bit set per included signature. Thus, the index of
|
|
// the signature to patch is the number of bits in `desc_sig_versions` set to `1`
|
|
// before `reg_fuse_version_bit`.
|
|
|
|
// Mask of the bits of `desc_sig_versions` to preserve.
|
|
let reg_fuse_version_mask = reg_fuse_version_bit.wrapping_sub(1);
|
|
|
|
usize::from_safe_cast((desc_sig_versions & reg_fuse_version_mask).count_ones())
|
|
};
|
|
|
|
dev_dbg!(dev, "patching signature with index {}\n", signature_idx);
|
|
let signature = bios
|
|
.fwsec_image()
|
|
.sigs(&desc)
|
|
.and_then(|sigs| sigs.get(signature_idx).ok_or(EINVAL))?;
|
|
|
|
ucode_dma.patch_signature(signature, sig_base_img)?
|
|
} else {
|
|
ucode_dma.no_patch_signature()
|
|
};
|
|
|
|
Ok(FwsecFirmware {
|
|
desc,
|
|
ucode: ucode_signed,
|
|
})
|
|
}
|
|
|
|
/// Loads the FWSEC firmware into `falcon` and execute it.
|
|
pub(crate) fn run(
|
|
&self,
|
|
dev: &Device<device::Bound>,
|
|
falcon: &Falcon<Gsp>,
|
|
bar: &Bar0,
|
|
) -> Result<()> {
|
|
// Reset falcon, load the firmware, and run it.
|
|
falcon
|
|
.reset(bar)
|
|
.inspect_err(|e| dev_err!(dev, "Failed to reset GSP falcon: {:?}\n", e))?;
|
|
falcon
|
|
.load(bar, self)
|
|
.inspect_err(|e| dev_err!(dev, "Failed to load FWSEC firmware: {:?}\n", e))?;
|
|
let (mbox0, _) = falcon
|
|
.boot(bar, Some(0), None)
|
|
.inspect_err(|e| dev_err!(dev, "Failed to boot FWSEC firmware: {:?}\n", e))?;
|
|
if mbox0 != 0 {
|
|
dev_err!(dev, "FWSEC firmware returned error {}\n", mbox0);
|
|
Err(EIO)
|
|
} else {
|
|
Ok(())
|
|
}
|
|
}
|
|
}
|