]> git.proxmox.com Git - mirror_edk2.git/blob - IntelFrameworkPkg/Library/DxeSmmDriverEntryPoint/DriverEntryPoint.c
2b3a4803c96b5a04a448f917f8534efacea6dd0e
[mirror_edk2.git] / IntelFrameworkPkg / Library / DxeSmmDriverEntryPoint / DriverEntryPoint.c
1 /** @file
2 This file implement EfiMain() for library class DxeSmmDriverEntryPoint.
3 EfiMain() is common driver entry point for all SMM driver who uses DxeSmmDriverEntryPoint
4 library class.
5
6 Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>
7 SPDX-License-Identifier: BSD-2-Clause-Patent
8
9 **/
10
11
12 #include <FrameworkSmm.h>
13
14 #include <Protocol/LoadedImage.h>
15 #include <Protocol/SmmBase.h>
16 #include <Protocol/DevicePath.h>
17
18 #include <Library/UefiDriverEntryPoint.h>
19 #include <Library/UefiBootServicesTableLib.h>
20 #include <Library/DebugLib.h>
21 #include <Library/DevicePathLib.h>
22
23 /**
24 This function returns the size, in bytes,
25 of the device path data structure specified by DevicePath.
26 If DevicePath is NULL, then 0 is returned.
27
28 @param DevicePath A pointer to a device path data structure.
29
30 @return The size of a device path in bytes.
31
32 **/
33 UINTN
34 EFIAPI
35 SmmGetDevicePathSize (
36 IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
37 )
38 {
39 CONST EFI_DEVICE_PATH_PROTOCOL *Start;
40
41 if (DevicePath == NULL) {
42 return 0;
43 }
44
45 //
46 // Search for the end of the device path structure
47 //
48 Start = DevicePath;
49 while (!IsDevicePathEnd (DevicePath)) {
50 DevicePath = NextDevicePathNode (DevicePath);
51 }
52
53 //
54 // Compute the size and add back in the size of the end device path structure
55 //
56 return ((UINTN) DevicePath - (UINTN) Start) + sizeof (EFI_DEVICE_PATH_PROTOCOL);
57 }
58
59 /**
60 This function appends the device path SecondDevicePath
61 to every device path instance in FirstDevicePath.
62
63 @param FirstDevicePath A pointer to a device path data structure.
64
65 @param SecondDevicePath A pointer to a device path data structure.
66
67 @return A pointer to the new device path is returned.
68 NULL is returned if space for the new device path could not be allocated from pool.
69 It is up to the caller to free the memory used by FirstDevicePath and SecondDevicePath
70 if they are no longer needed.
71
72 **/
73 EFI_DEVICE_PATH_PROTOCOL *
74 EFIAPI
75 SmmAppendDevicePath (
76 IN CONST EFI_DEVICE_PATH_PROTOCOL *FirstDevicePath,
77 IN CONST EFI_DEVICE_PATH_PROTOCOL *SecondDevicePath
78 )
79 {
80 EFI_STATUS Status;
81 UINTN Size;
82 UINTN Size1;
83 UINTN Size2;
84 EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
85 EFI_DEVICE_PATH_PROTOCOL *DevicePath2;
86
87 ASSERT (FirstDevicePath != NULL && SecondDevicePath != NULL);
88
89 //
90 // Allocate space for the combined device path. It only has one end node of
91 // length EFI_DEVICE_PATH_PROTOCOL
92 //
93 Size1 = SmmGetDevicePathSize (FirstDevicePath);
94 Size2 = SmmGetDevicePathSize (SecondDevicePath);
95 Size = Size1 + Size2 - sizeof (EFI_DEVICE_PATH_PROTOCOL);
96
97 Status = gBS->AllocatePool (EfiBootServicesData, Size, (VOID **) &NewDevicePath);
98
99 if (EFI_SUCCESS == Status) {
100 //
101 // CopyMem in gBS is used as this service should always be ready. We didn't choose
102 // to use a BaseMemoryLib function as such library instance may have constructor.
103 //
104 gBS->CopyMem ((VOID *) NewDevicePath, (VOID *) FirstDevicePath, Size1);
105 //
106 // Over write Src1 EndNode and do the copy
107 //
108 DevicePath2 = (EFI_DEVICE_PATH_PROTOCOL *) ((CHAR8 *) NewDevicePath + (Size1 - sizeof (EFI_DEVICE_PATH_PROTOCOL)));
109 gBS->CopyMem ((VOID *) DevicePath2, (VOID *) SecondDevicePath, Size2);
110 }
111
112 return NewDevicePath;
113 }
114
115 /**
116 Unload function that is registered in the LoadImage protocol. It un-installs
117 protocols produced and deallocates pool used by the driver. Called by the core
118 when unloading the driver.
119
120 @param ImageHandle ImageHandle of the unloaded driver
121
122 @return Status of the ProcessModuleUnloadList.
123
124 **/
125 EFI_STATUS
126 EFIAPI
127 _DriverUnloadHandler (
128 EFI_HANDLE ImageHandle
129 )
130 {
131 //
132 // Call the unload handlers for all the modules.
133 //
134 // Note: All libraries were constructed in SMM space,
135 // therefore we can not destruct them in Unload
136 // handler.
137 //
138 return ProcessModuleUnloadList (ImageHandle);
139 }
140
141 /**
142 Enrty point to DXE SMM Driver.
143
144 @param ImageHandle ImageHandle of the loaded driver.
145 @param SystemTable Pointer to the EFI System Table.
146
147 @retval EFI_SUCCESS One or more of the drivers returned a success code.
148 @retval !EFI_SUCESS The return status from the last driver entry point in the list.
149
150 **/
151 EFI_STATUS
152 EFIAPI
153 _ModuleEntryPoint (
154 IN EFI_HANDLE ImageHandle,
155 IN EFI_SYSTEM_TABLE *SystemTable
156 )
157 {
158 EFI_STATUS Status;
159 EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
160 EFI_SMM_BASE_PROTOCOL *SmmBase;
161 BOOLEAN InSmm;
162 EFI_DEVICE_PATH_PROTOCOL *CompleteFilePath;
163 EFI_DEVICE_PATH_PROTOCOL *ImageDevicePath;
164 EFI_HANDLE Handle;
165
166 //
167 // Cache a pointer to the Boot Services Table
168 //
169 gBS = SystemTable->BootServices;
170
171 //
172 // Retrieve SMM Base Protocol
173 //
174 Status = gBS->LocateProtocol (
175 &gEfiSmmBaseProtocolGuid,
176 NULL,
177 (VOID **) &SmmBase
178 );
179 ASSERT_EFI_ERROR (Status);
180
181 //
182 // Check to see if we are already in SMM
183 //
184 SmmBase->InSmm (SmmBase, &InSmm);
185
186 //
187 //
188 //
189 if (!InSmm) {
190 //
191 // Retrieve the Loaded Image Protocol
192 //
193 Status = gBS->HandleProtocol (
194 ImageHandle,
195 &gEfiLoadedImageProtocolGuid,
196 (VOID*)&LoadedImage
197 );
198 ASSERT_EFI_ERROR (Status);
199 //
200 // Retrieve the Device Path Protocol from the DeviceHandle from which this driver was loaded
201 //
202 Status = gBS->HandleProtocol (
203 LoadedImage->DeviceHandle,
204 &gEfiDevicePathProtocolGuid,
205 (VOID*)&ImageDevicePath
206 );
207 ASSERT_EFI_ERROR (Status);
208
209 //
210 // Build the full device path to the currently execuing image
211 //
212 CompleteFilePath = SmmAppendDevicePath (ImageDevicePath, LoadedImage->FilePath);
213
214 //
215 // Load the image in memory to SMRAM; it will automatically generate the
216 // SMI.
217 //
218 Status = SmmBase->Register (SmmBase, CompleteFilePath, LoadedImage->ImageBase, 0, &Handle, FALSE);
219 ASSERT_EFI_ERROR (Status);
220 //
221 // Optionally install the unload handler
222 //
223 if (_gDriverUnloadImageCount > 0) {
224 Status = gBS->HandleProtocol (
225 ImageHandle,
226 &gEfiLoadedImageProtocolGuid,
227 (VOID **)&LoadedImage
228 );
229 ASSERT_EFI_ERROR (Status);
230 LoadedImage->Unload = _DriverUnloadHandler;
231 }
232
233 return Status;
234 }
235
236 //
237 // Call constructor for all libraries
238 //
239 ProcessLibraryConstructorList (ImageHandle, SystemTable);
240
241 //
242 // Call the list of driver entry points
243 //
244 Status = ProcessModuleEntryPointList (ImageHandle, SystemTable);
245 if (EFI_ERROR (Status)) {
246 ProcessLibraryDestructorList (ImageHandle, SystemTable);
247 }
248
249 return Status;
250 }
251
252 /**
253 Enrty point wrapper of DXE SMM Driver.
254
255 @param ImageHandle ImageHandle of the loaded driver.
256 @param SystemTable Pointer to the EFI System Table.
257
258 @retval EFI_SUCCESS One or more of the drivers returned a success code.
259 @retval !EFI_SUCESS The return status from the last driver entry point in the list.
260
261 **/
262 EFI_STATUS
263 EFIAPI
264 EfiMain (
265 IN EFI_HANDLE ImageHandle,
266 IN EFI_SYSTEM_TABLE *SystemTable
267 )
268 {
269 return _ModuleEntryPoint (ImageHandle, SystemTable);
270 }