mirror of https://github.com/acidanthera/audk.git
129 lines
3.0 KiB
C
129 lines
3.0 KiB
C
/** @file
|
|
Arm Monitor Library that chooses the conduit based on the PSCI node in the
|
|
device tree provided by the VMM.
|
|
|
|
Copyright (c) 2022, Arm Limited. All rights reserved.<BR>
|
|
Copyright (c) 2024, Google LLC. All rights reserved.<BR>
|
|
|
|
SPDX-License-Identifier: BSD-2-Clause-Patent
|
|
|
|
**/
|
|
|
|
#include <Base.h>
|
|
|
|
#include <Library/ArmHvcLib.h>
|
|
#include <Library/ArmMonitorLib.h>
|
|
#include <Library/ArmSmcLib.h>
|
|
#include <Library/BaseLib.h>
|
|
#include <Library/DebugLib.h>
|
|
#include <Library/FdtLib.h>
|
|
|
|
typedef enum {
|
|
SmcccConduitUnknown,
|
|
SmcccConduitSmc,
|
|
SmcccConduitHvc,
|
|
} SMCCC_CONDUIT;
|
|
|
|
/**
|
|
Discover the SMCCC conduit by parsing the PSCI device tree node.
|
|
|
|
@return the discovered SMCCC conduit
|
|
**/
|
|
STATIC
|
|
SMCCC_CONDUIT
|
|
DiscoverSmcccConduit (
|
|
VOID
|
|
)
|
|
{
|
|
VOID *DeviceTreeBase;
|
|
INT32 Node, Prev;
|
|
INT32 Len;
|
|
CONST FDT_PROPERTY *Compatible;
|
|
CONST CHAR8 *CompatibleItem;
|
|
CONST FDT_PROPERTY *Prop;
|
|
|
|
DeviceTreeBase = (VOID *)(UINTN)PcdGet64 (PcdDeviceTreeInitialBaseAddress);
|
|
ASSERT (FdtCheckHeader (DeviceTreeBase) == 0);
|
|
|
|
//
|
|
// Enumerate all FDT nodes looking for the PSCI node and capture the conduit
|
|
//
|
|
for (Prev = 0; ; Prev = Node) {
|
|
Node = FdtNextNode (DeviceTreeBase, Prev, NULL);
|
|
if (Node < 0) {
|
|
break;
|
|
}
|
|
|
|
Compatible = FdtGetProperty (DeviceTreeBase, Node, "compatible", &Len);
|
|
if (Compatible == NULL) {
|
|
continue;
|
|
}
|
|
|
|
//
|
|
// Iterate over the NULL-separated items in the compatible string
|
|
//
|
|
for (CompatibleItem = Compatible->Data; CompatibleItem < Compatible->Data + Len;
|
|
CompatibleItem += 1 + AsciiStrLen (CompatibleItem))
|
|
{
|
|
if (AsciiStrCmp (CompatibleItem, "arm,psci-0.2") != 0) {
|
|
continue;
|
|
}
|
|
|
|
Prop = FdtGetProperty (DeviceTreeBase, Node, "method", NULL);
|
|
if (Prop == NULL) {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Missing PSCI method property\n",
|
|
__func__
|
|
));
|
|
|
|
return SmcccConduitUnknown;
|
|
}
|
|
|
|
if (AsciiStrnCmp (Prop->Data, "hvc", 3) == 0) {
|
|
return SmcccConduitHvc;
|
|
} else if (AsciiStrnCmp (Prop->Data, "smc", 3) == 0) {
|
|
return SmcccConduitSmc;
|
|
} else {
|
|
DEBUG ((
|
|
DEBUG_ERROR,
|
|
"%a: Unknown PSCI method \"%a\"\n",
|
|
__func__,
|
|
Prop
|
|
));
|
|
|
|
return SmcccConduitUnknown;
|
|
}
|
|
}
|
|
}
|
|
|
|
return SmcccConduitUnknown;
|
|
}
|
|
|
|
/** Monitor call.
|
|
|
|
An HyperVisor Call (HVC) or System Monitor Call (SMC) will be issued
|
|
depending on the default conduit.
|
|
|
|
@param [in,out] Args Arguments for the HVC/SMC.
|
|
**/
|
|
VOID
|
|
EFIAPI
|
|
ArmMonitorCall (
|
|
IN OUT ARM_MONITOR_ARGS *Args
|
|
)
|
|
{
|
|
switch (DiscoverSmcccConduit ()) {
|
|
case SmcccConduitHvc:
|
|
ArmCallHvc ((ARM_HVC_ARGS *)Args);
|
|
break;
|
|
|
|
case SmcccConduitSmc:
|
|
ArmCallSmc ((ARM_SMC_ARGS *)Args);
|
|
break;
|
|
|
|
default:
|
|
ASSERT (FALSE);
|
|
}
|
|
}
|