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