]> git.proxmox.com Git - mirror_edk2.git/blob - MdeModulePkg/Core/PiSmmCore/Dispatcher.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / MdeModulePkg / Core / PiSmmCore / Dispatcher.c
1 /** @file
2 SMM Driver Dispatcher.
3
4 Step #1 - When a FV protocol is added to the system every driver in the FV
5 is added to the mDiscoveredList. The Before, and After Depex are
6 pre-processed as drivers are added to the mDiscoveredList. If an Apriori
7 file exists in the FV those drivers are addeded to the
8 mScheduledQueue. The mFvHandleList is used to make sure a
9 FV is only processed once.
10
11 Step #2 - Dispatch. Remove driver from the mScheduledQueue and load and
12 start it. After mScheduledQueue is drained check the
13 mDiscoveredList to see if any item has a Depex that is ready to
14 be placed on the mScheduledQueue.
15
16 Step #3 - Adding to the mScheduledQueue requires that you process Before
17 and After dependencies. This is done recursively as the call to add
18 to the mScheduledQueue checks for Before and recursively adds
19 all Befores. It then addes the item that was passed in and then
20 processes the After dependencies by recursively calling the routine.
21
22 Dispatcher Rules:
23 The rules for the dispatcher are similar to the DXE dispatcher.
24
25 The rules for DXE dispatcher are in chapter 10 of the DXE CIS. Figure 10-3
26 is the state diagram for the DXE dispatcher
27
28 Depex - Dependency Expression.
29
30 Copyright (c) 2014, Hewlett-Packard Development Company, L.P.
31 Copyright (c) 2009 - 2018, Intel Corporation. All rights reserved.<BR>
32 SPDX-License-Identifier: BSD-2-Clause-Patent
33
34 **/
35
36 #include "PiSmmCore.h"
37
38 //
39 // SMM Dispatcher Data structures
40 //
41 #define KNOWN_HANDLE_SIGNATURE SIGNATURE_32('k','n','o','w')
42 typedef struct {
43 UINTN Signature;
44 LIST_ENTRY Link; // mFvHandleList
45 EFI_HANDLE Handle;
46 } KNOWN_HANDLE;
47
48 //
49 // Function Prototypes
50 //
51
52 /**
53 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
54 must add any driver with a before dependency on InsertedDriverEntry first.
55 You do this by recursively calling this routine. After all the Befores are
56 processed you can add InsertedDriverEntry to the mScheduledQueue.
57 Then you can add any driver with an After dependency on InsertedDriverEntry
58 by recursively calling this routine.
59
60 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
61
62 **/
63 VOID
64 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
65 IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry
66 );
67
68 //
69 // The Driver List contains one copy of every driver that has been discovered.
70 // Items are never removed from the driver list. List of EFI_SMM_DRIVER_ENTRY
71 //
72 LIST_ENTRY mDiscoveredList = INITIALIZE_LIST_HEAD_VARIABLE (mDiscoveredList);
73
74 //
75 // Queue of drivers that are ready to dispatch. This queue is a subset of the
76 // mDiscoveredList.list of EFI_SMM_DRIVER_ENTRY.
77 //
78 LIST_ENTRY mScheduledQueue = INITIALIZE_LIST_HEAD_VARIABLE (mScheduledQueue);
79
80 //
81 // List of handles who's Fv's have been parsed and added to the mFwDriverList.
82 //
83 LIST_ENTRY mFvHandleList = INITIALIZE_LIST_HEAD_VARIABLE (mFvHandleList);
84
85 //
86 // Flag for the SMM Dispatcher. TRUE if dispatcher is executing.
87 //
88 BOOLEAN gDispatcherRunning = FALSE;
89
90 //
91 // Flag for the SMM Dispatcher. TRUE if there is one or more SMM drivers ready to be dispatched
92 //
93 BOOLEAN gRequestDispatch = FALSE;
94
95 //
96 // List of file types supported by dispatcher
97 //
98 EFI_FV_FILETYPE mSmmFileTypes[] = {
99 EFI_FV_FILETYPE_SMM,
100 EFI_FV_FILETYPE_COMBINED_SMM_DXE,
101 EFI_FV_FILETYPE_SMM_CORE,
102 //
103 // Note: DXE core will process the FV image file, so skip it in SMM core
104 // EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE
105 //
106 };
107
108 typedef struct {
109 MEDIA_FW_VOL_FILEPATH_DEVICE_PATH File;
110 EFI_DEVICE_PATH_PROTOCOL End;
111 } FV_FILEPATH_DEVICE_PATH;
112
113 FV_FILEPATH_DEVICE_PATH mFvDevicePath;
114
115 //
116 // DXE Architecture Protocols
117 //
118 EFI_SECURITY_ARCH_PROTOCOL *mSecurity = NULL;
119 EFI_SECURITY2_ARCH_PROTOCOL *mSecurity2 = NULL;
120
121 //
122 // The global variable is defined for Loading modules at fixed address feature to track the SMM code
123 // memory range usage. It is a bit mapped array in which every bit indicates the corresponding
124 // memory page available or not.
125 //
126 GLOBAL_REMOVE_IF_UNREFERENCED UINT64 *mSmmCodeMemoryRangeUsageBitMap = NULL;
127
128 /**
129 To check memory usage bit map array to figure out if the memory range in which the image will be loaded is available or not. If
130 memory range is available, the function will mark the corresponding bits to 1 which indicates the memory range is used.
131 The function is only invoked when load modules at fixed address feature is enabled.
132
133 @param ImageBase The base address the image will be loaded at.
134 @param ImageSize The size of the image
135
136 @retval EFI_SUCCESS The memory range the image will be loaded in is available
137 @retval EFI_NOT_FOUND The memory range the image will be loaded in is not available
138 **/
139 EFI_STATUS
140 CheckAndMarkFixLoadingMemoryUsageBitMap (
141 IN EFI_PHYSICAL_ADDRESS ImageBase,
142 IN UINTN ImageSize
143 )
144 {
145 UINT32 SmmCodePageNumber;
146 UINT64 SmmCodeSize;
147 EFI_PHYSICAL_ADDRESS SmmCodeBase;
148 UINTN BaseOffsetPageNumber;
149 UINTN TopOffsetPageNumber;
150 UINTN Index;
151
152 //
153 // Build tool will calculate the smm code size and then patch the PcdLoadFixAddressSmmCodePageNumber
154 //
155 SmmCodePageNumber = PcdGet32 (PcdLoadFixAddressSmmCodePageNumber);
156 SmmCodeSize = EFI_PAGES_TO_SIZE (SmmCodePageNumber);
157 SmmCodeBase = gLoadModuleAtFixAddressSmramBase;
158
159 //
160 // If the memory usage bit map is not initialized, do it. Every bit in the array
161 // indicate the status of the corresponding memory page, available or not
162 //
163 if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
164 mSmmCodeMemoryRangeUsageBitMap = AllocateZeroPool (((SmmCodePageNumber / 64) + 1)*sizeof (UINT64));
165 }
166
167 //
168 // If the Dxe code memory range is not allocated or the bit map array allocation failed, return EFI_NOT_FOUND
169 //
170 if (mSmmCodeMemoryRangeUsageBitMap == NULL) {
171 return EFI_NOT_FOUND;
172 }
173
174 //
175 // see if the memory range for loading the image is in the SMM code range.
176 //
177 if ((SmmCodeBase + SmmCodeSize < ImageBase + ImageSize) || (SmmCodeBase > ImageBase)) {
178 return EFI_NOT_FOUND;
179 }
180
181 //
182 // Test if the memory is available or not.
183 //
184 BaseOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase - SmmCodeBase));
185 TopOffsetPageNumber = EFI_SIZE_TO_PAGES ((UINT32)(ImageBase + ImageSize - SmmCodeBase));
186 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
187 if ((mSmmCodeMemoryRangeUsageBitMap[Index / 64] & LShiftU64 (1, (Index % 64))) != 0) {
188 //
189 // This page is already used.
190 //
191 return EFI_NOT_FOUND;
192 }
193 }
194
195 //
196 // Being here means the memory range is available. So mark the bits for the memory range
197 //
198 for (Index = BaseOffsetPageNumber; Index < TopOffsetPageNumber; Index++) {
199 mSmmCodeMemoryRangeUsageBitMap[Index / 64] |= LShiftU64 (1, (Index % 64));
200 }
201
202 return EFI_SUCCESS;
203 }
204
205 /**
206 Get the fixed loading address from image header assigned by build tool. This function only be called
207 when Loading module at Fixed address feature enabled.
208
209 @param ImageContext Pointer to the image context structure that describes the PE/COFF
210 image that needs to be examined by this function.
211 @retval EFI_SUCCESS An fixed loading address is assigned to this image by build tools .
212 @retval EFI_NOT_FOUND The image has no assigned fixed loading address.
213
214 **/
215 EFI_STATUS
216 GetPeCoffImageFixLoadingAssignedAddress (
217 IN OUT PE_COFF_LOADER_IMAGE_CONTEXT *ImageContext
218 )
219 {
220 UINTN SectionHeaderOffset;
221 EFI_STATUS Status;
222 EFI_IMAGE_SECTION_HEADER SectionHeader;
223 EFI_IMAGE_OPTIONAL_HEADER_UNION *ImgHdr;
224 EFI_PHYSICAL_ADDRESS FixLoadingAddress;
225 UINT16 Index;
226 UINTN Size;
227 UINT16 NumberOfSections;
228 UINT64 ValueInSectionHeader;
229
230 FixLoadingAddress = 0;
231 Status = EFI_NOT_FOUND;
232
233 //
234 // Get PeHeader pointer
235 //
236 ImgHdr = (EFI_IMAGE_OPTIONAL_HEADER_UNION *)((CHAR8 *)ImageContext->Handle + ImageContext->PeCoffHeaderOffset);
237 SectionHeaderOffset = ImageContext->PeCoffHeaderOffset +
238 sizeof (UINT32) +
239 sizeof (EFI_IMAGE_FILE_HEADER) +
240 ImgHdr->Pe32.FileHeader.SizeOfOptionalHeader;
241 NumberOfSections = ImgHdr->Pe32.FileHeader.NumberOfSections;
242
243 //
244 // Get base address from the first section header that doesn't point to code section.
245 //
246 for (Index = 0; Index < NumberOfSections; Index++) {
247 //
248 // Read section header from file
249 //
250 Size = sizeof (EFI_IMAGE_SECTION_HEADER);
251 Status = ImageContext->ImageRead (
252 ImageContext->Handle,
253 SectionHeaderOffset,
254 &Size,
255 &SectionHeader
256 );
257 if (EFI_ERROR (Status)) {
258 return Status;
259 }
260
261 Status = EFI_NOT_FOUND;
262
263 if ((SectionHeader.Characteristics & EFI_IMAGE_SCN_CNT_CODE) == 0) {
264 //
265 // Build tool will save the address in PointerToRelocations & PointerToLineNumbers fields in the first section header
266 // that doesn't point to code section in image header.So there is an assumption that when the feature is enabled,
267 // if a module with a loading address assigned by tools, the PointerToRelocations & PointerToLineNumbers fields
268 // should not be Zero, or else, these 2 fields should be set to Zero
269 //
270 ValueInSectionHeader = ReadUnaligned64 ((UINT64 *)&SectionHeader.PointerToRelocations);
271 if (ValueInSectionHeader != 0) {
272 //
273 // Found first section header that doesn't point to code section in which build tool saves the
274 // offset to SMRAM base as image base in PointerToRelocations & PointerToLineNumbers fields
275 //
276 FixLoadingAddress = (EFI_PHYSICAL_ADDRESS)(gLoadModuleAtFixAddressSmramBase + (INT64)ValueInSectionHeader);
277 //
278 // Check if the memory range is available.
279 //
280 Status = CheckAndMarkFixLoadingMemoryUsageBitMap (FixLoadingAddress, (UINTN)(ImageContext->ImageSize + ImageContext->SectionAlignment));
281 if (!EFI_ERROR (Status)) {
282 //
283 // The assigned address is valid. Return the specified loading address
284 //
285 ImageContext->ImageAddress = FixLoadingAddress;
286 }
287 }
288
289 break;
290 }
291
292 SectionHeaderOffset += sizeof (EFI_IMAGE_SECTION_HEADER);
293 }
294
295 DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED INFO: Loading module at fixed address %x, Status = %r\n", FixLoadingAddress, Status));
296 return Status;
297 }
298
299 /**
300 Loads an EFI image into SMRAM.
301
302 @param DriverEntry EFI_SMM_DRIVER_ENTRY instance
303
304 @return EFI_STATUS
305
306 **/
307 EFI_STATUS
308 EFIAPI
309 SmmLoadImage (
310 IN OUT EFI_SMM_DRIVER_ENTRY *DriverEntry
311 )
312 {
313 UINT32 AuthenticationStatus;
314 UINTN FilePathSize;
315 VOID *Buffer;
316 UINTN Size;
317 UINTN PageCount;
318 EFI_GUID *NameGuid;
319 EFI_STATUS Status;
320 EFI_STATUS SecurityStatus;
321 EFI_HANDLE DeviceHandle;
322 EFI_PHYSICAL_ADDRESS DstBuffer;
323 EFI_DEVICE_PATH_PROTOCOL *FilePath;
324 EFI_DEVICE_PATH_PROTOCOL *OriginalFilePath;
325 EFI_DEVICE_PATH_PROTOCOL *HandleFilePath;
326 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
327 PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
328
329 PERF_LOAD_IMAGE_BEGIN (DriverEntry->ImageHandle);
330
331 Buffer = NULL;
332 Size = 0;
333 Fv = DriverEntry->Fv;
334 NameGuid = &DriverEntry->FileName;
335 FilePath = DriverEntry->FvFileDevicePath;
336
337 OriginalFilePath = FilePath;
338 HandleFilePath = FilePath;
339 DeviceHandle = NULL;
340 SecurityStatus = EFI_SUCCESS;
341 Status = EFI_SUCCESS;
342 AuthenticationStatus = 0;
343
344 //
345 // Try to get the image device handle by checking the match protocol.
346 //
347 Status = gBS->LocateDevicePath (&gEfiFirmwareVolume2ProtocolGuid, &HandleFilePath, &DeviceHandle);
348 if (EFI_ERROR (Status)) {
349 return Status;
350 }
351
352 //
353 // If the Security2 and Security Architectural Protocol has not been located yet, then attempt to locate it
354 //
355 if (mSecurity2 == NULL) {
356 gBS->LocateProtocol (&gEfiSecurity2ArchProtocolGuid, NULL, (VOID **)&mSecurity2);
357 }
358
359 if (mSecurity == NULL) {
360 gBS->LocateProtocol (&gEfiSecurityArchProtocolGuid, NULL, (VOID **)&mSecurity);
361 }
362
363 //
364 // When Security2 is installed, Security Architectural Protocol must be published.
365 //
366 ASSERT (mSecurity2 == NULL || mSecurity != NULL);
367
368 //
369 // Pull out just the file portion of the DevicePath for the LoadedImage FilePath
370 //
371 FilePath = OriginalFilePath;
372 Status = gBS->HandleProtocol (DeviceHandle, &gEfiDevicePathProtocolGuid, (VOID **)&HandleFilePath);
373 if (!EFI_ERROR (Status)) {
374 FilePathSize = GetDevicePathSize (HandleFilePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL);
375 FilePath = (EFI_DEVICE_PATH_PROTOCOL *)(((UINT8 *)FilePath) + FilePathSize);
376 }
377
378 //
379 // Try reading PE32 section firstly
380 //
381 Status = Fv->ReadSection (
382 Fv,
383 NameGuid,
384 EFI_SECTION_PE32,
385 0,
386 &Buffer,
387 &Size,
388 &AuthenticationStatus
389 );
390
391 if (EFI_ERROR (Status)) {
392 //
393 // Try reading TE section secondly
394 //
395 Buffer = NULL;
396 Size = 0;
397 Status = Fv->ReadSection (
398 Fv,
399 NameGuid,
400 EFI_SECTION_TE,
401 0,
402 &Buffer,
403 &Size,
404 &AuthenticationStatus
405 );
406 }
407
408 if (EFI_ERROR (Status)) {
409 if (Buffer != NULL) {
410 gBS->FreePool (Buffer);
411 }
412
413 return Status;
414 }
415
416 //
417 // Verify File Authentication through the Security2 Architectural Protocol
418 //
419 if (mSecurity2 != NULL) {
420 SecurityStatus = mSecurity2->FileAuthentication (
421 mSecurity2,
422 OriginalFilePath,
423 Buffer,
424 Size,
425 FALSE
426 );
427 }
428
429 //
430 // Verify the Authentication Status through the Security Architectural Protocol
431 // Only on images that have been read using Firmware Volume protocol.
432 // All SMM images are from FV protocol.
433 //
434 if (!EFI_ERROR (SecurityStatus) && (mSecurity != NULL)) {
435 SecurityStatus = mSecurity->FileAuthenticationState (
436 mSecurity,
437 AuthenticationStatus,
438 OriginalFilePath
439 );
440 }
441
442 if (EFI_ERROR (SecurityStatus) && (SecurityStatus != EFI_SECURITY_VIOLATION)) {
443 Status = SecurityStatus;
444 return Status;
445 }
446
447 //
448 // Initialize ImageContext
449 //
450 ImageContext.Handle = Buffer;
451 ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
452
453 //
454 // Get information about the image being loaded
455 //
456 Status = PeCoffLoaderGetImageInfo (&ImageContext);
457 if (EFI_ERROR (Status)) {
458 if (Buffer != NULL) {
459 gBS->FreePool (Buffer);
460 }
461
462 return Status;
463 }
464
465 //
466 // if Loading module at Fixed Address feature is enabled, then cut out a memory range started from TESG BASE
467 // to hold the Smm driver code
468 //
469 if (PcdGet64 (PcdLoadModuleAtFixAddressEnable) != 0) {
470 //
471 // Get the fixed loading address assigned by Build tool
472 //
473 Status = GetPeCoffImageFixLoadingAssignedAddress (&ImageContext);
474 if (!EFI_ERROR (Status)) {
475 //
476 // Since the memory range to load Smm core already been cut out, so no need to allocate and free this range
477 // following statements is to bypass SmmFreePages
478 //
479 PageCount = 0;
480 DstBuffer = (UINTN)gLoadModuleAtFixAddressSmramBase;
481 } else {
482 DEBUG ((DEBUG_INFO|DEBUG_LOAD, "LOADING MODULE FIXED ERROR: Failed to load module at fixed address. \n"));
483 //
484 // allocate the memory to load the SMM driver
485 //
486 PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
487 DstBuffer = (UINTN)(-1);
488
489 Status = SmmAllocatePages (
490 AllocateMaxAddress,
491 EfiRuntimeServicesCode,
492 PageCount,
493 &DstBuffer
494 );
495 if (EFI_ERROR (Status)) {
496 if (Buffer != NULL) {
497 gBS->FreePool (Buffer);
498 }
499
500 return Status;
501 }
502
503 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
504 }
505 } else {
506 PageCount = (UINTN)EFI_SIZE_TO_PAGES ((UINTN)ImageContext.ImageSize + ImageContext.SectionAlignment);
507 DstBuffer = (UINTN)(-1);
508
509 Status = SmmAllocatePages (
510 AllocateMaxAddress,
511 EfiRuntimeServicesCode,
512 PageCount,
513 &DstBuffer
514 );
515 if (EFI_ERROR (Status)) {
516 if (Buffer != NULL) {
517 gBS->FreePool (Buffer);
518 }
519
520 return Status;
521 }
522
523 ImageContext.ImageAddress = (EFI_PHYSICAL_ADDRESS)DstBuffer;
524 }
525
526 //
527 // Align buffer on section boundary
528 //
529 ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
530 ImageContext.ImageAddress &= ~((EFI_PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
531
532 //
533 // Load the image to our new buffer
534 //
535 Status = PeCoffLoaderLoadImage (&ImageContext);
536 if (EFI_ERROR (Status)) {
537 if (Buffer != NULL) {
538 gBS->FreePool (Buffer);
539 }
540
541 SmmFreePages (DstBuffer, PageCount);
542 return Status;
543 }
544
545 //
546 // Relocate the image in our new buffer
547 //
548 Status = PeCoffLoaderRelocateImage (&ImageContext);
549 if (EFI_ERROR (Status)) {
550 if (Buffer != NULL) {
551 gBS->FreePool (Buffer);
552 }
553
554 SmmFreePages (DstBuffer, PageCount);
555 return Status;
556 }
557
558 //
559 // Flush the instruction cache so the image data are written before we execute it
560 //
561 InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
562
563 //
564 // Save Image EntryPoint in DriverEntry
565 //
566 DriverEntry->ImageEntryPoint = ImageContext.EntryPoint;
567 DriverEntry->ImageBuffer = DstBuffer;
568 DriverEntry->NumberOfPage = PageCount;
569
570 //
571 // Allocate a Loaded Image Protocol in EfiBootServicesData
572 //
573 Status = gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_LOADED_IMAGE_PROTOCOL), (VOID **)&DriverEntry->LoadedImage);
574 if (EFI_ERROR (Status)) {
575 if (Buffer != NULL) {
576 gBS->FreePool (Buffer);
577 }
578
579 SmmFreePages (DstBuffer, PageCount);
580 return Status;
581 }
582
583 ZeroMem (DriverEntry->LoadedImage, sizeof (EFI_LOADED_IMAGE_PROTOCOL));
584 //
585 // Fill in the remaining fields of the Loaded Image Protocol instance.
586 // Note: ImageBase is an SMRAM address that can not be accessed outside of SMRAM if SMRAM window is closed.
587 //
588 DriverEntry->LoadedImage->Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
589 DriverEntry->LoadedImage->ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
590 DriverEntry->LoadedImage->SystemTable = gST;
591 DriverEntry->LoadedImage->DeviceHandle = DeviceHandle;
592
593 DriverEntry->SmmLoadedImage.Revision = EFI_LOADED_IMAGE_PROTOCOL_REVISION;
594 DriverEntry->SmmLoadedImage.ParentHandle = gSmmCorePrivate->SmmIplImageHandle;
595 DriverEntry->SmmLoadedImage.SystemTable = gST;
596 DriverEntry->SmmLoadedImage.DeviceHandle = DeviceHandle;
597
598 //
599 // Make an EfiBootServicesData buffer copy of FilePath
600 //
601 Status = gBS->AllocatePool (EfiBootServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->LoadedImage->FilePath);
602 if (EFI_ERROR (Status)) {
603 if (Buffer != NULL) {
604 gBS->FreePool (Buffer);
605 }
606
607 SmmFreePages (DstBuffer, PageCount);
608 return Status;
609 }
610
611 CopyMem (DriverEntry->LoadedImage->FilePath, FilePath, GetDevicePathSize (FilePath));
612
613 DriverEntry->LoadedImage->ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress;
614 DriverEntry->LoadedImage->ImageSize = ImageContext.ImageSize;
615 DriverEntry->LoadedImage->ImageCodeType = EfiRuntimeServicesCode;
616 DriverEntry->LoadedImage->ImageDataType = EfiRuntimeServicesData;
617
618 //
619 // Make a buffer copy of FilePath
620 //
621 Status = SmmAllocatePool (EfiRuntimeServicesData, GetDevicePathSize (FilePath), (VOID **)&DriverEntry->SmmLoadedImage.FilePath);
622 if (EFI_ERROR (Status)) {
623 if (Buffer != NULL) {
624 gBS->FreePool (Buffer);
625 }
626
627 gBS->FreePool (DriverEntry->LoadedImage->FilePath);
628 SmmFreePages (DstBuffer, PageCount);
629 return Status;
630 }
631
632 CopyMem (DriverEntry->SmmLoadedImage.FilePath, FilePath, GetDevicePathSize (FilePath));
633
634 DriverEntry->SmmLoadedImage.ImageBase = (VOID *)(UINTN)ImageContext.ImageAddress;
635 DriverEntry->SmmLoadedImage.ImageSize = ImageContext.ImageSize;
636 DriverEntry->SmmLoadedImage.ImageCodeType = EfiRuntimeServicesCode;
637 DriverEntry->SmmLoadedImage.ImageDataType = EfiRuntimeServicesData;
638
639 //
640 // Create a new image handle in the UEFI handle database for the SMM Driver
641 //
642 DriverEntry->ImageHandle = NULL;
643 Status = gBS->InstallMultipleProtocolInterfaces (
644 &DriverEntry->ImageHandle,
645 &gEfiLoadedImageProtocolGuid,
646 DriverEntry->LoadedImage,
647 NULL
648 );
649
650 //
651 // Create a new image handle in the SMM handle database for the SMM Driver
652 //
653 DriverEntry->SmmImageHandle = NULL;
654 Status = SmmInstallProtocolInterface (
655 &DriverEntry->SmmImageHandle,
656 &gEfiLoadedImageProtocolGuid,
657 EFI_NATIVE_INTERFACE,
658 &DriverEntry->SmmLoadedImage
659 );
660
661 PERF_LOAD_IMAGE_END (DriverEntry->ImageHandle);
662
663 //
664 // Print the load address and the PDB file name if it is available
665 //
666
667 DEBUG_CODE_BEGIN ();
668
669 UINTN Index;
670 UINTN StartIndex;
671 CHAR8 EfiFileName[256];
672
673 DEBUG ((
674 DEBUG_INFO | DEBUG_LOAD,
675 "Loading SMM driver at 0x%11p EntryPoint=0x%11p ",
676 (VOID *)(UINTN)ImageContext.ImageAddress,
677 FUNCTION_ENTRY_POINT (ImageContext.EntryPoint)
678 ));
679
680 //
681 // Print Module Name by Pdb file path.
682 // Windows and Unix style file path are all trimmed correctly.
683 //
684 if (ImageContext.PdbPointer != NULL) {
685 StartIndex = 0;
686 for (Index = 0; ImageContext.PdbPointer[Index] != 0; Index++) {
687 if ((ImageContext.PdbPointer[Index] == '\\') || (ImageContext.PdbPointer[Index] == '/')) {
688 StartIndex = Index + 1;
689 }
690 }
691
692 //
693 // Copy the PDB file name to our temporary string, and replace .pdb with .efi
694 // The PDB file name is limited in the range of 0~255.
695 // If the length is bigger than 255, trim the redundant characters to avoid overflow in array boundary.
696 //
697 for (Index = 0; Index < sizeof (EfiFileName) - 4; Index++) {
698 EfiFileName[Index] = ImageContext.PdbPointer[Index + StartIndex];
699 if (EfiFileName[Index] == 0) {
700 EfiFileName[Index] = '.';
701 }
702
703 if (EfiFileName[Index] == '.') {
704 EfiFileName[Index + 1] = 'e';
705 EfiFileName[Index + 2] = 'f';
706 EfiFileName[Index + 3] = 'i';
707 EfiFileName[Index + 4] = 0;
708 break;
709 }
710 }
711
712 if (Index == sizeof (EfiFileName) - 4) {
713 EfiFileName[Index] = 0;
714 }
715
716 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "%a", EfiFileName)); // &Image->ImageContext.PdbPointer[StartIndex]));
717 }
718
719 DEBUG ((DEBUG_INFO | DEBUG_LOAD, "\n"));
720
721 DEBUG_CODE_END ();
722
723 //
724 // Free buffer allocated by Fv->ReadSection.
725 //
726 // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
727 // used the UEFI Boot Services AllocatePool() function
728 //
729 Status = gBS->FreePool (Buffer);
730 if (!EFI_ERROR (Status) && EFI_ERROR (SecurityStatus)) {
731 Status = SecurityStatus;
732 }
733
734 return Status;
735 }
736
737 /**
738 Preprocess dependency expression and update DriverEntry to reflect the
739 state of Before and After dependencies. If DriverEntry->Before
740 or DriverEntry->After is set it will never be cleared.
741
742 @param DriverEntry DriverEntry element to update .
743
744 @retval EFI_SUCCESS It always works.
745
746 **/
747 EFI_STATUS
748 SmmPreProcessDepex (
749 IN EFI_SMM_DRIVER_ENTRY *DriverEntry
750 )
751 {
752 UINT8 *Iterator;
753
754 Iterator = DriverEntry->Depex;
755 DriverEntry->Dependent = TRUE;
756
757 if (*Iterator == EFI_DEP_BEFORE) {
758 DriverEntry->Before = TRUE;
759 } else if (*Iterator == EFI_DEP_AFTER) {
760 DriverEntry->After = TRUE;
761 }
762
763 if (DriverEntry->Before || DriverEntry->After) {
764 CopyMem (&DriverEntry->BeforeAfterGuid, Iterator + 1, sizeof (EFI_GUID));
765 }
766
767 return EFI_SUCCESS;
768 }
769
770 /**
771 Read Depex and pre-process the Depex for Before and After. If Section Extraction
772 protocol returns an error via ReadSection defer the reading of the Depex.
773
774 @param DriverEntry Driver to work on.
775
776 @retval EFI_SUCCESS Depex read and preprocessed
777 @retval EFI_PROTOCOL_ERROR The section extraction protocol returned an error
778 and Depex reading needs to be retried.
779 @retval Error DEPEX not found.
780
781 **/
782 EFI_STATUS
783 SmmGetDepexSectionAndPreProccess (
784 IN EFI_SMM_DRIVER_ENTRY *DriverEntry
785 )
786 {
787 EFI_STATUS Status;
788 EFI_SECTION_TYPE SectionType;
789 UINT32 AuthenticationStatus;
790 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
791
792 Fv = DriverEntry->Fv;
793
794 //
795 // Grab Depex info, it will never be free'ed.
796 // (Note: DriverEntry->Depex is in DXE memory)
797 //
798 SectionType = EFI_SECTION_SMM_DEPEX;
799 Status = Fv->ReadSection (
800 DriverEntry->Fv,
801 &DriverEntry->FileName,
802 SectionType,
803 0,
804 &DriverEntry->Depex,
805 (UINTN *)&DriverEntry->DepexSize,
806 &AuthenticationStatus
807 );
808 if (EFI_ERROR (Status)) {
809 if (Status == EFI_PROTOCOL_ERROR) {
810 //
811 // The section extraction protocol failed so set protocol error flag
812 //
813 DriverEntry->DepexProtocolError = TRUE;
814 } else {
815 //
816 // If no Depex assume depend on all architectural protocols
817 //
818 DriverEntry->Depex = NULL;
819 DriverEntry->Dependent = TRUE;
820 DriverEntry->DepexProtocolError = FALSE;
821 }
822 } else {
823 //
824 // Set Before and After state information based on Depex
825 // Driver will be put in Dependent state
826 //
827 SmmPreProcessDepex (DriverEntry);
828 DriverEntry->DepexProtocolError = FALSE;
829 }
830
831 return Status;
832 }
833
834 /**
835 This is the main Dispatcher for SMM and it exits when there are no more
836 drivers to run. Drain the mScheduledQueue and load and start a PE
837 image for each driver. Search the mDiscoveredList to see if any driver can
838 be placed on the mScheduledQueue. If no drivers are placed on the
839 mScheduledQueue exit the function.
840
841 @retval EFI_SUCCESS All of the SMM Drivers that could be dispatched
842 have been run and the SMM Entry Point has been
843 registered.
844 @retval EFI_NOT_READY The SMM Driver that registered the SMM Entry Point
845 was just dispatched.
846 @retval EFI_NOT_FOUND There are no SMM Drivers available to be dispatched.
847 @retval EFI_ALREADY_STARTED The SMM Dispatcher is already running
848
849 **/
850 EFI_STATUS
851 SmmDispatcher (
852 VOID
853 )
854 {
855 EFI_STATUS Status;
856 LIST_ENTRY *Link;
857 EFI_SMM_DRIVER_ENTRY *DriverEntry;
858 BOOLEAN ReadyToRun;
859 BOOLEAN PreviousSmmEntryPointRegistered;
860
861 if (!gRequestDispatch) {
862 return EFI_NOT_FOUND;
863 }
864
865 if (gDispatcherRunning) {
866 //
867 // If the dispatcher is running don't let it be restarted.
868 //
869 return EFI_ALREADY_STARTED;
870 }
871
872 gDispatcherRunning = TRUE;
873
874 do {
875 //
876 // Drain the Scheduled Queue
877 //
878 while (!IsListEmpty (&mScheduledQueue)) {
879 DriverEntry = CR (
880 mScheduledQueue.ForwardLink,
881 EFI_SMM_DRIVER_ENTRY,
882 ScheduledLink,
883 EFI_SMM_DRIVER_ENTRY_SIGNATURE
884 );
885
886 //
887 // Load the SMM Driver image into memory. If the Driver was transitioned from
888 // Untrused to Scheduled it would have already been loaded so we may need to
889 // skip the LoadImage
890 //
891 if (DriverEntry->ImageHandle == NULL) {
892 Status = SmmLoadImage (DriverEntry);
893
894 //
895 // Update the driver state to reflect that it's been loaded
896 //
897 if (EFI_ERROR (Status)) {
898 //
899 // The SMM Driver could not be loaded, and do not attempt to load or start it again.
900 // Take driver from Scheduled to Initialized.
901 //
902 DriverEntry->Initialized = TRUE;
903 DriverEntry->Scheduled = FALSE;
904 RemoveEntryList (&DriverEntry->ScheduledLink);
905
906 //
907 // If it's an error don't try the StartImage
908 //
909 continue;
910 }
911 }
912
913 DriverEntry->Scheduled = FALSE;
914 DriverEntry->Initialized = TRUE;
915 RemoveEntryList (&DriverEntry->ScheduledLink);
916
917 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
918 EFI_PROGRESS_CODE,
919 EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_BEGIN,
920 &DriverEntry->ImageHandle,
921 sizeof (DriverEntry->ImageHandle)
922 );
923
924 //
925 // Cache state of SmmEntryPointRegistered before calling entry point
926 //
927 PreviousSmmEntryPointRegistered = gSmmCorePrivate->SmmEntryPointRegistered;
928
929 //
930 // For each SMM driver, pass NULL as ImageHandle
931 //
932 RegisterSmramProfileImage (DriverEntry, TRUE);
933 PERF_START_IMAGE_BEGIN (DriverEntry->ImageHandle);
934 Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)DriverEntry->ImageEntryPoint)(DriverEntry->ImageHandle, gST);
935 PERF_START_IMAGE_END (DriverEntry->ImageHandle);
936 if (EFI_ERROR (Status)) {
937 DEBUG ((
938 DEBUG_ERROR,
939 "Error: SMM image at %11p start failed: %r\n",
940 DriverEntry->SmmLoadedImage.ImageBase,
941 Status
942 ));
943 UnregisterSmramProfileImage (DriverEntry, TRUE);
944 SmmFreePages (DriverEntry->ImageBuffer, DriverEntry->NumberOfPage);
945 //
946 // Uninstall LoadedImage
947 //
948 Status = gBS->UninstallProtocolInterface (
949 DriverEntry->ImageHandle,
950 &gEfiLoadedImageProtocolGuid,
951 DriverEntry->LoadedImage
952 );
953 if (!EFI_ERROR (Status)) {
954 if (DriverEntry->LoadedImage->FilePath != NULL) {
955 gBS->FreePool (DriverEntry->LoadedImage->FilePath);
956 }
957
958 gBS->FreePool (DriverEntry->LoadedImage);
959 }
960
961 Status = SmmUninstallProtocolInterface (
962 DriverEntry->SmmImageHandle,
963 &gEfiLoadedImageProtocolGuid,
964 &DriverEntry->SmmLoadedImage
965 );
966 if (!EFI_ERROR (Status)) {
967 if (DriverEntry->SmmLoadedImage.FilePath != NULL) {
968 SmmFreePool (DriverEntry->SmmLoadedImage.FilePath);
969 }
970 }
971 }
972
973 REPORT_STATUS_CODE_WITH_EXTENDED_DATA (
974 EFI_PROGRESS_CODE,
975 EFI_SOFTWARE_SMM_DRIVER | EFI_SW_PC_INIT_END,
976 &DriverEntry->ImageHandle,
977 sizeof (DriverEntry->ImageHandle)
978 );
979
980 if (!PreviousSmmEntryPointRegistered && gSmmCorePrivate->SmmEntryPointRegistered) {
981 //
982 // Return immediately if the SMM Entry Point was registered by the SMM
983 // Driver that was just dispatched. The SMM IPL will reinvoke the SMM
984 // Core Dispatcher. This is required so SMM Mode may be enabled as soon
985 // as all the dependent SMM Drivers for SMM Mode have been dispatched.
986 // Once the SMM Entry Point has been registered, then SMM Mode will be
987 // used.
988 //
989 gRequestDispatch = TRUE;
990 gDispatcherRunning = FALSE;
991 return EFI_NOT_READY;
992 }
993 }
994
995 //
996 // Search DriverList for items to place on Scheduled Queue
997 //
998 ReadyToRun = FALSE;
999 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1000 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1001
1002 if (DriverEntry->DepexProtocolError) {
1003 //
1004 // If Section Extraction Protocol did not let the Depex be read before retry the read
1005 //
1006 Status = SmmGetDepexSectionAndPreProccess (DriverEntry);
1007 }
1008
1009 if (DriverEntry->Dependent) {
1010 if (SmmIsSchedulable (DriverEntry)) {
1011 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
1012 ReadyToRun = TRUE;
1013 }
1014 }
1015 }
1016 } while (ReadyToRun);
1017
1018 //
1019 // If there is no more SMM driver to dispatch, stop the dispatch request
1020 //
1021 gRequestDispatch = FALSE;
1022 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1023 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1024
1025 if (!DriverEntry->Initialized) {
1026 //
1027 // We have SMM driver pending to dispatch
1028 //
1029 gRequestDispatch = TRUE;
1030 break;
1031 }
1032 }
1033
1034 gDispatcherRunning = FALSE;
1035
1036 return EFI_SUCCESS;
1037 }
1038
1039 /**
1040 Insert InsertedDriverEntry onto the mScheduledQueue. To do this you
1041 must add any driver with a before dependency on InsertedDriverEntry first.
1042 You do this by recursively calling this routine. After all the Befores are
1043 processed you can add InsertedDriverEntry to the mScheduledQueue.
1044 Then you can add any driver with an After dependency on InsertedDriverEntry
1045 by recursively calling this routine.
1046
1047 @param InsertedDriverEntry The driver to insert on the ScheduledLink Queue
1048
1049 **/
1050 VOID
1051 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (
1052 IN EFI_SMM_DRIVER_ENTRY *InsertedDriverEntry
1053 )
1054 {
1055 LIST_ENTRY *Link;
1056 EFI_SMM_DRIVER_ENTRY *DriverEntry;
1057
1058 //
1059 // Process Before Dependency
1060 //
1061 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1062 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1063 if (DriverEntry->Before && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
1064 DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
1065 DEBUG ((DEBUG_DISPATCH, " BEFORE FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
1066 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
1067 //
1068 // Recursively process BEFORE
1069 //
1070 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
1071 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
1072 } else {
1073 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
1074 }
1075 }
1076 }
1077
1078 //
1079 // Convert driver from Dependent to Scheduled state
1080 //
1081
1082 InsertedDriverEntry->Dependent = FALSE;
1083 InsertedDriverEntry->Scheduled = TRUE;
1084 InsertTailList (&mScheduledQueue, &InsertedDriverEntry->ScheduledLink);
1085
1086 //
1087 // Process After Dependency
1088 //
1089 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1090 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1091 if (DriverEntry->After && DriverEntry->Dependent && (DriverEntry != InsertedDriverEntry)) {
1092 DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
1093 DEBUG ((DEBUG_DISPATCH, " AFTER FFS(%g) = ", &DriverEntry->BeforeAfterGuid));
1094 if (CompareGuid (&InsertedDriverEntry->FileName, &DriverEntry->BeforeAfterGuid)) {
1095 //
1096 // Recursively process AFTER
1097 //
1098 DEBUG ((DEBUG_DISPATCH, "TRUE\n END\n RESULT = TRUE\n"));
1099 SmmInsertOnScheduledQueueWhileProcessingBeforeAndAfter (DriverEntry);
1100 } else {
1101 DEBUG ((DEBUG_DISPATCH, "FALSE\n END\n RESULT = FALSE\n"));
1102 }
1103 }
1104 }
1105 }
1106
1107 /**
1108 Return TRUE if the Fv has been processed, FALSE if not.
1109
1110 @param FvHandle The handle of a FV that's being tested
1111
1112 @retval TRUE Fv protocol on FvHandle has been processed
1113 @retval FALSE Fv protocol on FvHandle has not yet been
1114 processed
1115
1116 **/
1117 BOOLEAN
1118 FvHasBeenProcessed (
1119 IN EFI_HANDLE FvHandle
1120 )
1121 {
1122 LIST_ENTRY *Link;
1123 KNOWN_HANDLE *KnownHandle;
1124
1125 for (Link = mFvHandleList.ForwardLink; Link != &mFvHandleList; Link = Link->ForwardLink) {
1126 KnownHandle = CR (Link, KNOWN_HANDLE, Link, KNOWN_HANDLE_SIGNATURE);
1127 if (KnownHandle->Handle == FvHandle) {
1128 return TRUE;
1129 }
1130 }
1131
1132 return FALSE;
1133 }
1134
1135 /**
1136 Remember that Fv protocol on FvHandle has had its drivers placed on the
1137 mDiscoveredList. This function adds entries on the mFvHandleList. Items are
1138 never removed/freed from the mFvHandleList.
1139
1140 @param FvHandle The handle of a FV that has been processed
1141
1142 **/
1143 VOID
1144 FvIsBeingProcessed (
1145 IN EFI_HANDLE FvHandle
1146 )
1147 {
1148 KNOWN_HANDLE *KnownHandle;
1149
1150 KnownHandle = AllocatePool (sizeof (KNOWN_HANDLE));
1151 ASSERT (KnownHandle != NULL);
1152
1153 KnownHandle->Signature = KNOWN_HANDLE_SIGNATURE;
1154 KnownHandle->Handle = FvHandle;
1155 InsertTailList (&mFvHandleList, &KnownHandle->Link);
1156 }
1157
1158 /**
1159 Convert FvHandle and DriverName into an EFI device path
1160
1161 @param Fv Fv protocol, needed to read Depex info out of
1162 FLASH.
1163 @param FvHandle Handle for Fv, needed in the
1164 EFI_SMM_DRIVER_ENTRY so that the PE image can be
1165 read out of the FV at a later time.
1166 @param DriverName Name of driver to add to mDiscoveredList.
1167
1168 @return Pointer to device path constructed from FvHandle and DriverName
1169
1170 **/
1171 EFI_DEVICE_PATH_PROTOCOL *
1172 SmmFvToDevicePath (
1173 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
1174 IN EFI_HANDLE FvHandle,
1175 IN EFI_GUID *DriverName
1176 )
1177 {
1178 EFI_STATUS Status;
1179 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
1180 EFI_DEVICE_PATH_PROTOCOL *FileNameDevicePath;
1181
1182 //
1183 // Remember the device path of the FV
1184 //
1185 Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1186 if (EFI_ERROR (Status)) {
1187 FileNameDevicePath = NULL;
1188 } else {
1189 //
1190 // Build a device path to the file in the FV to pass into gBS->LoadImage
1191 //
1192 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, DriverName);
1193 SetDevicePathEndNode (&mFvDevicePath.End);
1194
1195 //
1196 // Note: FileNameDevicePath is in DXE memory
1197 //
1198 FileNameDevicePath = AppendDevicePath (
1199 FvDevicePath,
1200 (EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath
1201 );
1202 }
1203
1204 return FileNameDevicePath;
1205 }
1206
1207 /**
1208 Add an entry to the mDiscoveredList. Allocate memory to store the DriverEntry,
1209 and initialize any state variables. Read the Depex from the FV and store it
1210 in DriverEntry. Pre-process the Depex to set the Before and After state.
1211 The Discovered list is never free'ed and contains booleans that represent the
1212 other possible SMM driver states.
1213
1214 @param Fv Fv protocol, needed to read Depex info out of
1215 FLASH.
1216 @param FvHandle Handle for Fv, needed in the
1217 EFI_SMM_DRIVER_ENTRY so that the PE image can be
1218 read out of the FV at a later time.
1219 @param DriverName Name of driver to add to mDiscoveredList.
1220
1221 @retval EFI_SUCCESS If driver was added to the mDiscoveredList.
1222 @retval EFI_ALREADY_STARTED The driver has already been started. Only one
1223 DriverName may be active in the system at any one
1224 time.
1225
1226 **/
1227 EFI_STATUS
1228 SmmAddToDriverList (
1229 IN EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv,
1230 IN EFI_HANDLE FvHandle,
1231 IN EFI_GUID *DriverName
1232 )
1233 {
1234 EFI_SMM_DRIVER_ENTRY *DriverEntry;
1235
1236 //
1237 // Create the Driver Entry for the list. ZeroPool initializes lots of variables to
1238 // NULL or FALSE.
1239 //
1240 DriverEntry = AllocateZeroPool (sizeof (EFI_SMM_DRIVER_ENTRY));
1241 ASSERT (DriverEntry != NULL);
1242
1243 DriverEntry->Signature = EFI_SMM_DRIVER_ENTRY_SIGNATURE;
1244 CopyGuid (&DriverEntry->FileName, DriverName);
1245 DriverEntry->FvHandle = FvHandle;
1246 DriverEntry->Fv = Fv;
1247 DriverEntry->FvFileDevicePath = SmmFvToDevicePath (Fv, FvHandle, DriverName);
1248
1249 SmmGetDepexSectionAndPreProccess (DriverEntry);
1250
1251 InsertTailList (&mDiscoveredList, &DriverEntry->Link);
1252 gRequestDispatch = TRUE;
1253
1254 return EFI_SUCCESS;
1255 }
1256
1257 /**
1258 This function is the main entry point for an SMM handler dispatch
1259 or communicate-based callback.
1260
1261 Event notification that is fired every time a FV dispatch protocol is added.
1262 More than one protocol may have been added when this event is fired, so you
1263 must loop on SmmLocateHandle () to see how many protocols were added and
1264 do the following to each FV:
1265 If the Fv has already been processed, skip it. If the Fv has not been
1266 processed then mark it as being processed, as we are about to process it.
1267 Read the Fv and add any driver in the Fv to the mDiscoveredList.The
1268 mDiscoveredList is never free'ed and contains variables that define
1269 the other states the SMM driver transitions to..
1270 While you are at it read the A Priori file into memory.
1271 Place drivers in the A Priori list onto the mScheduledQueue.
1272
1273 @param DispatchHandle The unique handle assigned to this handler by SmiHandlerRegister().
1274 @param Context Points to an optional handler context which was specified when the handler was registered.
1275 @param CommBuffer A pointer to a collection of data in memory that will
1276 be conveyed from a non-SMM environment into an SMM environment.
1277 @param CommBufferSize The size of the CommBuffer.
1278
1279 @return Status Code
1280
1281 **/
1282 EFI_STATUS
1283 EFIAPI
1284 SmmDriverDispatchHandler (
1285 IN EFI_HANDLE DispatchHandle,
1286 IN CONST VOID *Context OPTIONAL,
1287 IN OUT VOID *CommBuffer OPTIONAL,
1288 IN OUT UINTN *CommBufferSize OPTIONAL
1289 )
1290 {
1291 EFI_STATUS Status;
1292 UINTN HandleCount;
1293 EFI_HANDLE *HandleBuffer;
1294 EFI_STATUS GetNextFileStatus;
1295 EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
1296 EFI_DEVICE_PATH_PROTOCOL *FvDevicePath;
1297 EFI_HANDLE FvHandle;
1298 EFI_GUID NameGuid;
1299 UINTN Key;
1300 EFI_FV_FILETYPE Type;
1301 EFI_FV_FILE_ATTRIBUTES Attributes;
1302 UINTN Size;
1303 EFI_SMM_DRIVER_ENTRY *DriverEntry;
1304 EFI_GUID *AprioriFile;
1305 UINTN AprioriEntryCount;
1306 UINTN HandleIndex;
1307 UINTN SmmTypeIndex;
1308 UINTN AprioriIndex;
1309 LIST_ENTRY *Link;
1310 UINT32 AuthenticationStatus;
1311 UINTN SizeOfBuffer;
1312
1313 HandleBuffer = NULL;
1314 Status = gBS->LocateHandleBuffer (
1315 ByProtocol,
1316 &gEfiFirmwareVolume2ProtocolGuid,
1317 NULL,
1318 &HandleCount,
1319 &HandleBuffer
1320 );
1321 if (EFI_ERROR (Status)) {
1322 return EFI_NOT_FOUND;
1323 }
1324
1325 for (HandleIndex = 0; HandleIndex < HandleCount; HandleIndex++) {
1326 FvHandle = HandleBuffer[HandleIndex];
1327
1328 if (FvHasBeenProcessed (FvHandle)) {
1329 //
1330 // This Fv has already been processed so lets skip it!
1331 //
1332 continue;
1333 }
1334
1335 //
1336 // Since we are about to process this Fv mark it as processed.
1337 //
1338 FvIsBeingProcessed (FvHandle);
1339
1340 Status = gBS->HandleProtocol (FvHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **)&Fv);
1341 if (EFI_ERROR (Status)) {
1342 //
1343 // FvHandle must have a Firmware Volume2 Protocol thus we should never get here.
1344 //
1345 ASSERT (FALSE);
1346 continue;
1347 }
1348
1349 Status = gBS->HandleProtocol (FvHandle, &gEfiDevicePathProtocolGuid, (VOID **)&FvDevicePath);
1350 if (EFI_ERROR (Status)) {
1351 //
1352 // The Firmware volume doesn't have device path, can't be dispatched.
1353 //
1354 continue;
1355 }
1356
1357 //
1358 // Discover Drivers in FV and add them to the Discovered Driver List.
1359 // Process EFI_FV_FILETYPE_SMM type and then EFI_FV_FILETYPE_COMBINED_SMM_DXE
1360 // EFI_FV_FILETYPE_SMM_CORE is processed to produce a Loaded Image protocol for the core
1361 //
1362 for (SmmTypeIndex = 0; SmmTypeIndex < sizeof (mSmmFileTypes)/sizeof (EFI_FV_FILETYPE); SmmTypeIndex++) {
1363 //
1364 // Initialize the search key
1365 //
1366 Key = 0;
1367 do {
1368 Type = mSmmFileTypes[SmmTypeIndex];
1369 GetNextFileStatus = Fv->GetNextFile (
1370 Fv,
1371 &Key,
1372 &Type,
1373 &NameGuid,
1374 &Attributes,
1375 &Size
1376 );
1377 if (!EFI_ERROR (GetNextFileStatus)) {
1378 if (Type == EFI_FV_FILETYPE_SMM_CORE) {
1379 //
1380 // If this is the SMM core fill in it's DevicePath & DeviceHandle
1381 //
1382 if (mSmmCoreLoadedImage->FilePath == NULL) {
1383 //
1384 // Maybe one special FV contains only one SMM_CORE module, so its device path must
1385 // be initialized completely.
1386 //
1387 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
1388 SetDevicePathEndNode (&mFvDevicePath.End);
1389
1390 //
1391 // Make an EfiBootServicesData buffer copy of FilePath
1392 //
1393 Status = gBS->AllocatePool (
1394 EfiBootServicesData,
1395 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
1396 (VOID **)&mSmmCoreLoadedImage->FilePath
1397 );
1398 ASSERT_EFI_ERROR (Status);
1399 CopyMem (mSmmCoreLoadedImage->FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
1400
1401 mSmmCoreLoadedImage->DeviceHandle = FvHandle;
1402 }
1403
1404 if (mSmmCoreDriverEntry->SmmLoadedImage.FilePath == NULL) {
1405 //
1406 // Maybe one special FV contains only one SMM_CORE module, so its device path must
1407 // be initialized completely.
1408 //
1409 EfiInitializeFwVolDevicepathNode (&mFvDevicePath.File, &NameGuid);
1410 SetDevicePathEndNode (&mFvDevicePath.End);
1411
1412 //
1413 // Make a buffer copy FilePath
1414 //
1415 Status = SmmAllocatePool (
1416 EfiRuntimeServicesData,
1417 GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath),
1418 (VOID **)&mSmmCoreDriverEntry->SmmLoadedImage.FilePath
1419 );
1420 ASSERT_EFI_ERROR (Status);
1421 CopyMem (mSmmCoreDriverEntry->SmmLoadedImage.FilePath, &mFvDevicePath, GetDevicePathSize ((EFI_DEVICE_PATH_PROTOCOL *)&mFvDevicePath));
1422
1423 mSmmCoreDriverEntry->SmmLoadedImage.DeviceHandle = FvHandle;
1424 }
1425 } else {
1426 SmmAddToDriverList (Fv, FvHandle, &NameGuid);
1427 }
1428 }
1429 } while (!EFI_ERROR (GetNextFileStatus));
1430 }
1431
1432 //
1433 // Read the array of GUIDs from the Apriori file if it is present in the firmware volume
1434 // (Note: AprioriFile is in DXE memory)
1435 //
1436 AprioriFile = NULL;
1437 Status = Fv->ReadSection (
1438 Fv,
1439 &gAprioriGuid,
1440 EFI_SECTION_RAW,
1441 0,
1442 (VOID **)&AprioriFile,
1443 &SizeOfBuffer,
1444 &AuthenticationStatus
1445 );
1446 if (!EFI_ERROR (Status)) {
1447 AprioriEntryCount = SizeOfBuffer / sizeof (EFI_GUID);
1448 } else {
1449 AprioriEntryCount = 0;
1450 }
1451
1452 //
1453 // Put drivers on Apriori List on the Scheduled queue. The Discovered List includes
1454 // drivers not in the current FV and these must be skipped since the a priori list
1455 // is only valid for the FV that it resided in.
1456 //
1457
1458 for (AprioriIndex = 0; AprioriIndex < AprioriEntryCount; AprioriIndex++) {
1459 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1460 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1461 if (CompareGuid (&DriverEntry->FileName, &AprioriFile[AprioriIndex]) &&
1462 (FvHandle == DriverEntry->FvHandle))
1463 {
1464 DriverEntry->Dependent = FALSE;
1465 DriverEntry->Scheduled = TRUE;
1466 InsertTailList (&mScheduledQueue, &DriverEntry->ScheduledLink);
1467 DEBUG ((DEBUG_DISPATCH, "Evaluate SMM DEPEX for FFS(%g)\n", &DriverEntry->FileName));
1468 DEBUG ((DEBUG_DISPATCH, " RESULT = TRUE (Apriori)\n"));
1469 break;
1470 }
1471 }
1472 }
1473
1474 //
1475 // Free data allocated by Fv->ReadSection ()
1476 //
1477 // The UEFI Boot Services FreePool() function must be used because Fv->ReadSection
1478 // used the UEFI Boot Services AllocatePool() function
1479 //
1480 gBS->FreePool (AprioriFile);
1481 }
1482
1483 //
1484 // Execute the SMM Dispatcher on any newly discovered FVs and previously
1485 // discovered SMM drivers that have been discovered but not dispatched.
1486 //
1487 Status = SmmDispatcher ();
1488
1489 //
1490 // Check to see if CommBuffer and CommBufferSize are valid
1491 //
1492 if ((CommBuffer != NULL) && (CommBufferSize != NULL)) {
1493 if (*CommBufferSize > 0) {
1494 if (Status == EFI_NOT_READY) {
1495 //
1496 // If a the SMM Core Entry Point was just registered, then set flag to
1497 // request the SMM Dispatcher to be restarted.
1498 //
1499 *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_RESTART;
1500 } else if (!EFI_ERROR (Status)) {
1501 //
1502 // Set the flag to show that the SMM Dispatcher executed without errors
1503 //
1504 *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_SUCCESS;
1505 } else {
1506 //
1507 // Set the flag to show that the SMM Dispatcher encountered an error
1508 //
1509 *(UINT8 *)CommBuffer = COMM_BUFFER_SMM_DISPATCH_ERROR;
1510 }
1511 }
1512 }
1513
1514 return EFI_SUCCESS;
1515 }
1516
1517 /**
1518 Traverse the discovered list for any drivers that were discovered but not loaded
1519 because the dependency expressions evaluated to false.
1520
1521 **/
1522 VOID
1523 SmmDisplayDiscoveredNotDispatched (
1524 VOID
1525 )
1526 {
1527 LIST_ENTRY *Link;
1528 EFI_SMM_DRIVER_ENTRY *DriverEntry;
1529
1530 for (Link = mDiscoveredList.ForwardLink; Link != &mDiscoveredList; Link = Link->ForwardLink) {
1531 DriverEntry = CR (Link, EFI_SMM_DRIVER_ENTRY, Link, EFI_SMM_DRIVER_ENTRY_SIGNATURE);
1532 if (DriverEntry->Dependent) {
1533 DEBUG ((DEBUG_LOAD, "SMM Driver %g was discovered but not loaded!!\n", &DriverEntry->FileName));
1534 }
1535 }
1536 }