1 /** @file
2   RISC-V SEC phase module.
3 
4   Copyright (c) 2020, Hewlett Packard Enterprise Development LP. All rights reserved.<BR>
5 
6   SPDX-License-Identifier: BSD-2-Clause-Patent
7 
8 **/
9 
10 #include <SecMain.h>
11 #include <IndustryStandard/RiscVOpensbi.h>
12 #include <Library/DebugPrintErrorLevelLib.h>
13 #include <Library/PrintLib.h>
14 #include <Library/RiscVEdk2SbiLib.h>
15 #include <sbi/riscv_asm.h>
16 #include <sbi/riscv_atomic.h>
17 #include <sbi/sbi_console.h>  // Reference to header file in opensbi
18 #include <sbi/sbi_hart.h>     // Reference to header file in opensbi
19 #include <sbi/sbi_hartmask.h>    // Reference to header file in opensbi
20 #include <sbi/sbi_scratch.h>  // Reference to header file in opensbi
21 #include <sbi/sbi_platform.h> // Reference to header file in opensbi
22 #include <sbi/sbi_init.h>     // Reference to header file in opensbi
23 #include <sbi/sbi_ecall.h>    // Reference to header file in opensbi
24 
25 //
26 // Indicates the boot hart (PcdBootHartId) OpenSBI initialization is done.
27 //
28 atomic_t BootHartDone = ATOMIC_INITIALIZER(0);
29 atomic_t NonBootHartMessageLock = ATOMIC_INITIALIZER(0);
30 
31 typedef struct sbi_scratch *(*hartid2scratch)(ulong hartid, ulong hartindex);
32 
33 STATIC EFI_PEI_TEMPORARY_RAM_SUPPORT_PPI mTemporaryRamSupportPpi = {
34   TemporaryRamMigration
35 };
36 
37 STATIC EFI_PEI_TEMPORARY_RAM_DONE_PPI mTemporaryRamDonePpi = {
38   TemporaryRamDone
39 };
40 
41 STATIC EFI_PEI_PPI_DESCRIPTOR mPrivateDispatchTable[] = {
42   {
43     EFI_PEI_PPI_DESCRIPTOR_PPI,
44     &gEfiTemporaryRamSupportPpiGuid,
45     &mTemporaryRamSupportPpi
46   },
47   {
48     (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
49     &gEfiTemporaryRamDonePpiGuid,
50     &mTemporaryRamDonePpi
51   },
52 };
53 
54 /**
55   Locates a section within a series of sections
56   with the specified section type.
57 
58   The Instance parameter indicates which instance of the section
59   type to return. (0 is first instance, 1 is second...)
60 
61   @param[in]   Sections        The sections to search
62   @param[in]   SizeOfSections  Total size of all sections
63   @param[in]   SectionType     The section type to locate
64   @param[in]   Instance        The section instance number
65   @param[out]  FoundSection    The FFS section if found
66 
67   @retval EFI_SUCCESS           The file and section was found
68   @retval EFI_NOT_FOUND         The file and section was not found
69   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
70 
71 **/
72 EFI_STATUS
FindFfsSectionInstance(IN VOID * Sections,IN UINTN SizeOfSections,IN EFI_SECTION_TYPE SectionType,IN UINTN Instance,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)73 FindFfsSectionInstance (
74   IN  VOID                             *Sections,
75   IN  UINTN                            SizeOfSections,
76   IN  EFI_SECTION_TYPE                 SectionType,
77   IN  UINTN                            Instance,
78   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
79   )
80 {
81   EFI_PHYSICAL_ADDRESS        CurrentAddress;
82   UINT32                      Size;
83   EFI_PHYSICAL_ADDRESS        EndOfSections;
84   EFI_COMMON_SECTION_HEADER   *Section;
85   EFI_PHYSICAL_ADDRESS        EndOfSection;
86 
87   //
88   // Loop through the FFS file sections within the PEI Core FFS file
89   //
90   EndOfSection = (EFI_PHYSICAL_ADDRESS)(UINTN) Sections;
91   EndOfSections = EndOfSection + SizeOfSections;
92   for (;;) {
93     if (EndOfSection == EndOfSections) {
94       break;
95     }
96     CurrentAddress = (EndOfSection + 3) & ~(3ULL);
97     if (CurrentAddress >= EndOfSections) {
98       return EFI_VOLUME_CORRUPTED;
99     }
100 
101     Section = (EFI_COMMON_SECTION_HEADER*)(UINTN) CurrentAddress;
102 
103     Size = SECTION_SIZE (Section);
104     if (Size < sizeof (*Section)) {
105       return EFI_VOLUME_CORRUPTED;
106     }
107 
108     EndOfSection = CurrentAddress + Size;
109     if (EndOfSection > EndOfSections) {
110       return EFI_VOLUME_CORRUPTED;
111     }
112 
113     //
114     // Look for the requested section type
115     //
116     if (Section->Type == SectionType) {
117       if (Instance == 0) {
118         *FoundSection = Section;
119         return EFI_SUCCESS;
120       } else {
121         Instance--;
122       }
123     }
124   }
125 
126   return EFI_NOT_FOUND;
127 }
128 
129 /**
130   Locates a section within a series of sections
131   with the specified section type.
132 
133   @param[in]   Sections        The sections to search
134   @param[in]   SizeOfSections  Total size of all sections
135   @param[in]   SectionType     The section type to locate
136   @param[out]  FoundSection    The FFS section if found
137 
138   @retval EFI_SUCCESS           The file and section was found
139   @retval EFI_NOT_FOUND         The file and section was not found
140   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
141 
142 **/
143 EFI_STATUS
FindFfsSectionInSections(IN VOID * Sections,IN UINTN SizeOfSections,IN EFI_SECTION_TYPE SectionType,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)144 FindFfsSectionInSections (
145   IN  VOID                             *Sections,
146   IN  UINTN                            SizeOfSections,
147   IN  EFI_SECTION_TYPE                 SectionType,
148   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
149   )
150 {
151   return FindFfsSectionInstance (
152            Sections,
153            SizeOfSections,
154            SectionType,
155            0,
156            FoundSection
157            );
158 }
159 
160 /**
161   Locates a FFS file with the specified file type and a section
162   within that file with the specified section type.
163 
164   @param[in]   Fv            The firmware volume to search
165   @param[in]   FileType      The file type to locate
166   @param[in]   SectionType   The section type to locate
167   @param[out]  FoundSection  The FFS section if found
168 
169   @retval EFI_SUCCESS           The file and section was found
170   @retval EFI_NOT_FOUND         The file and section was not found
171   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
172 
173 **/
174 EFI_STATUS
FindFfsFileAndSection(IN EFI_FIRMWARE_VOLUME_HEADER * Fv,IN EFI_FV_FILETYPE FileType,IN EFI_SECTION_TYPE SectionType,OUT EFI_COMMON_SECTION_HEADER ** FoundSection)175 FindFfsFileAndSection (
176   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
177   IN  EFI_FV_FILETYPE                  FileType,
178   IN  EFI_SECTION_TYPE                 SectionType,
179   OUT EFI_COMMON_SECTION_HEADER        **FoundSection
180   )
181 {
182   EFI_STATUS                  Status;
183   EFI_PHYSICAL_ADDRESS        CurrentAddress;
184   EFI_PHYSICAL_ADDRESS        EndOfFirmwareVolume;
185   EFI_FFS_FILE_HEADER         *File;
186   UINT32                      Size;
187   EFI_PHYSICAL_ADDRESS        EndOfFile;
188 
189   if (Fv->Signature != EFI_FVH_SIGNATURE) {
190     DEBUG ((DEBUG_ERROR, "%a: FV at %p does not have FV header signature\n", __FUNCTION__, Fv));
191     return EFI_VOLUME_CORRUPTED;
192   }
193 
194   CurrentAddress = (EFI_PHYSICAL_ADDRESS)(UINTN) Fv;
195   EndOfFirmwareVolume = CurrentAddress + Fv->FvLength;
196 
197   //
198   // Loop through the FFS files in the Boot Firmware Volume
199   //
200   for (EndOfFile = CurrentAddress + Fv->HeaderLength; ; ) {
201 
202     CurrentAddress = (EndOfFile + 7) & ~(7ULL);
203     if (CurrentAddress > EndOfFirmwareVolume) {
204       return EFI_VOLUME_CORRUPTED;
205     }
206 
207     File = (EFI_FFS_FILE_HEADER*)(UINTN) CurrentAddress;
208     Size = *(UINT32*) File->Size & 0xffffff;
209     if (Size < (sizeof (*File) + sizeof (EFI_COMMON_SECTION_HEADER))) {
210       return EFI_VOLUME_CORRUPTED;
211     }
212 
213     EndOfFile = CurrentAddress + Size;
214     if (EndOfFile > EndOfFirmwareVolume) {
215       return EFI_VOLUME_CORRUPTED;
216     }
217 
218     //
219     // Look for the request file type
220     //
221     if (File->Type != FileType) {
222       continue;
223     }
224 
225     Status = FindFfsSectionInSections (
226                (VOID*) (File + 1),
227                (UINTN) EndOfFile - (UINTN) (File + 1),
228                SectionType,
229                FoundSection
230                );
231     if (!EFI_ERROR (Status) || (Status == EFI_VOLUME_CORRUPTED)) {
232       return Status;
233     }
234   }
235 }
236 
237 /**
238   Locates the PEI Core entry point address
239 
240   @param[in]  Fv                 The firmware volume to search
241   @param[out] PeiCoreEntryPoint  The entry point of the PEI Core image
242 
243   @retval EFI_SUCCESS           The file and section was found
244   @retval EFI_NOT_FOUND         The file and section was not found
245   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
246 
247 **/
248 EFI_STATUS
FindPeiCoreImageBaseInFv(IN EFI_FIRMWARE_VOLUME_HEADER * Fv,OUT EFI_PHYSICAL_ADDRESS * PeiCoreImageBase)249 FindPeiCoreImageBaseInFv (
250   IN  EFI_FIRMWARE_VOLUME_HEADER       *Fv,
251   OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
252   )
253 {
254   EFI_STATUS                  Status;
255   EFI_COMMON_SECTION_HEADER   *Section;
256 
257   Status = FindFfsFileAndSection (
258              Fv,
259              EFI_FV_FILETYPE_PEI_CORE,
260              EFI_SECTION_PE32,
261              &Section
262              );
263   if (EFI_ERROR (Status)) {
264     Status = FindFfsFileAndSection (
265                Fv,
266                EFI_FV_FILETYPE_PEI_CORE,
267                EFI_SECTION_TE,
268                &Section
269                );
270     if (EFI_ERROR (Status)) {
271       DEBUG ((DEBUG_ERROR, "%a: Unable to find PEI Core image\n", __FUNCTION__));
272       return Status;
273     }
274   }
275   DEBUG ((DEBUG_INFO, "%a: PeiCoreImageBase found\n", __FUNCTION__));
276   *PeiCoreImageBase = (EFI_PHYSICAL_ADDRESS)(UINTN)(Section + 1);
277   return EFI_SUCCESS;
278 }
279 
280 /**
281   Locates the PEI Core entry point address
282 
283   @param[in,out]  Fv                 The firmware volume to search
284   @param[out]     PeiCoreEntryPoint  The entry point of the PEI Core image
285 
286   @retval EFI_SUCCESS           The file and section was found
287   @retval EFI_NOT_FOUND         The file and section was not found
288   @retval EFI_VOLUME_CORRUPTED  The firmware volume was corrupted
289 
290 **/
291 VOID
FindPeiCoreImageBase(IN OUT EFI_FIRMWARE_VOLUME_HEADER ** BootFv,OUT EFI_PHYSICAL_ADDRESS * PeiCoreImageBase)292 FindPeiCoreImageBase (
293   IN OUT  EFI_FIRMWARE_VOLUME_HEADER       **BootFv,
294      OUT  EFI_PHYSICAL_ADDRESS             *PeiCoreImageBase
295   )
296 {
297   *PeiCoreImageBase = 0;
298 
299   DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__));
300   FindPeiCoreImageBaseInFv (*BootFv, PeiCoreImageBase);
301 }
302 
303 /*
304   Find and return Pei Core entry point.
305 
306   It also find SEC and PEI Core file debug inforamtion. It will report them if
307   remote debug is enabled.
308 
309 **/
310 VOID
FindAndReportEntryPoints(IN EFI_FIRMWARE_VOLUME_HEADER ** BootFirmwareVolumePtr,OUT EFI_PEI_CORE_ENTRY_POINT * PeiCoreEntryPoint)311 FindAndReportEntryPoints (
312   IN  EFI_FIRMWARE_VOLUME_HEADER       **BootFirmwareVolumePtr,
313   OUT EFI_PEI_CORE_ENTRY_POINT         *PeiCoreEntryPoint
314   )
315 {
316   EFI_STATUS                       Status;
317   EFI_PHYSICAL_ADDRESS             PeiCoreImageBase;
318 
319   DEBUG ((DEBUG_INFO, "%a: Entry\n", __FUNCTION__));
320 
321   FindPeiCoreImageBase (BootFirmwareVolumePtr, &PeiCoreImageBase);
322   //
323   // Find PEI Core entry point
324   //
325   Status = PeCoffLoaderGetEntryPoint ((VOID *) (UINTN) PeiCoreImageBase, (VOID**) PeiCoreEntryPoint);
326   if (EFI_ERROR(Status)) {
327     *PeiCoreEntryPoint = 0;
328   }
329   DEBUG ((DEBUG_INFO, "%a: PeCoffLoaderGetEntryPoint success: %x\n", __FUNCTION__, *PeiCoreEntryPoint));
330 
331   return;
332 }
333 /*
334   Print out the content of firmware context.
335 
336 **/
337 VOID
DebutPrintFirmwareContext(EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT * FirmwareContext)338 DebutPrintFirmwareContext (
339     EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT *FirmwareContext
340     )
341 {
342   DEBUG ((DEBUG_INFO, "%a: OpenSBI Firmware Context at 0x%x\n", __FUNCTION__, FirmwareContext));
343   DEBUG ((DEBUG_INFO, "%a:              PEI Service at 0x%x\n\n", __FUNCTION__, FirmwareContext->PeiServiceTable));
344 }
345 /** Temporary RAM migration function.
346 
347   This function migrates the data from temporary RAM to permanent
348   memory.
349 
350   @param[in]  PeiServices           PEI service
351   @param[in]  TemporaryMemoryBase   Temporary memory base address
352   @param[in]  PermanentMemoryBase   Permanent memory base address
353   @param[in]  CopySize              Size to copy
354 
355 **/
356 EFI_STATUS
357 EFIAPI
TemporaryRamMigration(IN CONST EFI_PEI_SERVICES ** PeiServices,IN EFI_PHYSICAL_ADDRESS TemporaryMemoryBase,IN EFI_PHYSICAL_ADDRESS PermanentMemoryBase,IN UINTN CopySize)358 TemporaryRamMigration (
359   IN CONST EFI_PEI_SERVICES   **PeiServices,
360   IN EFI_PHYSICAL_ADDRESS     TemporaryMemoryBase,
361   IN EFI_PHYSICAL_ADDRESS     PermanentMemoryBase,
362   IN UINTN                    CopySize
363   )
364 {
365   VOID      *OldHeap;
366   VOID      *NewHeap;
367   VOID      *OldStack;
368   VOID      *NewStack;
369   EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT *FirmwareContext;
370 
371   DEBUG ((DEBUG_INFO,
372     "%a: Temp Mem Base:0x%Lx, Permanent Mem Base:0x%Lx, CopySize:0x%Lx\n",
373     __FUNCTION__,
374     TemporaryMemoryBase,
375     PermanentMemoryBase,
376     (UINT64)CopySize
377     ));
378 
379   OldHeap = (VOID*)(UINTN)TemporaryMemoryBase;
380   NewHeap = (VOID*)((UINTN)PermanentMemoryBase + (CopySize >> 1));
381 
382   OldStack = (VOID*)((UINTN)TemporaryMemoryBase + (CopySize >> 1));
383   NewStack = (VOID*)(UINTN)PermanentMemoryBase;
384 
385   CopyMem (NewHeap, OldHeap, CopySize >> 1);   // Migrate Heap
386   CopyMem (NewStack, OldStack, CopySize >> 1); // Migrate Stack
387 
388   //
389   // Reset firmware context pointer
390   //
391   SbiGetFirmwareContext (&FirmwareContext);
392   FirmwareContext = (VOID *)FirmwareContext + (unsigned long)((UINTN)NewStack - (UINTN)OldStack);
393   SbiSetFirmwareContext (FirmwareContext);
394 
395   //
396   // Relocate PEI Service **
397   //
398   FirmwareContext->PeiServiceTable += (unsigned long)((UINTN)NewStack - (UINTN)OldStack);
399   DEBUG ((DEBUG_INFO, "%a: OpenSBI Firmware Context is relocated to 0x%x\n", __FUNCTION__, FirmwareContext));
400   DebutPrintFirmwareContext ((EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT *)FirmwareContext);
401 
402   register uintptr_t a0 asm ("a0") = (uintptr_t)((UINTN)NewStack - (UINTN)OldStack);
403   asm volatile ("add sp, sp, a0"::"r"(a0):);
404   return EFI_SUCCESS;
405 }
406 
407 /** Temprary RAM done function.
408 
409 **/
TemporaryRamDone(VOID)410 EFI_STATUS EFIAPI TemporaryRamDone (
411   VOID
412   )
413 {
414   DEBUG ((DEBUG_INFO, "%a: 2nd time PEI core, temporary ram done.\n", __FUNCTION__));
415   return EFI_SUCCESS;
416 }
417 
418 /**
419   Handles SBI calls of EDK2's SBI FW extension.
420 
421   The return value is the error code returned by the SBI call.
422 
423   @param[in]  ExtId        The extension ID of the FW extension.
424   @param[in]  FuncId       The called function ID.
425   @param[in]  Args         The args to the function.
426   @param[out] OutVal       The value the function returns to the caller.
427   @param[out] OutTrap      Trap info for trapping further, see OpenSBI code.
428                            Is ignored if return value is not SBI_ETRAP.
429 
430   @retval SBI_OK           If the handler succeeds.
431   @retval SBI_ENOTSUPP     If there's no function with the given ID.
432   @retval SBI_ETRAP        If the called SBI functions wants to trap further.
433 **/
SbiEcallFirmwareHandler(IN unsigned long ExtId,IN unsigned long FuncId,IN unsigned long * Args,OUT unsigned long * OutVal,OUT struct sbi_trap_info * OutTrap)434 STATIC int SbiEcallFirmwareHandler (
435   IN  unsigned long         ExtId,
436   IN  unsigned long         FuncId,
437   IN  unsigned long        *Args,
438   OUT unsigned long        *OutVal,
439   OUT struct sbi_trap_info *OutTrap
440   )
441 {
442   int Ret = SBI_OK;
443 
444   switch (FuncId) {
445     case SBI_EXT_FW_MSCRATCH_FUNC:
446       *OutVal = (unsigned long) sbi_scratch_thishart_ptr();
447       break;
448     case SBI_EXT_FW_MSCRATCH_HARTID_FUNC:
449       *OutVal = (unsigned long) sbi_hartid_to_scratch (Args[0]);
450       break;
451     default:
452       Ret = SBI_ENOTSUPP;
453       DEBUG ((DEBUG_ERROR, "%a: Called SBI firmware ecall with invalid function ID\n", __FUNCTION__));
454       ASSERT (FALSE);
455   };
456 
457   return Ret;
458 }
459 
460 struct sbi_ecall_extension FirmwareEcall = {
461   .extid_start = SBI_EDK2_FW_EXT,
462   .extid_end = SBI_EDK2_FW_EXT,
463   .handle = SbiEcallFirmwareHandler,
464 };
465 
466 /** Register EDK2's SBI extension with OpenSBI
467 
468   This function returns EFI_STATUS, even though it only ever returns
469   EFI_SUCCESS. On error it ASSERTs. Looking at OpenSBI code it appears that
470   registering an extension can only fail if the extension ID is invalid or was
471   already registered. Failure is therefore an error of the programmer.
472 
473   @retval EFI_SUCCESS If the extension was successfully registered.
474 **/
475 EFI_STATUS
476 EFIAPI
RegisterFirmwareSbiExtension(VOID)477 RegisterFirmwareSbiExtension (
478   VOID
479   )
480 {
481   UINTN Ret;
482   Ret = sbi_ecall_register_extension(&FirmwareEcall);
483   if (Ret) {
484     //
485     // Only fails if the extension ID is invalid or already is registered.
486     //
487     DEBUG ((DEBUG_ERROR, "Failed to register SBI Firmware Extension for EDK2\n"));
488     ASSERT(FALSE);
489   }
490 
491   return EFI_SUCCESS;
492 }
493 /** Transion from SEC phase to PEI phase.
494 
495   This function transits to S-mode PEI phase from M-mode SEC phase.
496 
497   @param[in]  BootHartId     Hardware thread ID of boot hart.
498   @param[in]  FuncArg1       Arg1 delivered from previous phase.
499 
500 **/
PeiCore(IN UINTN BootHartId,IN UINTN FuncArg1)501 VOID EFIAPI PeiCore (
502   IN  UINTN  BootHartId,
503   IN  UINTN  FuncArg1
504   )
505 {
506   EFI_SEC_PEI_HAND_OFF        SecCoreData;
507   EFI_PEI_CORE_ENTRY_POINT    PeiCoreEntryPoint;
508   EFI_FIRMWARE_VOLUME_HEADER *BootFv = (EFI_FIRMWARE_VOLUME_HEADER *)FixedPcdGet32(PcdRiscVPeiFvBase);
509   EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT FirmwareContext;
510   struct sbi_scratch         *ScratchSpace;
511   struct sbi_platform        *ThisSbiPlatform;
512   UINT32 HartId;
513 
514   FindAndReportEntryPoints (&BootFv, &PeiCoreEntryPoint);
515 
516   SecCoreData.DataSize               = sizeof(EFI_SEC_PEI_HAND_OFF);
517   SecCoreData.BootFirmwareVolumeBase = BootFv;
518   SecCoreData.BootFirmwareVolumeSize = (UINTN) BootFv->FvLength;
519   SecCoreData.TemporaryRamBase       = (VOID*)(UINT64) FixedPcdGet32(PcdTemporaryRamBase);
520   SecCoreData.TemporaryRamSize       = (UINTN)  FixedPcdGet32(PcdTemporaryRamSize);
521   SecCoreData.PeiTemporaryRamBase    = SecCoreData.TemporaryRamBase;
522   SecCoreData.PeiTemporaryRamSize    = SecCoreData.TemporaryRamSize >> 1;
523   SecCoreData.StackBase              = (UINT8 *)SecCoreData.TemporaryRamBase + (SecCoreData.TemporaryRamSize >> 1);
524   SecCoreData.StackSize              = SecCoreData.TemporaryRamSize >> 1;
525 
526   //
527   // Print out scratch address of each hart
528   //
529   DEBUG ((DEBUG_INFO, "%a: OpenSBI scratch address for each hart:\n", __FUNCTION__));
530   for (HartId = 0; HartId < SBI_HARTMASK_MAX_BITS; HartId ++) {
531     SbiGetMscratchHartid (HartId, &ScratchSpace);
532     if(ScratchSpace != NULL) {
533       DEBUG((DEBUG_INFO, "          Hart %d: 0x%x\n", HartId, ScratchSpace));
534     }
535   }
536 
537   //
538   // Set up OpepSBI firmware context pointer on boot hart OpenSbi scratch.
539   // Firmware context residents in stack and will be switched to memory when
540   // temporary RAM migration.
541   //
542   SbiGetMscratchHartid (BootHartId, &ScratchSpace);
543   ZeroMem ((VOID *)&FirmwareContext, sizeof (EFI_RISCV_OPENSBI_FIRMWARE_CONTEXT));
544   ThisSbiPlatform = (struct sbi_platform *)sbi_platform_ptr(ScratchSpace);
545   if (ThisSbiPlatform->opensbi_version > OPENSBI_VERSION) {
546       DEBUG ((DEBUG_ERROR, "%a: OpenSBI platform table version 0x%x is newer than OpenSBI version 0x%x.\n"
547                            "There maybe be some backward compatable issues.\n",
548               __FUNCTION__,
549              ThisSbiPlatform->opensbi_version,
550              OPENSBI_VERSION
551              ));
552       ASSERT(FALSE);
553   }
554   DEBUG ((DEBUG_INFO, "%a: OpenSBI platform table at address: 0x%x\nFirmware Context is located at 0x%x\n",
555              __FUNCTION__,
556              ThisSbiPlatform,
557              &FirmwareContext
558              ));
559   ThisSbiPlatform->firmware_context = (unsigned long)&FirmwareContext;
560   //
561   // Set firmware context Hart-specific pointer
562   //
563   for (HartId = 0; HartId < SBI_HARTMASK_MAX_BITS; HartId ++) {
564     SbiGetMscratchHartid (HartId, &ScratchSpace);
565     if (ScratchSpace != NULL) {
566       FirmwareContext.HartSpecific[HartId] =
567         (EFI_RISCV_FIRMWARE_CONTEXT_HART_SPECIFIC *)((UINT8 *)ScratchSpace - FIRMWARE_CONTEXT_HART_SPECIFIC_SIZE);
568         DEBUG ((DEBUG_INFO, "%a: OpenSBI Hart %d Firmware Context Hart-specific at address: 0x%x\n",
569                 __FUNCTION__,
570                  HartId,
571                  FirmwareContext.HartSpecific [HartId]
572                  ));
573     }
574   }
575   //
576   // Set supervisor translation mode to Bare mode
577   //
578   DEBUG ((DEBUG_INFO, "%a: Set Supervisor address mode to Bare-mode.\n", __FUNCTION__));
579   RiscVSetSupervisorAddressTranslationRegister ((UINT64)RISCV_SATP_MODE_OFF << RISCV_SATP_MODE_BIT_POSITION);
580 
581   //
582   // Transfer the control to the PEI core
583   //
584   (*PeiCoreEntryPoint) (&SecCoreData, (EFI_PEI_PPI_DESCRIPTOR *)&mPrivateDispatchTable);
585 }
586 
587 /**
588   Register firmware SBI extension and launch PeiCore to the mode specified in
589   PcdPeiCorePrivilegeMode;
590 
591   To register the SBI extension we stay in M-Mode and then transition here,
592   rather than before in sbi_init.
593 
594   @param[in]  ThisHartId     Hardware thread ID.
595   @param[in]  FuncArg1       Arg1 delivered from previous phase.
596 
597 **/
598 VOID
599 EFIAPI
LaunchPeiCore(IN UINTN ThisHartId,IN UINTN FuncArg1)600 LaunchPeiCore (
601   IN  UINTN  ThisHartId,
602   IN  UINTN  FuncArg1
603   )
604 {
605   UINT32 PeiCoreMode;
606 
607   DEBUG ((DEBUG_INFO, "%a: Set boot hart done.\n", __FUNCTION__));
608   atomic_write (&BootHartDone, (UINT64)TRUE);
609   RegisterFirmwareSbiExtension ();
610 
611   PeiCoreMode = FixedPcdGet32 (PcdPeiCorePrivilegeMode);
612   if (PeiCoreMode == PRV_S) {
613     DEBUG ((DEBUG_INFO, "%a: Switch to S-Mode for PeiCore.\n", __FUNCTION__));
614     sbi_hart_switch_mode (ThisHartId, FuncArg1, (UINTN)PeiCore, PRV_S, FALSE);
615   } else if (PeiCoreMode == PRV_M) {
616     DEBUG ((DEBUG_INFO, "%a: Switch to M-Mode for PeiCore.\n", __FUNCTION__));
617     PeiCore (ThisHartId, FuncArg1);
618   } else {
619     DEBUG ((DEBUG_INFO, "%a: The privilege mode specified in PcdPeiCorePrivilegeMode is not supported.\n", __FUNCTION__));
620     while (TRUE);
621   }
622 }
623 
624 /**
625   Interface to invoke internal mode switch function.
626 
627   To register the SBI extension we stay in M-Mode and then transition here,
628   rather than before in sbi_init.
629 
630   @param[in]  FuncArg0       Arg0 to pass to next phase entry point address.
631   @param[in]  FuncArg1       Arg1 to pass to next phase entry point address.
632   @param[in]  NextAddr       Entry point of next phase.
633   @param[in]  NextMode       Privilege mode of next phase.
634   @param[in]  NextVirt       Next phase is in virtualiztion.
635 
636 **/
637 VOID
638 EFIAPI
RiscVOpenSbiHartSwitchMode(IN UINTN FuncArg0,IN UINTN FuncArg1,IN UINTN NextAddr,IN UINTN NextMode,IN BOOLEAN NextVirt)639 RiscVOpenSbiHartSwitchMode (
640   IN  UINTN   FuncArg0,
641   IN  UINTN   FuncArg1,
642   IN  UINTN   NextAddr,
643   IN  UINTN   NextMode,
644   IN  BOOLEAN NextVirt
645   )
646 {
647   sbi_hart_switch_mode(FuncArg0, FuncArg1, NextAddr, NextMode, NextVirt);
648 }
649 
650 /**
651   This function initilizes hart specific information and SBI.
652   For the boot hart, it boots system through PEI core and initial SBI in the DXE IPL.
653   For others, it goes to initial SBI and halt.
654 
655   the lay out of memory region for each hart is as below delineates,
656 
657                                                _                                        ____
658   |----Scratch ends                             |                                           |
659   |                                             | sizeof (sbi_scratch)                      |
660   |                                            _|                                           |
661   |----Scratch buffer starts                   <----- *Scratch                              |
662   |----Firmware Context Hart-specific ends     _                                            |
663   |                                             |                                           |
664   |                                             | FIRMWARE_CONTEXT_HART_SPECIFIC_SIZE       |
665   |                                             |                                           |  PcdOpenSbiStackSize
666   |                                            _|                                           |
667   |----Firmware Context Hart-specific starts   <----- **HartFirmwareContext                 |
668   |----Hart stack top                          _                                            |
669   |                                             |                                           |
670   |                                             |                                           |
671   |                                             |  Stack                                    |
672   |                                             |                                           |
673   |                                            _|                                       ____|
674   |----Hart stack bottom
675 
676   @param[in]  HartId          Hardware thread ID.
677   @param[in]  Scratch         Pointer to sbi_scratch structure.
678 
679 **/
SecCoreStartUpWithStack(IN UINTN HartId,IN struct sbi_scratch * Scratch)680 VOID EFIAPI SecCoreStartUpWithStack(
681   IN  UINTN HartId,
682   IN  struct sbi_scratch *Scratch
683   )
684 {
685   UINT64 BootHartDoneSbiInit;
686   UINT64 NonBootHartMessageLockValue;
687   EFI_RISCV_FIRMWARE_CONTEXT_HART_SPECIFIC *HartFirmwareContext;
688 
689   //
690   // Setup EFI_RISCV_FIRMWARE_CONTEXT_HART_SPECIFIC for each hart.
691   //
692   HartFirmwareContext = (EFI_RISCV_FIRMWARE_CONTEXT_HART_SPECIFIC *)((UINT8 *)Scratch - FIRMWARE_CONTEXT_HART_SPECIFIC_SIZE);
693   HartFirmwareContext->IsaExtensionSupported = RiscVReadMachineIsa ();
694   HartFirmwareContext->MachineVendorId.Value64_L = RiscVReadMachineVendorId ();
695   HartFirmwareContext->MachineVendorId.Value64_H = 0;
696   HartFirmwareContext->MachineArchId.Value64_L = RiscVReadMachineArchitectureId ();
697   HartFirmwareContext->MachineArchId.Value64_H = 0;
698   HartFirmwareContext->MachineImplId.Value64_L = RiscVReadMachineImplementId ();
699   HartFirmwareContext->MachineImplId.Value64_H = 0;
700   HartFirmwareContext->HartSwitchMode = RiscVOpenSbiHartSwitchMode;
701 
702   if (HartId == FixedPcdGet32(PcdBootHartId)) {
703     Scratch->next_addr = (UINTN)LaunchPeiCore;
704     Scratch->next_mode = PRV_M;
705     DEBUG ((DEBUG_INFO, "%a: Initializing OpenSBI library for booting hart %d\n", __FUNCTION__, HartId));
706     sbi_init(Scratch);
707   }
708 
709   //
710   // Initialize the non boot harts
711   //
712   do {
713     BootHartDoneSbiInit = atomic_read (&BootHartDone);
714     //
715     // Below leave some memory cycles to boot hart
716     // for updating BootHartDone.
717     //
718     CpuPause ();
719     CpuPause ();
720     CpuPause ();
721   } while (BootHartDoneSbiInit != (UINT64)TRUE);
722 
723   NonBootHartMessageLockValue = atomic_xchg(&NonBootHartMessageLock, TRUE);
724   while (NonBootHartMessageLockValue == TRUE) {
725     CpuPause ();
726     CpuPause ();
727     CpuPause ();
728     NonBootHartMessageLockValue = atomic_xchg(&NonBootHartMessageLock, TRUE);
729   };
730   DEBUG((DEBUG_INFO, "%a: Non boot hart %d initialization.\n", __FUNCTION__, HartId));
731   NonBootHartMessageLockValue = atomic_xchg(&NonBootHartMessageLock, FALSE);
732   //
733   // Non boot hart wiil be halted waiting for SBI_HART_STARTING.
734   // Use HSM ecall to start non boot hart (SBI_EXT_HSM_HART_START) later on,
735   //
736   sbi_init(Scratch);
737 }
738 
739