Skip to content

Commit e73e76b

Browse files
dhaval-rivoscap2k4-rivos
authored andcommitted
StandaloneMmPkg: Implement RPMI Req-Fwd API interface
Implementation is based on https://github.com/riscv-non-isa/riscv-rpmi/tree/main and works in the following way: 1. MM initialization is successful -> call REQFWD_COMPLETE_CURRENT_MESSAGE to yield. (this API will change once we have properly defined the init API for MM) 2. NS domain calls MM_COMMUNICATE, OpenSBI performs context switch (if channel is not capable of SSE) -> MM resumes loop from REQFWD_COMPLETE_CURRENT_MESSAGE. 3. Calls REQFWD_RETRIEVE_CURRENT_MESSAGE. 4. MM handles the request contained in the message. 5. MM calls REQFWD_COMPLETE_CURRENT_MESSAGE. 6. OpenSBI switches to the non-secure domain (as there are no more messages in the queue && SSE is not supported) 7. Go to #2 Signed-off-by: Dhaval Sharma <[email protected]>
1 parent 99ae634 commit e73e76b

File tree

3 files changed

+337
-13
lines changed

3 files changed

+337
-13
lines changed

StandaloneMmPkg/Library/StandaloneMmCoreEntryPoint/RiscV64/StandaloneMmCoreEntryPoint.c

Lines changed: 259 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -8,9 +8,73 @@ SPDX-License-Identifier: BSD-2-Clause-Patent
88

99
#include <PiMm.h>
1010

11-
#include <StandaloneMmCpu.h>
11+
#include <Protocol/PiMmCpuDriverEp.h>
1212
#include <StandaloneMmCoreEntryPoint.h>
1313

