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