gsp.rs 5.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160
  1. // SPDX-License-Identifier: GPL-2.0
  2. mod boot;
  3. use kernel::{
  4. device,
  5. dma::{
  6. CoherentAllocation,
  7. DmaAddress, //
  8. },
  9. dma_write,
  10. pci,
  11. prelude::*,
  12. transmute::AsBytes, //
  13. };
  14. pub(crate) mod cmdq;
  15. pub(crate) mod commands;
  16. mod fw;
  17. mod sequencer;
  18. pub(crate) use fw::{
  19. GspFwWprMeta,
  20. LibosParams, //
  21. };
  22. use crate::{
  23. gsp::cmdq::Cmdq,
  24. gsp::fw::{
  25. GspArgumentsPadded,
  26. LibosMemoryRegionInitArgument, //
  27. },
  28. num,
  29. };
  30. pub(crate) const GSP_PAGE_SHIFT: usize = 12;
  31. pub(crate) const GSP_PAGE_SIZE: usize = 1 << GSP_PAGE_SHIFT;
  32. /// Number of GSP pages to use in a RM log buffer.
  33. const RM_LOG_BUFFER_NUM_PAGES: usize = 0x10;
  34. /// Array of page table entries, as understood by the GSP bootloader.
  35. #[repr(C)]
  36. struct PteArray<const NUM_ENTRIES: usize>([u64; NUM_ENTRIES]);
  37. /// SAFETY: arrays of `u64` implement `AsBytes` and we are but a wrapper around one.
  38. unsafe impl<const NUM_ENTRIES: usize> AsBytes for PteArray<NUM_ENTRIES> {}
  39. impl<const NUM_PAGES: usize> PteArray<NUM_PAGES> {
  40. /// Returns the page table entry for `index`, for a mapping starting at `start`.
  41. // TODO: Replace with `IoView` projection once available.
  42. fn entry(start: DmaAddress, index: usize) -> Result<u64> {
  43. start
  44. .checked_add(num::usize_as_u64(index) << GSP_PAGE_SHIFT)
  45. .ok_or(EOVERFLOW)
  46. }
  47. }
  48. /// The logging buffers are byte queues that contain encoded printf-like
  49. /// messages from GSP-RM. They need to be decoded by a special application
  50. /// that can parse the buffers.
  51. ///
  52. /// The 'loginit' buffer contains logs from early GSP-RM init and
  53. /// exception dumps. The 'logrm' buffer contains the subsequent logs. Both are
  54. /// written to directly by GSP-RM and can be any multiple of GSP_PAGE_SIZE.
  55. ///
  56. /// The physical address map for the log buffer is stored in the buffer
  57. /// itself, starting with offset 1. Offset 0 contains the "put" pointer (pp).
  58. /// Initially, pp is equal to 0. If the buffer has valid logging data in it,
  59. /// then pp points to index into the buffer where the next logging entry will
  60. /// be written. Therefore, the logging data is valid if:
  61. /// 1 <= pp < sizeof(buffer)/sizeof(u64)
  62. struct LogBuffer(CoherentAllocation<u8>);
  63. impl LogBuffer {
  64. /// Creates a new `LogBuffer` mapped on `dev`.
  65. fn new(dev: &device::Device<device::Bound>) -> Result<Self> {
  66. const NUM_PAGES: usize = RM_LOG_BUFFER_NUM_PAGES;
  67. let mut obj = Self(CoherentAllocation::<u8>::alloc_coherent(
  68. dev,
  69. NUM_PAGES * GSP_PAGE_SIZE,
  70. GFP_KERNEL | __GFP_ZERO,
  71. )?);
  72. let start_addr = obj.0.dma_handle();
  73. // SAFETY: `obj` has just been created and we are its sole user.
  74. let pte_region = unsafe {
  75. obj.0
  76. .as_slice_mut(size_of::<u64>(), NUM_PAGES * size_of::<u64>())?
  77. };
  78. // Write values one by one to avoid an on-stack instance of `PteArray`.
  79. for (i, chunk) in pte_region.chunks_exact_mut(size_of::<u64>()).enumerate() {
  80. let pte_value = PteArray::<0>::entry(start_addr, i)?;
  81. chunk.copy_from_slice(&pte_value.to_ne_bytes());
  82. }
  83. Ok(obj)
  84. }
  85. }
  86. /// GSP runtime data.
  87. #[pin_data]
  88. pub(crate) struct Gsp {
  89. /// Libos arguments.
  90. pub(crate) libos: CoherentAllocation<LibosMemoryRegionInitArgument>,
  91. /// Init log buffer.
  92. loginit: LogBuffer,
  93. /// Interrupts log buffer.
  94. logintr: LogBuffer,
  95. /// RM log buffer.
  96. logrm: LogBuffer,
  97. /// Command queue.
  98. pub(crate) cmdq: Cmdq,
  99. /// RM arguments.
  100. rmargs: CoherentAllocation<GspArgumentsPadded>,
  101. }
  102. impl Gsp {
  103. // Creates an in-place initializer for a `Gsp` manager for `pdev`.
  104. pub(crate) fn new(pdev: &pci::Device<device::Bound>) -> impl PinInit<Self, Error> + '_ {
  105. pin_init::pin_init_scope(move || {
  106. let dev = pdev.as_ref();
  107. Ok(try_pin_init!(Self {
  108. libos: CoherentAllocation::<LibosMemoryRegionInitArgument>::alloc_coherent(
  109. dev,
  110. GSP_PAGE_SIZE / size_of::<LibosMemoryRegionInitArgument>(),
  111. GFP_KERNEL | __GFP_ZERO,
  112. )?,
  113. loginit: LogBuffer::new(dev)?,
  114. logintr: LogBuffer::new(dev)?,
  115. logrm: LogBuffer::new(dev)?,
  116. cmdq: Cmdq::new(dev)?,
  117. rmargs: CoherentAllocation::<GspArgumentsPadded>::alloc_coherent(
  118. dev,
  119. 1,
  120. GFP_KERNEL | __GFP_ZERO,
  121. )?,
  122. _: {
  123. // Initialise the logging structures. The OpenRM equivalents are in:
  124. // _kgspInitLibosLoggingStructures (allocates memory for buffers)
  125. // kgspSetupLibosInitArgs_IMPL (creates pLibosInitArgs[] array)
  126. dma_write!(
  127. libos, [0]?, LibosMemoryRegionInitArgument::new("LOGINIT", &loginit.0)
  128. );
  129. dma_write!(
  130. libos, [1]?, LibosMemoryRegionInitArgument::new("LOGINTR", &logintr.0)
  131. );
  132. dma_write!(libos, [2]?, LibosMemoryRegionInitArgument::new("LOGRM", &logrm.0));
  133. dma_write!(rmargs, [0]?.inner, fw::GspArgumentsCached::new(cmdq));
  134. dma_write!(libos, [3]?, LibosMemoryRegionInitArgument::new("RMARGS", rmargs));
  135. },
  136. }))
  137. })
  138. }
  139. }