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