@@ -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**/
74307VOID
75308EFIAPI
@@ -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