1 /*++
2 
3 Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
4 This program and the accompanying materials
5 are licensed and made available under the terms and conditions of the BSD License
6 which accompanies this distribution.  The full text of the license may be found at
7 http://opensource.org/licenses/bsd-license.php
8 
9 THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
10 WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
11 
12 Module Name:
13   EfiLoader.c
14 
15 Abstract:
16 
17 Revision History:
18 
19 --*/
20 
21 #include "EfiLdr.h"
22 #include "Support.h"
23 #include "Debug.h"
24 #include "PeLoader.h"
25 #include "LzmaDecompress.h"
26 
27 EFILDR_LOADED_IMAGE    DxeCoreImage;
28 EFILDR_LOADED_IMAGE    DxeIplImage;
29 
30 VOID
SystemHang(CHAR8 * Message)31 SystemHang (
32   CHAR8        *Message
33   )
34 {
35   PrintString (
36     "%s## FATAL ERROR ##: Fail to load DUET images! System hang!\n",
37     Message
38     );
39   CpuDeadLoop();
40 }
41 
42 VOID
EfiLoader(UINT32 BiosMemoryMapBaseAddress)43 EfiLoader (
44   UINT32    BiosMemoryMapBaseAddress
45   )
46 {
47   BIOS_MEMORY_MAP       *BiosMemoryMap;
48   EFILDR_IMAGE          *EFILDRImage;
49   EFI_MEMORY_DESCRIPTOR EfiMemoryDescriptor[EFI_MAX_MEMORY_DESCRIPTORS];
50   EFI_STATUS            Status;
51   UINTN                 NumberOfMemoryMapEntries;
52   UINT32                DestinationSize;
53   UINT32                ScratchSize;
54   UINTN                 BfvPageNumber;
55   UINTN                 BfvBase;
56   EFI_MAIN_ENTRYPOINT   EfiMainEntrypoint;
57   EFILDRHANDOFF         Handoff;
58   UINTN                 Index;
59 
60   ClearScreen();
61 
62   PrintHeader ('A');
63 
64   PrintString ("Enter DUET Loader...\n");
65   PrintString ("BiosMemoryMapBaseAddress = %x\n", (UINTN) BiosMemoryMapBaseAddress);
66 
67   //
68   // Add all EfiConventionalMemory descriptors to the table.  If there are partial pages, then
69   // round the start address up to the next page, and round the length down to a page boundry.
70   //
71   BiosMemoryMap = (BIOS_MEMORY_MAP *) (UINTN) BiosMemoryMapBaseAddress;
72   NumberOfMemoryMapEntries = 0;
73   GenMemoryMap (&NumberOfMemoryMapEntries, EfiMemoryDescriptor, BiosMemoryMap);
74 
75   PrintString ("Get %d entries of memory map!\n", NumberOfMemoryMapEntries);
76 
77   //
78   // Get information on where the image is in memory
79   //
80   EFILDRImage  = (EFILDR_IMAGE *)(UINTN)(EFILDR_HEADER_ADDRESS + sizeof(EFILDR_HEADER));
81 
82 
83   //
84   // Point to the 4th image (Bfv)
85   //
86   EFILDRImage += 3;
87 
88   //
89   // Decompress the image
90   //
91   PrintString (
92     "Decompress BFV image, Image Address = %x Offset = %x\n",
93     (UINTN) (EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
94     (UINTN) EFILDRImage->Offset
95     );
96   Status = LzmaUefiDecompressGetInfo (
97              (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
98              EFILDRImage->Length,
99              &DestinationSize,
100              &ScratchSize
101              );
102 
103   if (EFI_ERROR (Status)) {
104     SystemHang ("Failed to get decompress information for BFV!\n");
105   }
106 
107   PrintString ("BFV decompress: DestinationSize = %x, ScratchSize = %x\n", (UINTN) DestinationSize, (UINTN) ScratchSize);
108   Status =  LzmaUefiDecompress (
109     (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
110     EFILDRImage->Length,
111     (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS,
112     (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000)
113     );
114 
115 
116   if (EFI_ERROR (Status)) {
117     SystemHang ("Failed to decompress BFV!\n");
118   }
119 
120   BfvPageNumber = EFI_SIZE_TO_PAGES (DestinationSize);
121   BfvBase = (UINTN) FindSpace (BfvPageNumber, &NumberOfMemoryMapEntries, EfiMemoryDescriptor, EfiRuntimeServicesData, EFI_MEMORY_WB);
122   if (BfvBase == 0) {
123     SystemHang ("Failed to find free space to hold decompressed BFV\n");
124   }
125   ZeroMem ((VOID *)(UINTN)BfvBase, BfvPageNumber * EFI_PAGE_SIZE);
126   CopyMem ((VOID *)(UINTN)BfvBase, (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS, DestinationSize);
127 
128   PrintHeader ('B');
129 
130   //
131   // Point to the 2nd image (DxeIpl)
132   //
133 
134   EFILDRImage -= 2;
135 
136   //
137   // Decompress the image
138   //
139   PrintString (
140     "Decompress DxeIpl image, Image Address = %x Offset = %x\n",
141     (UINTN) (EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
142     (UINTN) EFILDRImage->Offset
143     );
144 
145   Status = LzmaUefiDecompressGetInfo (
146              (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
147              EFILDRImage->Length,
148              &DestinationSize,
149              &ScratchSize
150              );
151   if (EFI_ERROR (Status)) {
152     SystemHang ("Failed to get decompress information for DxeIpl!\n");
153   }
154 
155   Status = LzmaUefiDecompress (
156              (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
157              EFILDRImage->Length,
158              (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS,
159              (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000)
160              );
161   if (EFI_ERROR (Status)) {
162     SystemHang ("Failed to decompress DxeIpl image\n");
163   }
164 
165   PrintString ("Start load DxeIpl PE image\n");
166 
167   //
168   // Load and relocate the EFI PE/COFF Firmware Image
169   //
170   Status = EfiLdrPeCoffLoadPeImage (
171              (VOID *)(UINTN)(EFI_DECOMPRESSED_BUFFER_ADDRESS),
172              &DxeIplImage,
173              &NumberOfMemoryMapEntries,
174              EfiMemoryDescriptor
175              );
176   if (EFI_ERROR (Status)) {
177     SystemHang ("Failed to load and relocate DxeIpl PE image!\n");
178   }
179   PrintString (
180     "DxeIpl PE image is successed loaded at %lx, entry=%p\n",
181     DxeIplImage.ImageBasePage,
182     DxeIplImage.EntryPoint
183     );
184 
185 PrintHeader ('C');
186 
187   //
188   // Point to the 3rd image (DxeMain)
189   //
190   EFILDRImage++;
191 
192   //
193   // Decompress the image
194   //
195   PrintString (
196     "Decompress DxeMain FV image, Image Address = %x Offset = %x\n",
197     (UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
198     (UINTN) EFILDRImage->Offset
199     );
200 
201   Status = LzmaUefiDecompressGetInfo (
202              (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
203              EFILDRImage->Length,
204              &DestinationSize,
205              &ScratchSize
206              );
207   if (EFI_ERROR (Status)) {
208     SystemHang ("Failed to get decompress information for DxeMain FV image!\n");
209   }
210 
211   Status = LzmaUefiDecompress (
212              (VOID *)(UINTN)(EFILDR_HEADER_ADDRESS + EFILDRImage->Offset),
213               EFILDRImage->Length,
214              (VOID *)(UINTN)EFI_DECOMPRESSED_BUFFER_ADDRESS,
215              (VOID *)(UINTN)((EFI_DECOMPRESSED_BUFFER_ADDRESS + DestinationSize + 0x1000) & 0xfffff000)
216              );
217   if (EFI_ERROR (Status)) {
218     SystemHang ("Failed to decompress DxeMain FV image!\n");
219   }
220 
221   //
222   // Load and relocate the EFI PE/COFF Firmware Image
223   //
224   Status = EfiLdrPeCoffLoadPeImage (
225              (VOID *)(UINTN)(EFI_DECOMPRESSED_BUFFER_ADDRESS),
226              &DxeCoreImage,
227              &NumberOfMemoryMapEntries,
228              EfiMemoryDescriptor
229              );
230   if (EFI_ERROR (Status)) {
231     SystemHang ("Failed to load/relocate DxeMain!\n");
232   }
233   PrintString (
234     "DxeCore PE image is successed loaded at %lx, entry=%p\n",
235     DxeCoreImage.ImageBasePage,
236     DxeCoreImage.EntryPoint
237     );
238 
239 PrintHeader ('E');
240 
241   //
242   // Display the table of memory descriptors.
243   //
244   PrintString ("\nEFI Memory Descriptors\n");
245   for (Index = 0; Index < NumberOfMemoryMapEntries; Index++) {
246     PrintString (
247       "Type = %x Start = %08lx NumberOfPages = %08lx\n",
248       EfiMemoryDescriptor[Index].Type, EfiMemoryDescriptor[Index].PhysicalStart, EfiMemoryDescriptor[Index].NumberOfPages
249       );
250   }
251 
252   //
253   // Jump to EFI Firmware
254   //
255 
256   if (DxeIplImage.EntryPoint != NULL) {
257 
258     Handoff.MemDescCount      = NumberOfMemoryMapEntries;
259     Handoff.MemDesc           = EfiMemoryDescriptor;
260     Handoff.BfvBase           = (VOID *)(UINTN)BfvBase;
261     Handoff.BfvSize           = BfvPageNumber * EFI_PAGE_SIZE;
262     Handoff.DxeIplImageBase   = (VOID *)(UINTN)DxeIplImage.ImageBasePage;
263     Handoff.DxeIplImageSize   = DxeIplImage.NoPages * EFI_PAGE_SIZE;
264     Handoff.DxeCoreImageBase  = (VOID *)(UINTN)DxeCoreImage.ImageBasePage;
265     Handoff.DxeCoreImageSize  = DxeCoreImage.NoPages * EFI_PAGE_SIZE;
266     Handoff.DxeCoreEntryPoint = (VOID *)(UINTN)DxeCoreImage.EntryPoint;
267 
268     PrintString ("Transfer to DxeIpl ...EntryPoint = %p\n", DxeIplImage.EntryPoint);
269 
270     EfiMainEntrypoint = (EFI_MAIN_ENTRYPOINT) DxeIplImage.EntryPoint;
271     EfiMainEntrypoint (&Handoff);
272   }
273 
274 PrintHeader ('F');
275 
276   //
277   // There was a problem loading the image, so HALT the system.
278   //
279 
280   SystemHang ("Failed to jump to DxeIpl!\n");
281 }
282 
283 EFI_STATUS
284 EFIAPI
_ModuleEntryPoint(UINT32 BiosMemoryMapBaseAddress)285 _ModuleEntryPoint (
286   UINT32    BiosMemoryMapBaseAddress
287   )
288 {
289   SerialPortInitialize ();
290   EfiLoader(BiosMemoryMapBaseAddress);
291   return EFI_SUCCESS;
292 }
293 
294 
295