Running as a kvmtool guest in NV mode, the timer parser explodes
quickly, as finding the EL2 virtual timer is too much for it.
Granted, it only has been 11+ years since ARMv8.1 was publicly
announced, so this is awfully modern. Sigh.

Teach the ArmGenericTimerParser about all the architectural per-CPU
timers, checking that each of them actually exists in the DT.

Tested as a KVM guest at EL1 and EL2 (both E2H==0 and E2H==1).

Signed-off-by: Marc Zyngier <[email protected]>
Cc: Pierre Gondois <[email protected]>
Cc: Sami Mujawar <[email protected]>
Cc: Leif Lindholm <[email protected]>
Cc: Ard Biesheuvel <[email protected]>
---
 .../Arm/GenericTimer/ArmGenericTimerParser.c  | 86 ++++++++++++-------
 .../Arm/GenericTimer/ArmGenericTimerParser.h  |  1 +
 2 files changed, 56 insertions(+), 31 deletions(-)

diff --git 
a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.c
 
b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.c
index a14ed3a98a..65e30eb4c0 100644
--- 
a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.c
+++ 
b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.c
@@ -56,7 +56,8 @@ TimerNodeParser (
   UINT32        GicVersion;
   INT32         DataSize;
   INT32         IntCells;
-  BOOLEAN       AlwaysOnTimer;
+  INT32         IntCount;
+  UINT32        AlwaysOnTimerFlag;
 
   if ((Fdt == NULL) ||
       (GenericTimerInfo == NULL))
@@ -67,9 +68,9 @@ TimerNodeParser (
 
   Data = FdtGetProp (Fdt, TimerNode, "always-on", &DataSize);
   if ((Data == NULL) || (DataSize < 0)) {
-    AlwaysOnTimer = FALSE;
+    AlwaysOnTimerFlag = 0;
   } else {
-    AlwaysOnTimer = TRUE;
+    AlwaysOnTimerFlag = BIT2;
   }
 
   // Get the associated interrupt-controller.
@@ -99,36 +100,63 @@ TimerNodeParser (
   }
 
   Data = FdtGetProp (Fdt, TimerNode, "interrupts", &DataSize);
+  IntCount = DataSize / IntCells / sizeof (UINT32);
   if ((Data == NULL) ||
-      (DataSize != (FdtMaxTimerItem * IntCells * sizeof (UINT32))))
-  {
+      (IntCount > FdtMaxTimerItem)) {
     // If error or not FdtMaxTimerItem interrupts.
     ASSERT (0);
     return EFI_ABORTED;
   }
 
-  GenericTimerInfo->SecurePL1TimerGSIV =
-    FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]);
-  GenericTimerInfo->SecurePL1TimerFlags =
-    FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]);
-  GenericTimerInfo->NonSecurePL1TimerGSIV =
-    FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]);
-  GenericTimerInfo->NonSecurePL1TimerFlags =
-    FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]);
-  GenericTimerInfo->VirtualTimerGSIV =
-    FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]);
-  GenericTimerInfo->VirtualTimerFlags =
-    FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]);
-  GenericTimerInfo->NonSecurePL2TimerGSIV =
-    FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]);
-  GenericTimerInfo->NonSecurePL2TimerFlags =
-    FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]);
-
-  if (AlwaysOnTimer) {
-    GenericTimerInfo->SecurePL1TimerFlags    |= BIT2;
-    GenericTimerInfo->NonSecurePL1TimerFlags |= BIT2;
-    GenericTimerInfo->VirtualTimerFlags      |= BIT2;
-    GenericTimerInfo->NonSecurePL2TimerFlags |= BIT2;
+  if ((IntCount > FdtSecureTimerIrq)) {
+    GenericTimerInfo->SecurePL1TimerGSIV =
+      FdtGetInterruptId (&Data[FdtSecureTimerIrq * IntCells]);
+    GenericTimerInfo->SecurePL1TimerFlags =
+      FdtGetInterruptFlags (&Data[FdtSecureTimerIrq * IntCells]) | 
AlwaysOnTimerFlag;
+  } else {
+    // No timer, no luck
+    ASSERT (0);
+    return EFI_ABORTED;
+  }
+
+  if ((IntCount > FdtNonSecureTimerIrq)) {
+    GenericTimerInfo->NonSecurePL1TimerGSIV =
+      FdtGetInterruptId (&Data[FdtNonSecureTimerIrq * IntCells]);
+    GenericTimerInfo->NonSecurePL1TimerFlags =
+      FdtGetInterruptFlags (&Data[FdtNonSecureTimerIrq * IntCells]) | 
AlwaysOnTimerFlag;
+  } else {
+    GenericTimerInfo->NonSecurePL1TimerGSIV = 0;
+    GenericTimerInfo->NonSecurePL1TimerFlags = 0;
+  }
+
+  if ((IntCount > FdtVirtualTimerIrq)) {
+    GenericTimerInfo->VirtualTimerGSIV =
+      FdtGetInterruptId (&Data[FdtVirtualTimerIrq * IntCells]);
+    GenericTimerInfo->VirtualTimerFlags =
+      FdtGetInterruptFlags (&Data[FdtVirtualTimerIrq * IntCells]) | 
AlwaysOnTimerFlag;
+  } else {
+    GenericTimerInfo->VirtualTimerGSIV = 0;
+    GenericTimerInfo->VirtualTimerFlags = 0;
+  }
+
+  if ((IntCount > FdtHypervisorTimerIrq)) {
+    GenericTimerInfo->NonSecurePL2TimerGSIV =
+      FdtGetInterruptId (&Data[FdtHypervisorTimerIrq * IntCells]);
+    GenericTimerInfo->NonSecurePL2TimerFlags =
+      FdtGetInterruptFlags (&Data[FdtHypervisorTimerIrq * IntCells]) | 
AlwaysOnTimerFlag;
+  } else {
+    GenericTimerInfo->NonSecurePL2TimerGSIV = 0;
+    GenericTimerInfo->NonSecurePL2TimerFlags = 0;
+  }
+
+  if ((IntCount > FdtHypervisorVTimerIrq)) {
+    GenericTimerInfo->VirtualPL2TimerGSIV  =
+      FdtGetInterruptId (&Data[FdtHypervisorVTimerIrq * IntCells]);
+    GenericTimerInfo->VirtualPL2TimerFlags =
+      FdtGetInterruptFlags (&Data[FdtHypervisorVTimerIrq * IntCells]) | 
AlwaysOnTimerFlag;
+  } else {
+    GenericTimerInfo->VirtualPL2TimerGSIV  = 0;
+    GenericTimerInfo->VirtualPL2TimerFlags = 0;
   }
 
   // Setup default values
@@ -138,10 +166,6 @@ TimerNodeParser (
   GenericTimerInfo->CounterControlBaseAddress = 0xFFFFFFFFFFFFFFFF;
   GenericTimerInfo->CounterReadBaseAddress    = 0xFFFFFFFFFFFFFFFF;
 
-  // For systems not implementing ARMv8.1 VHE, this field is 0.
-  GenericTimerInfo->VirtualPL2TimerGSIV  = 0;
-  GenericTimerInfo->VirtualPL2TimerFlags = 0;
-
   return EFI_SUCCESS;
 }
 
diff --git 
a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.h
 
b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.h
index f4712048ef..8b685397b9 100644
--- 
a/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.h
+++ 
b/DynamicTablesPkg/Library/FdtHwInfoParserLib/Arm/GenericTimer/ArmGenericTimerParser.h
@@ -17,6 +17,7 @@ typedef enum FdtTimerInterruptItems {
   FdtNonSecureTimerIrq,   ///< Non-secure timer IRQ
   FdtVirtualTimerIrq,     ///< Virtual timer IRQ
   FdtHypervisorTimerIrq,  ///< Hypervisor timer IRQ
+  FdtHypervisorVTimerIrq, ///< Hypervisor virtual timer IRQ
   FdtMaxTimerItem         ///< Max timer item
 } FDT_TIMER_INTERRUPT_ITEMS;
 
-- 
2.47.3



-=-=-=-=-=-=-=-=-=-=-=-
Groups.io Links: You receive all messages sent to this group.
View/Reply Online (#122008): https://edk2.groups.io/g/devel/message/122008
Mute This Topic: https://groups.io/mt/120005632/21656
Group Owner: [email protected]
Unsubscribe: https://edk2.groups.io/g/devel/unsub [[email protected]]
-=-=-=-=-=-=-=-=-=-=-=-


Reply via email to