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