1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
|
/** @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);
}
}
|