|
3 | 3 | //! Contains structures and functions dedicated to the parsing, building and patching of firmwares
|
4 | 4 | //! to be loaded into a given execution unit.
|
5 | 5 |
|
| 6 | +use core::marker::PhantomData; |
| 7 | + |
6 | 8 | use kernel::device;
|
7 | 9 | use kernel::firmware;
|
8 | 10 | use kernel::prelude::*;
|
9 | 11 | use kernel::str::CString;
|
10 | 12 |
|
| 13 | +use crate::dma::DmaObject; |
| 14 | +use crate::falcon::FalconFirmware; |
11 | 15 | use crate::gpu;
|
12 | 16 | use crate::gpu::Chipset;
|
13 | 17 |
|
@@ -84,6 +88,66 @@ impl FalconUCodeDescV3 {
|
84 | 88 | }
|
85 | 89 | }
|
86 | 90 |
|
| 91 | +/// Trait implemented by types defining the signed state of a firmware. |
| 92 | +trait SignedState {} |
| 93 | + |
| 94 | +/// Type indicating that the firmware must be signed before it can be used. |
| 95 | +struct Unsigned; |
| 96 | +impl SignedState for Unsigned {} |
| 97 | + |
| 98 | +/// Type indicating that the firmware is signed and ready to be loaded. |
| 99 | +struct Signed; |
| 100 | +impl SignedState for Signed {} |
| 101 | + |
| 102 | +/// A [`DmaObject`] containing a specific microcode ready to be loaded into a falcon. |
| 103 | +/// |
| 104 | +/// This is module-local and meant for sub-modules to use internally. |
| 105 | +/// |
| 106 | +/// After construction, a firmware is [`Unsigned`], and must generally be patched with a signature |
| 107 | +/// before it can be loaded (with an exception for development hardware). The |
| 108 | +/// [`Self::patch_signature`] and [`Self::no_patch_signature`] methods are used to transition the |
| 109 | +/// firmware to its [`Signed`] state. |
| 110 | +struct FirmwareDmaObject<F: FalconFirmware, S: SignedState>(DmaObject, PhantomData<(F, S)>); |
| 111 | + |
| 112 | +/// Trait for signatures to be patched directly into a given firmware. |
| 113 | +/// |
| 114 | +/// This is module-local and meant for sub-modules to use internally. |
| 115 | +trait FirmwareSignature<F: FalconFirmware>: AsRef<[u8]> {} |
| 116 | + |
| 117 | +#[expect(unused)] |
| 118 | +impl<F: FalconFirmware> FirmwareDmaObject<F, Unsigned> { |
| 119 | + /// Patches the firmware at offset `sig_base_img` with `signature`. |
| 120 | + fn patch_signature<S: FirmwareSignature<F>>( |
| 121 | + mut self, |
| 122 | + signature: &S, |
| 123 | + sig_base_img: usize, |
| 124 | + ) -> Result<FirmwareDmaObject<F, Signed>> { |
| 125 | + let signature_bytes = signature.as_ref(); |
| 126 | + if sig_base_img + signature_bytes.len() > self.0.size() { |
| 127 | + return Err(EINVAL); |
| 128 | + } |
| 129 | + |
| 130 | + // SAFETY: We are the only user of this object, so there cannot be any race. |
| 131 | + let dst = unsafe { self.0.start_ptr_mut().add(sig_base_img) }; |
| 132 | + |
| 133 | + // SAFETY: `signature` and `dst` are valid, properly aligned, and do not overlap. |
| 134 | + unsafe { |
| 135 | + core::ptr::copy_nonoverlapping(signature_bytes.as_ptr(), dst, signature_bytes.len()) |
| 136 | + }; |
| 137 | + |
| 138 | + Ok(FirmwareDmaObject(self.0, PhantomData)) |
| 139 | + } |
| 140 | + |
| 141 | + /// Mark the firmware as signed without patching it. |
| 142 | + /// |
| 143 | + /// This method is used to explicitly confirm that we do not need to sign the firmware, while |
| 144 | + /// allowing us to continue as if it was. This is typically only needed for development |
| 145 | + /// hardware. |
| 146 | + fn no_patch_signature(self) -> FirmwareDmaObject<F, Signed> { |
| 147 | + FirmwareDmaObject(self.0, PhantomData) |
| 148 | + } |
| 149 | +} |
| 150 | + |
87 | 151 | pub(crate) struct ModInfoBuilder<const N: usize>(firmware::ModInfoBuilder<N>);
|
88 | 152 |
|
89 | 153 | impl<const N: usize> ModInfoBuilder<N> {
|
|
0 commit comments