1 // SPDX-License-Identifier: GPL-2.0 2 3 //! Falcon microprocessor base support 4 5 use core::ops::Deref; 6 7 use hal::FalconHal; 8 9 use kernel::{ 10 device, 11 dma::{ 12 DmaAddress, 13 DmaMask, // 14 }, 15 io::poll::read_poll_timeout, 16 prelude::*, 17 sync::aref::ARef, 18 time::{ 19 delay::fsleep, 20 Delta, // 21 }, 22 }; 23 24 use crate::{ 25 dma::DmaObject, 26 driver::Bar0, 27 gpu::Chipset, 28 num::{ 29 FromSafeCast, 30 IntoSafeCast, // 31 }, 32 regs, 33 regs::macros::RegisterBase, // 34 }; 35 36 pub(crate) mod gsp; 37 mod hal; 38 pub(crate) mod sec2; 39 40 // TODO[FPRI]: Replace with `ToPrimitive`. 41 macro_rules! impl_from_enum_to_u8 { 42 ($enum_type:ty) => { 43 impl From<$enum_type> for u8 { 44 fn from(value: $enum_type) -> Self { 45 value as u8 46 } 47 } 48 }; 49 } 50 51 /// Revision number of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 52 /// register. 53 #[repr(u8)] 54 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 55 pub(crate) enum FalconCoreRev { 56 #[default] 57 Rev1 = 1, 58 Rev2 = 2, 59 Rev3 = 3, 60 Rev4 = 4, 61 Rev5 = 5, 62 Rev6 = 6, 63 Rev7 = 7, 64 } 65 impl_from_enum_to_u8!(FalconCoreRev); 66 67 // TODO[FPRI]: replace with `FromPrimitive`. 68 impl TryFrom<u8> for FalconCoreRev { 69 type Error = Error; 70 71 fn try_from(value: u8) -> Result<Self> { 72 use FalconCoreRev::*; 73 74 let rev = match value { 75 1 => Rev1, 76 2 => Rev2, 77 3 => Rev3, 78 4 => Rev4, 79 5 => Rev5, 80 6 => Rev6, 81 7 => Rev7, 82 _ => return Err(EINVAL), 83 }; 84 85 Ok(rev) 86 } 87 } 88 89 /// Revision subversion number of a falcon core, used in the 90 /// [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] register. 91 #[repr(u8)] 92 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq, PartialOrd, Ord)] 93 pub(crate) enum FalconCoreRevSubversion { 94 #[default] 95 Subversion0 = 0, 96 Subversion1 = 1, 97 Subversion2 = 2, 98 Subversion3 = 3, 99 } 100 impl_from_enum_to_u8!(FalconCoreRevSubversion); 101 102 // TODO[FPRI]: replace with `FromPrimitive`. 103 impl TryFrom<u8> for FalconCoreRevSubversion { 104 type Error = Error; 105 106 fn try_from(value: u8) -> Result<Self> { 107 use FalconCoreRevSubversion::*; 108 109 let sub_version = match value & 0b11 { 110 0 => Subversion0, 111 1 => Subversion1, 112 2 => Subversion2, 113 3 => Subversion3, 114 _ => return Err(EINVAL), 115 }; 116 117 Ok(sub_version) 118 } 119 } 120 121 /// Security model of a falcon core, used in the [`crate::regs::NV_PFALCON_FALCON_HWCFG1`] 122 /// register. 123 #[repr(u8)] 124 #[derive(Debug, Default, Copy, Clone)] 125 /// Security mode of the Falcon microprocessor. 126 /// 127 /// See `falcon.rst` for more details. 128 pub(crate) enum FalconSecurityModel { 129 /// Non-Secure: runs unsigned code without privileges. 130 #[default] 131 None = 0, 132 /// Light-Secured (LS): Runs signed code with some privileges. 133 /// Entry into this mode is only possible from 'Heavy-secure' mode, which verifies the code's 134 /// signature. 135 /// 136 /// Also known as Low-Secure, Privilege Level 2 or PL2. 137 Light = 2, 138 /// Heavy-Secured (HS): Runs signed code with full privileges. 139 /// The code's signature is verified by the Falcon Boot ROM (BROM). 140 /// 141 /// Also known as High-Secure, Privilege Level 3 or PL3. 142 Heavy = 3, 143 } 144 impl_from_enum_to_u8!(FalconSecurityModel); 145 146 // TODO[FPRI]: replace with `FromPrimitive`. 147 impl TryFrom<u8> for FalconSecurityModel { 148 type Error = Error; 149 150 fn try_from(value: u8) -> Result<Self> { 151 use FalconSecurityModel::*; 152 153 let sec_model = match value { 154 0 => None, 155 2 => Light, 156 3 => Heavy, 157 _ => return Err(EINVAL), 158 }; 159 160 Ok(sec_model) 161 } 162 } 163 164 /// Signing algorithm for a given firmware, used in the [`crate::regs::NV_PFALCON2_FALCON_MOD_SEL`] 165 /// register. It is passed to the Falcon Boot ROM (BROM) as a parameter. 166 #[repr(u8)] 167 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 168 pub(crate) enum FalconModSelAlgo { 169 /// AES. 170 #[expect(dead_code)] 171 Aes = 0, 172 /// RSA3K. 173 #[default] 174 Rsa3k = 1, 175 } 176 impl_from_enum_to_u8!(FalconModSelAlgo); 177 178 // TODO[FPRI]: replace with `FromPrimitive`. 179 impl TryFrom<u8> for FalconModSelAlgo { 180 type Error = Error; 181 182 fn try_from(value: u8) -> Result<Self> { 183 match value { 184 1 => Ok(FalconModSelAlgo::Rsa3k), 185 _ => Err(EINVAL), 186 } 187 } 188 } 189 190 /// Valid values for the `size` field of the [`crate::regs::NV_PFALCON_FALCON_DMATRFCMD`] register. 191 #[repr(u8)] 192 #[derive(Debug, Default, Copy, Clone, PartialEq, Eq)] 193 pub(crate) enum DmaTrfCmdSize { 194 /// 256 bytes transfer. 195 #[default] 196 Size256B = 0x6, 197 } 198 impl_from_enum_to_u8!(DmaTrfCmdSize); 199 200 // TODO[FPRI]: replace with `FromPrimitive`. 201 impl TryFrom<u8> for DmaTrfCmdSize { 202 type Error = Error; 203 204 fn try_from(value: u8) -> Result<Self> { 205 match value { 206 0x6 => Ok(Self::Size256B), 207 _ => Err(EINVAL), 208 } 209 } 210 } 211 212 /// Currently active core on a dual falcon/riscv (Peregrine) controller. 213 #[derive(Debug, Clone, Copy, PartialEq, Eq, Default)] 214 pub(crate) enum PeregrineCoreSelect { 215 /// Falcon core is active. 216 #[default] 217 Falcon = 0, 218 /// RISC-V core is active. 219 Riscv = 1, 220 } 221 222 impl From<bool> for PeregrineCoreSelect { 223 fn from(value: bool) -> Self { 224 match value { 225 false => PeregrineCoreSelect::Falcon, 226 true => PeregrineCoreSelect::Riscv, 227 } 228 } 229 } 230 231 impl From<PeregrineCoreSelect> for bool { 232 fn from(value: PeregrineCoreSelect) -> Self { 233 match value { 234 PeregrineCoreSelect::Falcon => false, 235 PeregrineCoreSelect::Riscv => true, 236 } 237 } 238 } 239 240 /// Different types of memory present in a falcon core. 241 #[derive(Debug, Clone, Copy, PartialEq, Eq)] 242 pub(crate) enum FalconMem { 243 /// Secure Instruction Memory. 244 ImemSecure, 245 /// Non-Secure Instruction Memory. 246 #[expect(unused)] 247 ImemNonSecure, 248 /// Data Memory. 249 Dmem, 250 } 251 252 /// Defines the Framebuffer Interface (FBIF) aperture type. 253 /// This determines the memory type for external memory access during a DMA transfer, which is 254 /// performed by the Falcon's Framebuffer DMA (FBDMA) engine. See falcon.rst for more details. 255 #[derive(Debug, Clone, Default)] 256 pub(crate) enum FalconFbifTarget { 257 /// VRAM. 258 #[default] 259 /// Local Framebuffer (GPU's VRAM memory). 260 LocalFb = 0, 261 /// Coherent system memory (System DRAM). 262 CoherentSysmem = 1, 263 /// Non-coherent system memory (System DRAM). 264 NoncoherentSysmem = 2, 265 } 266 impl_from_enum_to_u8!(FalconFbifTarget); 267 268 // TODO[FPRI]: replace with `FromPrimitive`. 269 impl TryFrom<u8> for FalconFbifTarget { 270 type Error = Error; 271 272 fn try_from(value: u8) -> Result<Self> { 273 let res = match value { 274 0 => Self::LocalFb, 275 1 => Self::CoherentSysmem, 276 2 => Self::NoncoherentSysmem, 277 _ => return Err(EINVAL), 278 }; 279 280 Ok(res) 281 } 282 } 283 284 /// Type of memory addresses to use. 285 #[derive(Debug, Clone, Default)] 286 pub(crate) enum FalconFbifMemType { 287 /// Virtual memory addresses. 288 #[default] 289 Virtual = 0, 290 /// Physical memory addresses. 291 Physical = 1, 292 } 293 294 /// Conversion from a single-bit register field. 295 impl From<bool> for FalconFbifMemType { 296 fn from(value: bool) -> Self { 297 match value { 298 false => Self::Virtual, 299 true => Self::Physical, 300 } 301 } 302 } 303 304 impl From<FalconFbifMemType> for bool { 305 fn from(value: FalconFbifMemType) -> Self { 306 match value { 307 FalconFbifMemType::Virtual => false, 308 FalconFbifMemType::Physical => true, 309 } 310 } 311 } 312 313 /// Type used to represent the `PFALCON` registers address base for a given falcon engine. 314 pub(crate) struct PFalconBase(()); 315 316 /// Type used to represent the `PFALCON2` registers address base for a given falcon engine. 317 pub(crate) struct PFalcon2Base(()); 318 319 /// Trait defining the parameters of a given Falcon engine. 320 /// 321 /// Each engine provides one base for `PFALCON` and `PFALCON2` registers. The `ID` constant is used 322 /// to identify a given Falcon instance with register I/O methods. 323 pub(crate) trait FalconEngine: 324 Send + Sync + RegisterBase<PFalconBase> + RegisterBase<PFalcon2Base> + Sized 325 { 326 /// Singleton of the engine, used to identify it with register I/O methods. 327 const ID: Self; 328 } 329 330 /// Represents a portion of the firmware to be loaded into a particular memory (e.g. IMEM or DMEM). 331 #[derive(Debug, Clone)] 332 pub(crate) struct FalconLoadTarget { 333 /// Offset from the start of the source object to copy from. 334 pub(crate) src_start: u32, 335 /// Offset from the start of the destination memory to copy into. 336 pub(crate) dst_start: u32, 337 /// Number of bytes to copy. 338 pub(crate) len: u32, 339 } 340 341 /// Parameters for the falcon boot ROM. 342 #[derive(Debug, Clone)] 343 pub(crate) struct FalconBromParams { 344 /// Offset in `DMEM`` of the firmware's signature. 345 pub(crate) pkc_data_offset: u32, 346 /// Mask of engines valid for this firmware. 347 pub(crate) engine_id_mask: u16, 348 /// ID of the ucode used to infer a fuse register to validate the signature. 349 pub(crate) ucode_id: u8, 350 } 351 352 /// Trait for providing load parameters of falcon firmwares. 353 pub(crate) trait FalconLoadParams { 354 /// Returns the load parameters for Secure `IMEM`. 355 fn imem_sec_load_params(&self) -> FalconLoadTarget; 356 357 /// Returns the load parameters for Non-Secure `IMEM`, 358 /// used only on Turing and GA100. 359 fn imem_ns_load_params(&self) -> Option<FalconLoadTarget>; 360 361 /// Returns the load parameters for `DMEM`. 362 fn dmem_load_params(&self) -> FalconLoadTarget; 363 364 /// Returns the parameters to write into the BROM registers. 365 fn brom_params(&self) -> FalconBromParams; 366 367 /// Returns the start address of the firmware. 368 fn boot_addr(&self) -> u32; 369 } 370 371 /// Trait for a falcon firmware. 372 /// 373 /// A falcon firmware can be loaded on a given engine, and is presented in the form of a DMA 374 /// object. 375 pub(crate) trait FalconFirmware: FalconLoadParams + Deref<Target = DmaObject> { 376 /// Engine on which this firmware is to be loaded. 377 type Target: FalconEngine; 378 } 379 380 /// Contains the base parameters common to all Falcon instances. 381 pub(crate) struct Falcon<E: FalconEngine> { 382 hal: KBox<dyn FalconHal<E>>, 383 dev: ARef<device::Device>, 384 } 385 386 impl<E: FalconEngine + 'static> Falcon<E> { 387 /// Create a new falcon instance. 388 pub(crate) fn new(dev: &device::Device, chipset: Chipset) -> Result<Self> { 389 Ok(Self { 390 hal: hal::falcon_hal(chipset)?, 391 dev: dev.into(), 392 }) 393 } 394 395 /// Resets DMA-related registers. 396 pub(crate) fn dma_reset(&self, bar: &Bar0) { 397 regs::NV_PFALCON_FBIF_CTL::update(bar, &E::ID, |v| v.set_allow_phys_no_ctx(true)); 398 regs::NV_PFALCON_FALCON_DMACTL::default().write(bar, &E::ID); 399 } 400 401 /// Wait for memory scrubbing to complete. 402 fn reset_wait_mem_scrubbing(&self, bar: &Bar0) -> Result { 403 // TIMEOUT: memory scrubbing should complete in less than 20ms. 404 read_poll_timeout( 405 || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), 406 |r| r.mem_scrubbing_done(), 407 Delta::ZERO, 408 Delta::from_millis(20), 409 ) 410 .map(|_| ()) 411 } 412 413 /// Reset the falcon engine. 414 fn reset_eng(&self, bar: &Bar0) -> Result { 415 let _ = regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID); 416 417 // According to OpenRM's `kflcnPreResetWait_GA102` documentation, HW sometimes does not set 418 // RESET_READY so a non-failing timeout is used. 419 let _ = read_poll_timeout( 420 || Ok(regs::NV_PFALCON_FALCON_HWCFG2::read(bar, &E::ID)), 421 |r| r.reset_ready(), 422 Delta::ZERO, 423 Delta::from_micros(150), 424 ); 425 426 regs::NV_PFALCON_FALCON_ENGINE::update(bar, &E::ID, |v| v.set_reset(true)); 427 428 // TIMEOUT: falcon engine should not take more than 10us to reset. 429 fsleep(Delta::from_micros(10)); 430 431 regs::NV_PFALCON_FALCON_ENGINE::update(bar, &E::ID, |v| v.set_reset(false)); 432 433 self.reset_wait_mem_scrubbing(bar)?; 434 435 Ok(()) 436 } 437 438 /// Reset the controller, select the falcon core, and wait for memory scrubbing to complete. 439 pub(crate) fn reset(&self, bar: &Bar0) -> Result { 440 self.reset_eng(bar)?; 441 self.hal.select_core(self, bar)?; 442 self.reset_wait_mem_scrubbing(bar)?; 443 444 regs::NV_PFALCON_FALCON_RM::default() 445 .set_value(regs::NV_PMC_BOOT_0::read(bar).into()) 446 .write(bar, &E::ID); 447 448 Ok(()) 449 } 450 451 /// Perform a DMA write according to `load_offsets` from `dma_handle` into the falcon's 452 /// `target_mem`. 453 /// 454 /// `sec` is set if the loaded firmware is expected to run in secure mode. 455 fn dma_wr<F: FalconFirmware<Target = E>>( 456 &self, 457 bar: &Bar0, 458 fw: &F, 459 target_mem: FalconMem, 460 load_offsets: FalconLoadTarget, 461 sec: bool, 462 ) -> Result { 463 const DMA_LEN: u32 = 256; 464 465 // For IMEM, we want to use the start offset as a virtual address tag for each page, since 466 // code addresses in the firmware (and the boot vector) are virtual. 467 // 468 // For DMEM we can fold the start offset into the DMA handle. 469 let (src_start, dma_start) = match target_mem { 470 FalconMem::ImemSecure | FalconMem::ImemNonSecure => { 471 (load_offsets.src_start, fw.dma_handle()) 472 } 473 FalconMem::Dmem => ( 474 0, 475 fw.dma_handle_with_offset(load_offsets.src_start.into_safe_cast())?, 476 ), 477 }; 478 if dma_start % DmaAddress::from(DMA_LEN) > 0 { 479 dev_err!( 480 self.dev, 481 "DMA transfer start addresses must be a multiple of {}\n", 482 DMA_LEN 483 ); 484 return Err(EINVAL); 485 } 486 487 // The DMATRFBASE/1 register pair only supports a 49-bit address. 488 if dma_start > DmaMask::new::<49>().value() { 489 dev_err!(self.dev, "DMA address {:#x} exceeds 49 bits\n", dma_start); 490 return Err(ERANGE); 491 } 492 493 // DMA transfers can only be done in units of 256 bytes. Compute how many such transfers we 494 // need to perform. 495 let num_transfers = load_offsets.len.div_ceil(DMA_LEN); 496 497 // Check that the area we are about to transfer is within the bounds of the DMA object. 498 // Upper limit of transfer is `(num_transfers * DMA_LEN) + load_offsets.src_start`. 499 match num_transfers 500 .checked_mul(DMA_LEN) 501 .and_then(|size| size.checked_add(load_offsets.src_start)) 502 { 503 None => { 504 dev_err!(self.dev, "DMA transfer length overflow\n"); 505 return Err(EOVERFLOW); 506 } 507 Some(upper_bound) if usize::from_safe_cast(upper_bound) > fw.size() => { 508 dev_err!(self.dev, "DMA transfer goes beyond range of DMA object\n"); 509 return Err(EINVAL); 510 } 511 Some(_) => (), 512 }; 513 514 // Set up the base source DMA address. 515 516 regs::NV_PFALCON_FALCON_DMATRFBASE::default() 517 // CAST: `as u32` is used on purpose since we do want to strip the upper bits, which 518 // will be written to `NV_PFALCON_FALCON_DMATRFBASE1`. 519 .set_base((dma_start >> 8) as u32) 520 .write(bar, &E::ID); 521 regs::NV_PFALCON_FALCON_DMATRFBASE1::default() 522 // CAST: `as u16` is used on purpose since the remaining bits are guaranteed to fit 523 // within a `u16`. 524 .set_base((dma_start >> 40) as u16) 525 .write(bar, &E::ID); 526 527 let cmd = regs::NV_PFALCON_FALCON_DMATRFCMD::default() 528 .set_size(DmaTrfCmdSize::Size256B) 529 .set_imem(target_mem != FalconMem::Dmem) 530 .set_sec(if sec { 1 } else { 0 }); 531 532 for pos in (0..num_transfers).map(|i| i * DMA_LEN) { 533 // Perform a transfer of size `DMA_LEN`. 534 regs::NV_PFALCON_FALCON_DMATRFMOFFS::default() 535 .set_offs(load_offsets.dst_start + pos) 536 .write(bar, &E::ID); 537 regs::NV_PFALCON_FALCON_DMATRFFBOFFS::default() 538 .set_offs(src_start + pos) 539 .write(bar, &E::ID); 540 cmd.write(bar, &E::ID); 541 542 // Wait for the transfer to complete. 543 // TIMEOUT: arbitrarily large value, no DMA transfer to the falcon's small memories 544 // should ever take that long. 545 read_poll_timeout( 546 || Ok(regs::NV_PFALCON_FALCON_DMATRFCMD::read(bar, &E::ID)), 547 |r| r.idle(), 548 Delta::ZERO, 549 Delta::from_secs(2), 550 )?; 551 } 552 553 Ok(()) 554 } 555 556 /// Perform a DMA load into `IMEM` and `DMEM` of `fw`, and prepare the falcon to run it. 557 pub(crate) fn dma_load<F: FalconFirmware<Target = E>>(&self, bar: &Bar0, fw: &F) -> Result { 558 // The Non-Secure section only exists on firmware used by Turing and GA100, and 559 // those platforms do not use DMA. 560 if fw.imem_ns_load_params().is_some() { 561 debug_assert!(false); 562 return Err(EINVAL); 563 } 564 565 self.dma_reset(bar); 566 regs::NV_PFALCON_FBIF_TRANSCFG::update(bar, &E::ID, 0, |v| { 567 v.set_target(FalconFbifTarget::CoherentSysmem) 568 .set_mem_type(FalconFbifMemType::Physical) 569 }); 570 571 self.dma_wr( 572 bar, 573 fw, 574 FalconMem::ImemSecure, 575 fw.imem_sec_load_params(), 576 true, 577 )?; 578 self.dma_wr(bar, fw, FalconMem::Dmem, fw.dmem_load_params(), true)?; 579 580 self.hal.program_brom(self, bar, &fw.brom_params())?; 581 582 // Set `BootVec` to start of non-secure code. 583 regs::NV_PFALCON_FALCON_BOOTVEC::default() 584 .set_value(fw.boot_addr()) 585 .write(bar, &E::ID); 586 587 Ok(()) 588 } 589 590 /// Wait until the falcon CPU is halted. 591 pub(crate) fn wait_till_halted(&self, bar: &Bar0) -> Result<()> { 592 // TIMEOUT: arbitrarily large value, firmwares should complete in less than 2 seconds. 593 read_poll_timeout( 594 || Ok(regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID)), 595 |r| r.halted(), 596 Delta::ZERO, 597 Delta::from_secs(2), 598 )?; 599 600 Ok(()) 601 } 602 603 /// Start the falcon CPU. 604 pub(crate) fn start(&self, bar: &Bar0) -> Result<()> { 605 match regs::NV_PFALCON_FALCON_CPUCTL::read(bar, &E::ID).alias_en() { 606 true => regs::NV_PFALCON_FALCON_CPUCTL_ALIAS::default() 607 .set_startcpu(true) 608 .write(bar, &E::ID), 609 false => regs::NV_PFALCON_FALCON_CPUCTL::default() 610 .set_startcpu(true) 611 .write(bar, &E::ID), 612 } 613 614 Ok(()) 615 } 616 617 /// Writes values to the mailbox registers if provided. 618 pub(crate) fn write_mailboxes(&self, bar: &Bar0, mbox0: Option<u32>, mbox1: Option<u32>) { 619 if let Some(mbox0) = mbox0 { 620 regs::NV_PFALCON_FALCON_MAILBOX0::default() 621 .set_value(mbox0) 622 .write(bar, &E::ID); 623 } 624 625 if let Some(mbox1) = mbox1 { 626 regs::NV_PFALCON_FALCON_MAILBOX1::default() 627 .set_value(mbox1) 628 .write(bar, &E::ID); 629 } 630 } 631 632 /// Reads the value from `mbox0` register. 633 pub(crate) fn read_mailbox0(&self, bar: &Bar0) -> u32 { 634 regs::NV_PFALCON_FALCON_MAILBOX0::read(bar, &E::ID).value() 635 } 636 637 /// Reads the value from `mbox1` register. 638 pub(crate) fn read_mailbox1(&self, bar: &Bar0) -> u32 { 639 regs::NV_PFALCON_FALCON_MAILBOX1::read(bar, &E::ID).value() 640 } 641 642 /// Reads values from both mailbox registers. 643 pub(crate) fn read_mailboxes(&self, bar: &Bar0) -> (u32, u32) { 644 let mbox0 = self.read_mailbox0(bar); 645 let mbox1 = self.read_mailbox1(bar); 646 647 (mbox0, mbox1) 648 } 649 650 /// Start running the loaded firmware. 651 /// 652 /// `mbox0` and `mbox1` are optional parameters to write into the `MBOX0` and `MBOX1` registers 653 /// prior to running. 654 /// 655 /// Wait up to two seconds for the firmware to complete, and return its exit status read from 656 /// the `MBOX0` and `MBOX1` registers. 657 pub(crate) fn boot( 658 &self, 659 bar: &Bar0, 660 mbox0: Option<u32>, 661 mbox1: Option<u32>, 662 ) -> Result<(u32, u32)> { 663 self.write_mailboxes(bar, mbox0, mbox1); 664 self.start(bar)?; 665 self.wait_till_halted(bar)?; 666 Ok(self.read_mailboxes(bar)) 667 } 668 669 /// Returns the fused version of the signature to use in order to run a HS firmware on this 670 /// falcon instance. `engine_id_mask` and `ucode_id` are obtained from the firmware header. 671 pub(crate) fn signature_reg_fuse_version( 672 &self, 673 bar: &Bar0, 674 engine_id_mask: u16, 675 ucode_id: u8, 676 ) -> Result<u32> { 677 self.hal 678 .signature_reg_fuse_version(self, bar, engine_id_mask, ucode_id) 679 } 680 681 /// Check if the RISC-V core is active. 682 /// 683 /// Returns `true` if the RISC-V core is active, `false` otherwise. 684 pub(crate) fn is_riscv_active(&self, bar: &Bar0) -> bool { 685 let cpuctl = regs::NV_PRISCV_RISCV_CPUCTL::read(bar, &E::ID); 686 cpuctl.active_stat() 687 } 688 689 /// Write the application version to the OS register. 690 pub(crate) fn write_os_version(&self, bar: &Bar0, app_version: u32) { 691 regs::NV_PFALCON_FALCON_OS::default() 692 .set_value(app_version) 693 .write(bar, &E::ID); 694 } 695 } 696