14+
#include <PiPei.h>
15+
#include <Guid/MmramMemoryReserve.h>
16+
#include <Guid/MpInformation.h>
17+
18+
#include <Library/DebugLib.h>
19+
#include <Library/HobLib.h>
20+
#include <Library/BaseLib.h>
21+
#include <Library/MemoryAllocationLib.h>
22+
#include <Library/BaseMemoryLib.h>
23+
#include <Library/SerialPortLib.h>
24+
#include <Library/PcdLib.h>
25+
26+
#include <Library/BaseRiscVSbiLib.h>
27+
#include <Library/DxeRiscvMpxy.h>
28+
29+
/** RPMI Messages Types */
30+
enum rpmi_message_type {
31+
/* Normal request backed with ack */
32+
RPMI_MSG_NORMAL_REQUEST = 0x0,
33+
/* Request without any ack */
34+
RPMI_MSG_POSTED_REQUEST = 0x1,
35+
/* Acknowledgment for normal request message */
36+
RPMI_MSG_ACKNOWLDGEMENT = 0x2,
37+
/* Notification message */
38+
RPMI_MSG_NOTIFICATION = 0x3,
39+
};
40+
41+
/*
42+
* RPMI SERVICEGROUPS AND SERVICES
43+
*/
44+
45+
/** RPMI ServiceGroups IDs */
46+
enum rpmi_servicegroup_id {
47+
RPMI_SRVGRP_ID_MIN = 0,
48+
RPMI_SRVGRP_BASE = 0x00001,
49+
RPMI_SRVGRP_SYSTEM_RESET = 0x00002,
50+
RPMI_SRVGRP_SYSTEM_SUSPEND = 0x00003,
51+
RPMI_SRVGRP_HSM = 0x00004,
52+
RPMI_SRVGRP_CPPC = 0x00005,
53+
RPMI_SRVGRP_CLOCK = 0x00007,
54+
RPMI_SRVGRP_REQUEST_FORWARD = 0x0000D,
55+
RPMI_SRVGRP_ID_MAX_COUNT,
56+
};
57+
58+
/** RPMI Error Types */
59+
enum rpmi_error {
60+
RPMI_SUCCESS = 0,
61+
RPMI_ERR_FAILED = -1,
62+
RPMI_ERR_NOTSUPP = -2,
63+
RPMI_ERR_INVAL = -3,
64+
RPMI_ERR_DENIED = -4,
65+
RPMI_ERR_NOTFOUND = -5,
66+
RPMI_ERR_OUTOFRANGE = -6,
67+
RPMI_ERR_OUTOFRES = -7,
68+
RPMI_ERR_HWFAULT = -8,
69+
};
70+
71+
/** RPMI ReqFwd ServiceGroup Service IDs */
72+
enum rpmi_reqfwd_service_id {
73+
RPMI_REQFWD_ENABLE_NOTIFICATION = 1,
74+
RPMI_REQFWD_RETRIEVE_CURRENT_MESSAGE = 2,
75+
RPMI_REQFWD_COMPLETE_CURRENT_MESSAGE = 3,
76+
};
77+
1478
/**
1579
Retrieve and print boot information provided by privileged firmware.
1680
@@ -29,7 +93,7 @@ GetAndPrintBootinformation (
2993
{
3094
EFI_RISCV_SMM_PAYLOAD_INFO *BootInfo;
3195
EFI_RISCV_SMM_CPU_INFO *CpuInfo;
32-
UINTN Index;
96+
UINTN Index;
3397

3498
BootInfo = (EFI_RISCV_SMM_PAYLOAD_INFO *)PayloadInfoAddress;
3599

@@ -55,21 +119,190 @@ GetAndPrintBootinformation (
55119
CpuInfo = (EFI_RISCV_SMM_CPU_INFO *)&BootInfo->CpuInfo;
56120

57121
for (Index = 0; Index < BootInfo->NumCpus; Index++) {
58-
DEBUG ((DEBUG_INFO, " CPU[%u] ProcessorId: 0x%lx, Package: %u, Core: %u\n",
59-
Index,
60-
CpuInfo[Index].ProcessorId,
61-
CpuInfo[Index].Package,
62-
CpuInfo[Index].Core));
122+
DEBUG ((
123+
DEBUG_INFO,
124+
" CPU[%u] ProcessorId: 0x%lx, Package: %u, Core: %u\n",
125+
Index,
126+
CpuInfo[Index].ProcessorId,
127+
CpuInfo[Index].Package,
128+
CpuInfo[Index].Core
129+
));
63130
}
64131

65132
return BootInfo;
66133
}
134+
135+
/**
136+
Prepare an RPMI message header for a forwarded MM request.
137+
138+
This routine fills out the RPMI header with the correct service group
139+
and message ID, using the standard flags for a normal request. In future
140+
this can be extended by passing required flags etc.
141+
142+
@param[out] Hdr Pointer to the RPMI message header structure to initialize.
143+
@param[in] Msg Message ID to assign to the header.
144+
**/
145+
STATIC
146+
VOID
147+
PrepareRpmiHeader (
148+
OUT RPMI_MESSAGE_HEADER *Hdr,
149+
IN UINT8 ServiceId,
150+
IN UINT16 DataLen
151+
)
152+
{
153+
Hdr->Flags = RPMI_MSG_NORMAL_REQUEST;
154+
Hdr->ServiceGroupId = RPMI_SRVGRP_REQUEST_FORWARD;
155+
Hdr->ServiceId = ServiceId;
156+
Hdr->DataLen = DataLen;
157+
}
158+
159+
/**
160+
Send a completion message to the host after MM handling completes.
161+
162+
This function uses MPXY to send a completion response for the last forwarded
163+
message, indicating success or failure back to the host firmware.
164+
165+
@param[in] ChannelId MPXY communication channel.
166+
@param[in] EventCompleteArgs Pointer to the completion response structure.
167+
168+
@retval EFI_SUCCESS Completion message successfully sent.
169+
@retval EFI_ACCESS_DENIED Communication failed.
170+
**/
171+
EFI_STATUS
172+
EFIAPI
173+
SendMMComplete (
174+
IN UINTN ChannelId,
175+
IN RPMI_SMM_MSG_CMPL_CMD *EventCompleteArgs
176+
)
177+
{
178+
EFI_STATUS Status;
179+
UINTN SmmMsgLen = sizeof (RPMI_SMM_MSG_CMPL_CMD);
180+
UINTN SmmRespLen = sizeof (RPMI_SMM_MSG_CMPL_RESP);
181+
RPMI_SMM_MSG_CMPL_RESP EventCompleteResp;
182+
183+
PrepareRpmiHeader (&EventCompleteArgs->hdr, RPMI_REQFWD_COMPLETE_CURRENT_MESSAGE, sizeof (RISCV_SMM_MSG_COMM_RESP));
184+
EventCompleteArgs->mm_resp.Status = RPMI_SUCCESS;
185+
186+
Status = SbiMpxySendMessage (
187+
ChannelId,
188+
RPMI_REQFWD_COMPLETE_CURRENT_MESSAGE,
189+
EventCompleteArgs,
190+
SmmMsgLen,
191+
&EventCompleteResp,
192+
&SmmRespLen
193+
);
194+
195+
// TODO: Add size verification for the response.
196+
if (EFI_ERROR (Status) || (EventCompleteResp.Status == RPMI_SUCCESS)) {
197+
DEBUG ((DEBUG_ERROR, "SendMMComplete: MPXY communication failed - %r\n", Status));
198+
Status = EFI_ERROR (Status);
199+
}
200+
201+
return EFI_SUCCESS;
202+
}
203+
204+
/**
205+
Retrieve a forwarded RAS message from the host over MPXY.
206+
207+
This function sends a retrieve request and waits for a valid forwarded message
208+
to be placed in the shared buffer. It also ensures the message is structurally
209+
valid before allowing it to proceed.
210+
211+
@param[in] ChannelId MPXY communication channel.
212+
@param[out] pReqFwdResp Pointer to buffer where the forwarded response is stored.
213+
214+
@retval EFI_SUCCESS Message successfully retrieved and verified.
215+
@retval EFI_ACCESS_DENIED MPXY communication failed.
216+
@retval EFI_COMPROMISED_DATA Message contents failed verification.
217+
**/
218+
EFI_STATUS
219+
EFIAPI
220+
RetrieveReqFwdMessage (
221+
IN UINTN ChannelId,
222+
OUT RPMI_SMM_MSG_COMM_ARGS *pReqFwdResp
223+
)
224+
{
225+
EFI_STATUS Status;
226+
UINTN SmmMsgLen, SmmRespLen;
227+
REQFWD_RETRIEVE_CMD ReqFwdCmd;
228+
229+
if (pReqFwdResp == NULL) {
230+
return EFI_INVALID_PARAMETER;
231+
}
232+
233+
PrepareRpmiHeader (&ReqFwdCmd.hdr, RPMI_REQFWD_RETRIEVE_CURRENT_MESSAGE, sizeof (UINT32));
234+
SmmMsgLen = sizeof (REQFWD_RETRIEVE_CMD);
235+
SmmRespLen = sizeof (RPMI_SMM_MSG_COMM_ARGS);
236+
237+
Status = SbiMpxySendMessage (
238+
ChannelId,
239+
RPMI_REQFWD_RETRIEVE_CURRENT_MESSAGE,
240+
&ReqFwdCmd,
241+
SmmMsgLen,
242+
pReqFwdResp,
243+
&SmmRespLen
244+
);
245+
if (EFI_ERROR (Status) || (SmmRespLen == 0)) {
246+
DEBUG ((DEBUG_ERROR, "RetrieveReqFwdMessage: MPXY communication failed or empty response\n"));
247+
return EFI_NO_RESPONSE;
248+
}
249+
250+
// TODO: Verify structure/content/response size etc to make it more robust
251+
if (pReqFwdResp->rpmi_resp.hdr.ServiceGroupId != RPMI_SRVGRP_REQUEST_FORWARD) {
252+
DEBUG ((
253+
DEBUG_ERROR,
254+
"RetrieveReqFwdMessage: Unexpected ServiceGroupId = 0x%x\n",
255+
pReqFwdResp->rpmi_resp.hdr.ServiceGroupId
256+
));
257+
return EFI_NO_RESPONSE;
258+
}
259+
260+
return EFI_SUCCESS;
261+
}
262+
67263
/**
68-
The entry point of Standalone MM Foundation.
264+
Delegated MM event loop for processing forwarded messages.
265+
266+
@param[in] CpuId Logical CPU ID handling the request.
267+
@param[in] ChannelId MPXY communication channel.
268+
@param[in] CompletionMessage Pointer to completion message structure.
269+
@param[in] CpuDriverEntryPoint Function pointer to invoke MM service handler.
270+
271+
TODO: Pass proper HartID
272+
**/
273+
STATIC
274+
VOID
275+
DelegatedEventLoop (
276+
IN UINTN CpuId,
277+
IN UINTN ChannelId,
278+
IN RPMI_SMM_MSG_CMPL_CMD *CompletionMessage
279+
)
280+
{
281+
EFI_STATUS Status;
282+
RPMI_SMM_MSG_COMM_ARGS ForwardedMsg;
283+
284+
Status = SendMMComplete (ChannelId, CompletionMessage);
285+
while (TRUE) {
286+
Status = RetrieveReqFwdMessage (ChannelId, &ForwardedMsg);
287+
if (EFI_ERROR (Status)) {
288+
DEBUG ((DEBUG_ERROR, "Req Fwd Command Failed"));
289+
}
69290

70-
@param [in] CpuId The Id assigned to this running CPU
71-
@param [in] PayloadInfoAddress The address of boot info
291+
// Add Handling of the incoming service request
292+
CompletionMessage->mm_resp.Status = EFI_ERROR (Status) ? RPMI_ERR_FAILED : RPMI_SUCCESS;
72293

294+
Status = SendMMComplete (ChannelId, CompletionMessage);
295+
if (EFI_ERROR (Status)) {
296+
DEBUG ((DEBUG_ERROR, "MM Complete Command Failed"));
297+
}
298+
}
299+
}
300+
301+
/**
302+
Main entry point to the Standalone MM Foundation on RISC-V platforms.
303+
304+
@param[in] CpuId Logical CPU ID.
305+
@param[in] PayloadInfoAddress Address of payload boot information passed by firmware.
73306
**/
74307
VOID
75308
EFIAPI
@@ -80,21 +313,35 @@ CModuleEntryPoint (
80313
{
81314
EFI_RISCV_SMM_PAYLOAD_INFO *BootInfo;
82315
VOID *HobStart;
316+
EFI_STATUS Status;
317+
RPMI_SMM_MSG_CMPL_CMD *CompletionMessage;
83318

84319
BootInfo = GetAndPrintBootinformation (PayloadInfoAddress);
85320
if (BootInfo == NULL) {
321+
DEBUG ((DEBUG_ERROR, "CModuleEntryPoint: Invalid boot info\n"));
86322
return;
87323
}
88324

89325
//
90326
// Create Hoblist based upon boot information passed by privileged software
91327
//
92-
HobStart = CreateHobListFromBootInfo (PayloadBootInfo);
328+
HobStart = CreateHobListFromBootInfo (BootInfo);
93329

94330
//
95331
// Call the MM Core entry point
96332
//
97333
ProcessModuleEntryPointList (HobStart);
98334

99-
ASSERT (0);
335+
CompletionMessage = AllocateZeroPool (sizeof (RPMI_SMM_MSG_CMPL_CMD));
336+
ASSERT (CompletionMessage != NULL);
337+
338+
// Ensure MPXY has been initialized for future communications
339+
if (EFI_ERROR (SbiMpxyInit ())) {
340+
CompletionMessage->mm_resp.Status = RPMI_ERR_FAILED;
341+
} else {
342+
CompletionMessage->mm_resp.Status = RPMI_SUCCESS;
343+
}
344+
345+
DelegatedEventLoop ((UINTN)CpuId, BootInfo->MpxyChannelId, CompletionMessage);
346+
ASSERT (FALSE);
100347
}

0 commit comments

Comments
 (0)