]>
Commit | Line | Data |
---|---|---|
b522c77b HW |
1 | /** @file\r |
2 | \r | |
3 | Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r | |
4 | \r | |
5 | SPDX-License-Identifier: BSD-2-Clause-Patent\r | |
6 | \r | |
7 | **/\r | |
8 | \r | |
9 | #include "LegacyBiosInterface.h"\r | |
10 | \r | |
11 | #define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))\r | |
12 | \r | |
13 | //\r | |
14 | // define maximum number of HDD system supports\r | |
15 | //\r | |
ac0a286f | 16 | #define MAX_HDD_ENTRIES 0x30\r |
b522c77b HW |
17 | \r |
18 | //\r | |
19 | // Module Global:\r | |
20 | // Since this driver will only ever produce one instance of the Private Data\r | |
21 | // protocol you are not required to dynamically allocate the PrivateData.\r | |
22 | //\r | |
23 | LEGACY_BIOS_INSTANCE mPrivateData;\r | |
24 | \r | |
25 | //\r | |
26 | // The SMBIOS table in EfiRuntimeServicesData memory\r | |
27 | //\r | |
ac0a286f | 28 | VOID *mRuntimeSmbiosEntryPoint = NULL;\r |
b522c77b HW |
29 | \r |
30 | //\r | |
31 | // The SMBIOS table in EfiReservedMemoryType memory\r | |
32 | //\r | |
33 | EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;\r | |
34 | EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;\r | |
35 | UINTN mStructureTablePages = 0;\r | |
36 | BOOLEAN mEndOfDxe = FALSE;\r | |
37 | \r | |
38 | /**\r | |
39 | Allocate memory for legacy usage. The memory is executable.\r | |
40 | \r | |
41 | @param AllocateType The type of allocation to perform.\r | |
42 | @param MemoryType The type of memory to allocate.\r | |
43 | @param StartPageAddress Start address of range\r | |
44 | @param Pages Number of pages to allocate\r | |
45 | @param Result Result of allocation\r | |
46 | \r | |
47 | @retval EFI_SUCCESS Legacy memory is allocated successfully.\r | |
48 | @retval Other Legacy memory is not allocated.\r | |
49 | \r | |
50 | **/\r | |
51 | EFI_STATUS\r | |
52 | AllocateLegacyMemory (\r | |
ac0a286f MK |
53 | IN EFI_ALLOCATE_TYPE AllocateType,\r |
54 | IN EFI_MEMORY_TYPE MemoryType,\r | |
55 | IN EFI_PHYSICAL_ADDRESS StartPageAddress,\r | |
56 | IN UINTN Pages,\r | |
57 | OUT EFI_PHYSICAL_ADDRESS *Result\r | |
b522c77b HW |
58 | )\r |
59 | {\r | |
ac0a286f MK |
60 | EFI_STATUS Status;\r |
61 | EFI_PHYSICAL_ADDRESS MemPage;\r | |
62 | EFI_GCD_MEMORY_SPACE_DESCRIPTOR MemDesc;\r | |
b522c77b HW |
63 | \r |
64 | //\r | |
65 | // Allocate Pages of memory less <= StartPageAddress\r | |
66 | //\r | |
ac0a286f MK |
67 | MemPage = (EFI_PHYSICAL_ADDRESS)(UINTN)StartPageAddress;\r |
68 | Status = gBS->AllocatePages (\r | |
69 | AllocateType,\r | |
70 | MemoryType,\r | |
71 | Pages,\r | |
72 | &MemPage\r | |
73 | );\r | |
b522c77b HW |
74 | //\r |
75 | // Do not ASSERT on Status error but let caller decide since some cases\r | |
76 | // memory is already taken but that is ok.\r | |
77 | //\r | |
78 | if (!EFI_ERROR (Status)) {\r | |
79 | if (MemoryType != EfiBootServicesCode) {\r | |
80 | //\r | |
81 | // Make sure that the buffer can be used to store code.\r | |
82 | //\r | |
83 | Status = gDS->GetMemorySpaceDescriptor (MemPage, &MemDesc);\r | |
ac0a286f | 84 | if (!EFI_ERROR (Status) && ((MemDesc.Attributes & EFI_MEMORY_XP) != 0)) {\r |
b522c77b HW |
85 | Status = gDS->SetMemorySpaceAttributes (\r |
86 | MemPage,\r | |
87 | EFI_PAGES_TO_SIZE (Pages),\r | |
88 | MemDesc.Attributes & (~EFI_MEMORY_XP)\r | |
89 | );\r | |
90 | }\r | |
ac0a286f | 91 | \r |
b522c77b HW |
92 | if (EFI_ERROR (Status)) {\r |
93 | gBS->FreePages (MemPage, Pages);\r | |
94 | }\r | |
95 | }\r | |
96 | }\r | |
97 | \r | |
98 | if (!EFI_ERROR (Status)) {\r | |
ac0a286f | 99 | *Result = (EFI_PHYSICAL_ADDRESS)(UINTN)MemPage;\r |
b522c77b HW |
100 | }\r |
101 | \r | |
102 | return Status;\r | |
103 | }\r | |
104 | \r | |
b522c77b HW |
105 | /**\r |
106 | This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000\r | |
107 | 64 KB blocks.\r | |
108 | \r | |
109 | Note: inconsistency with the Framework CSM spec. Per the spec, this function may be\r | |
48cf40b8 | 110 | invoked only once. This limitation is relaxed to allow multiple calls in this implementation.\r |
b522c77b HW |
111 | \r |
112 | @param This Protocol instance pointer.\r | |
113 | @param LegacyMemorySize Size of required region\r | |
114 | @param Region Region to use. 00 = Either 0xE0000 or 0xF0000\r | |
115 | block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000\r | |
116 | block\r | |
117 | @param Alignment Address alignment. Bit mapped. First non-zero\r | |
118 | bit from right is alignment.\r | |
119 | @param LegacyMemoryAddress Region Assigned\r | |
120 | \r | |
121 | @retval EFI_SUCCESS Region assigned\r | |
122 | @retval EFI_ACCESS_DENIED Procedure previously invoked\r | |
123 | @retval Other Region not assigned\r | |
124 | \r | |
125 | **/\r | |
126 | EFI_STATUS\r | |
127 | EFIAPI\r | |
128 | LegacyBiosGetLegacyRegion (\r | |
ac0a286f MK |
129 | IN EFI_LEGACY_BIOS_PROTOCOL *This,\r |
130 | IN UINTN LegacyMemorySize,\r | |
131 | IN UINTN Region,\r | |
132 | IN UINTN Alignment,\r | |
133 | OUT VOID **LegacyMemoryAddress\r | |
b522c77b HW |
134 | )\r |
135 | {\r | |
ac0a286f MK |
136 | LEGACY_BIOS_INSTANCE *Private;\r |
137 | EFI_IA32_REGISTER_SET Regs;\r | |
138 | EFI_STATUS Status;\r | |
139 | UINT32 Granularity;\r | |
b522c77b HW |
140 | \r |
141 | Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r | |
142 | Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r | |
143 | \r | |
144 | ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r | |
145 | Regs.X.AX = Legacy16GetTableAddress;\r | |
ac0a286f MK |
146 | Regs.X.BX = (UINT16)Region;\r |
147 | Regs.X.CX = (UINT16)LegacyMemorySize;\r | |
148 | Regs.X.DX = (UINT16)Alignment;\r | |
b522c77b | 149 | Private->LegacyBios.FarCall86 (\r |
ac0a286f MK |
150 | &Private->LegacyBios,\r |
151 | Private->Legacy16CallSegment,\r | |
152 | Private->Legacy16CallOffset,\r | |
153 | &Regs,\r | |
154 | NULL,\r | |
155 | 0\r | |
156 | );\r | |
b522c77b HW |
157 | \r |
158 | if (Regs.X.AX == 0) {\r | |
ac0a286f MK |
159 | *LegacyMemoryAddress = (VOID *)(((UINTN)Regs.X.DS << 4) + Regs.X.BX);\r |
160 | Status = EFI_SUCCESS;\r | |
b522c77b HW |
161 | } else {\r |
162 | Status = EFI_OUT_OF_RESOURCES;\r | |
163 | }\r | |
164 | \r | |
165 | Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r | |
166 | Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r | |
167 | \r | |
168 | return Status;\r | |
169 | }\r | |
170 | \r | |
b522c77b HW |
171 | /**\r |
172 | This function is called when copying data to the region assigned by\r | |
173 | EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().\r | |
174 | \r | |
175 | @param This Protocol instance pointer.\r | |
176 | @param LegacyMemorySize Size of data to copy\r | |
177 | @param LegacyMemoryAddress Legacy Region destination address Note: must\r | |
178 | be in region assigned by\r | |
179 | LegacyBiosGetLegacyRegion\r | |
180 | @param LegacyMemorySourceAddress Source of data\r | |
181 | \r | |
182 | @retval EFI_SUCCESS The data was copied successfully.\r | |
183 | @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.\r | |
184 | **/\r | |
185 | EFI_STATUS\r | |
186 | EFIAPI\r | |
187 | LegacyBiosCopyLegacyRegion (\r | |
ac0a286f MK |
188 | IN EFI_LEGACY_BIOS_PROTOCOL *This,\r |
189 | IN UINTN LegacyMemorySize,\r | |
190 | IN VOID *LegacyMemoryAddress,\r | |
191 | IN VOID *LegacyMemorySourceAddress\r | |
b522c77b HW |
192 | )\r |
193 | {\r | |
b522c77b HW |
194 | LEGACY_BIOS_INSTANCE *Private;\r |
195 | UINT32 Granularity;\r | |
196 | \r | |
ac0a286f MK |
197 | if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000) ||\r |
198 | ((UINTN)LegacyMemoryAddress + LegacyMemorySize > (UINTN)0x100000)\r | |
199 | )\r | |
200 | {\r | |
b522c77b HW |
201 | return EFI_ACCESS_DENIED;\r |
202 | }\r | |
ac0a286f | 203 | \r |
b522c77b HW |
204 | //\r |
205 | // There is no protection from writes over lapping if this function is\r | |
206 | // called multiple times.\r | |
207 | //\r | |
208 | Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r | |
209 | Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r | |
210 | CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);\r | |
211 | \r | |
212 | Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);\r | |
213 | Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);\r | |
214 | \r | |
215 | return EFI_SUCCESS;\r | |
216 | }\r | |
217 | \r | |
b522c77b HW |
218 | /**\r |
219 | Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find\r | |
220 | the $EFI table in the shadow area. Thunk into the Legacy16 code after it had\r | |
221 | been shadowed.\r | |
222 | \r | |
223 | @param Private Legacy BIOS context data\r | |
224 | \r | |
225 | @retval EFI_SUCCESS Legacy16 code loaded\r | |
226 | @retval Other No protocol installed, unload driver.\r | |
227 | \r | |
228 | **/\r | |
229 | EFI_STATUS\r | |
230 | ShadowAndStartLegacy16 (\r | |
231 | IN LEGACY_BIOS_INSTANCE *Private\r | |
232 | )\r | |
233 | {\r | |
ac0a286f MK |
234 | EFI_STATUS Status;\r |
235 | UINT8 *Ptr;\r | |
236 | UINT8 *PtrEnd;\r | |
237 | BOOLEAN Done;\r | |
238 | EFI_COMPATIBILITY16_TABLE *Table;\r | |
239 | UINT8 CheckSum;\r | |
240 | EFI_IA32_REGISTER_SET Regs;\r | |
241 | EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r | |
242 | EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;\r | |
243 | VOID *LegacyBiosImage;\r | |
244 | UINTN LegacyBiosImageSize;\r | |
245 | UINTN E820Size;\r | |
246 | UINT32 *ClearPtr;\r | |
247 | BBS_TABLE *BbsTable;\r | |
248 | LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;\r | |
249 | UINTN Index;\r | |
250 | UINT32 TpmPointer;\r | |
251 | VOID *TpmBinaryImage;\r | |
252 | UINTN TpmBinaryImageSize;\r | |
253 | UINTN Location;\r | |
254 | UINTN Alignment;\r | |
255 | UINTN TempData;\r | |
256 | EFI_PHYSICAL_ADDRESS Address;\r | |
257 | UINT16 OldMask;\r | |
258 | UINT16 NewMask;\r | |
259 | UINT32 Granularity;\r | |
260 | EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r | |
b522c77b HW |
261 | \r |
262 | Location = 0;\r | |
263 | Alignment = 0;\r | |
264 | \r | |
265 | //\r | |
266 | // we allocate the C/D/E/F segment as RT code so no one will use it any more.\r | |
267 | //\r | |
268 | Address = 0xC0000;\r | |
269 | gDS->GetMemorySpaceDescriptor (Address, &Descriptor);\r | |
270 | if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {\r | |
271 | //\r | |
272 | // If it is already reserved, we should be safe, or else we allocate it.\r | |
273 | //\r | |
274 | Status = gBS->AllocatePages (\r | |
275 | AllocateAddress,\r | |
276 | EfiRuntimeServicesCode,\r | |
277 | 0x40000/EFI_PAGE_SIZE,\r | |
278 | &Address\r | |
279 | );\r | |
280 | if (EFI_ERROR (Status)) {\r | |
281 | //\r | |
282 | // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.\r | |
283 | //\r | |
284 | DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));\r | |
285 | }\r | |
286 | }\r | |
287 | \r | |
288 | //\r | |
289 | // start testtest\r | |
290 | // GetTimerValue (&Ticker);\r | |
291 | //\r | |
292 | // gRT->SetVariable (L"StartLegacy",\r | |
293 | // &gEfiGlobalVariableGuid,\r | |
294 | // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
295 | // sizeof (UINT64),\r | |
296 | // (VOID *)&Ticker\r | |
297 | // );\r | |
298 | // end testtest\r | |
299 | //\r | |
300 | EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;\r | |
ac0a286f MK |
301 | Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r |
302 | Private->LegacyBiosPlatform,\r | |
303 | EfiGetPlatformBinarySystemRom,\r | |
304 | &LegacyBiosImage,\r | |
305 | &LegacyBiosImageSize,\r | |
306 | &Location,\r | |
307 | &Alignment,\r | |
308 | 0,\r | |
309 | 0\r | |
310 | );\r | |
b522c77b HW |
311 | if (EFI_ERROR (Status)) {\r |
312 | return Status;\r | |
313 | }\r | |
314 | \r | |
ac0a286f MK |
315 | Private->BiosStart = (UINT32)(0x100000 - LegacyBiosImageSize);\r |
316 | Private->OptionRom = 0xc0000;\r | |
317 | Private->LegacyBiosImageSize = (UINT32)LegacyBiosImageSize;\r | |
b522c77b HW |
318 | \r |
319 | //\r | |
48cf40b8 | 320 | // Can only shadow into memory allocated for legacy usage.\r |
b522c77b HW |
321 | //\r |
322 | ASSERT (Private->BiosStart > Private->OptionRom);\r | |
323 | \r | |
324 | //\r | |
325 | // Shadow Legacy BIOS. Turn on memory and copy image\r | |
326 | //\r | |
327 | Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);\r | |
328 | \r | |
ac0a286f | 329 | ClearPtr = (VOID *)((UINTN)0xc0000);\r |
b522c77b HW |
330 | \r |
331 | //\r | |
332 | // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused\r | |
333 | // regions to be used by EMM386 etc.\r | |
334 | //\r | |
ac0a286f | 335 | SetMem ((VOID *)ClearPtr, (UINTN)(0x40000 - LegacyBiosImageSize), 0xff);\r |
b522c77b HW |
336 | \r |
337 | TempData = Private->BiosStart;\r | |
338 | \r | |
339 | CopyMem (\r | |
ac0a286f | 340 | (VOID *)TempData,\r |
b522c77b | 341 | LegacyBiosImage,\r |
ac0a286f | 342 | (UINTN)LegacyBiosImageSize\r |
b522c77b HW |
343 | );\r |
344 | \r | |
345 | Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);\r | |
346 | \r | |
347 | //\r | |
348 | // Search for Legacy16 table in Shadowed ROM\r | |
349 | //\r | |
350 | Done = FALSE;\r | |
351 | Table = NULL;\r | |
ac0a286f MK |
352 | for (Ptr = (UINT8 *)TempData; Ptr < (UINT8 *)((UINTN)0x100000) && !Done; Ptr += 0x10) {\r |
353 | if (*(UINT32 *)Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {\r | |
354 | Table = (EFI_COMPATIBILITY16_TABLE *)Ptr;\r | |
355 | PtrEnd = Ptr + Table->TableLength;\r | |
b522c77b | 356 | for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {\r |
ac0a286f | 357 | CheckSum = (UINT8)(CheckSum +*Ptr);\r |
b522c77b HW |
358 | }\r |
359 | \r | |
360 | Done = TRUE;\r | |
361 | }\r | |
362 | }\r | |
363 | \r | |
364 | if (Table == NULL) {\r | |
70d5086c | 365 | DEBUG ((DEBUG_ERROR, "No Legacy16 table found\n"));\r |
b522c77b HW |
366 | return EFI_NOT_FOUND;\r |
367 | }\r | |
368 | \r | |
369 | if (!Done) {\r | |
370 | //\r | |
371 | // Legacy16 table header checksum error.\r | |
372 | //\r | |
70d5086c | 373 | DEBUG ((DEBUG_ERROR, "Legacy16 table found with bad talbe header checksum\n"));\r |
b522c77b HW |
374 | }\r |
375 | \r | |
376 | //\r | |
377 | // Remember location of the Legacy16 table\r | |
378 | //\r | |
ac0a286f MK |
379 | Private->Legacy16Table = Table;\r |
380 | Private->Legacy16CallSegment = Table->Compatibility16CallSegment;\r | |
381 | Private->Legacy16CallOffset = Table->Compatibility16CallOffset;\r | |
382 | EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r | |
383 | Private->Legacy16InitPtr = EfiToLegacy16InitTable;\r | |
384 | Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;\r | |
385 | Private->InternalIrqRoutingTable = NULL;\r | |
386 | Private->NumberIrqRoutingEntries = 0;\r | |
387 | Private->BbsTablePtr = NULL;\r | |
388 | Private->LegacyEfiHddTable = NULL;\r | |
389 | Private->DiskEnd = 0;\r | |
390 | Private->Disk4075 = 0;\r | |
391 | Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;\r | |
392 | Private->NumberHddControllers = MAX_IDE_CONTROLLER;\r | |
393 | Private->Dump[0] = 'D';\r | |
394 | Private->Dump[1] = 'U';\r | |
395 | Private->Dump[2] = 'M';\r | |
396 | Private->Dump[3] = 'P';\r | |
b522c77b HW |
397 | \r |
398 | ZeroMem (\r | |
399 | Private->Legacy16BootPtr,\r | |
400 | sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)\r | |
401 | );\r | |
402 | \r | |
403 | //\r | |
404 | // Store away a copy of the EFI System Table\r | |
405 | //\r | |
ac0a286f | 406 | Table->EfiSystemTable = (UINT32)(UINTN)gST;\r |
b522c77b HW |
407 | \r |
408 | //\r | |
409 | // IPF CSM integration -Bug\r | |
410 | //\r | |
411 | // Construct the Legacy16 boot memory map. This sets up number of\r | |
412 | // E820 entries.\r | |
413 | //\r | |
414 | LegacyBiosBuildE820 (Private, &E820Size);\r | |
415 | //\r | |
416 | // Initialize BDA and EBDA standard values needed to load Legacy16 code\r | |
417 | //\r | |
418 | LegacyBiosInitBda (Private);\r | |
419 | LegacyBiosInitCmos (Private);\r | |
420 | \r | |
421 | //\r | |
422 | // All legacy interrupt should be masked when do initialization work from legacy 16 code.\r | |
423 | //\r | |
ac0a286f | 424 | Private->Legacy8259->GetMask (Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r |
b522c77b | 425 | NewMask = 0xFFFF;\r |
ac0a286f | 426 | Private->Legacy8259->SetMask (Private->Legacy8259, &NewMask, NULL, NULL, NULL);\r |
b522c77b HW |
427 | \r |
428 | //\r | |
429 | // Call into Legacy16 code to do an INIT\r | |
430 | //\r | |
431 | ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r | |
432 | Regs.X.AX = Legacy16InitializeYourself;\r | |
ac0a286f MK |
433 | Regs.X.ES = EFI_SEGMENT (*((UINT32 *)&EfiToLegacy16InitTable));\r |
434 | Regs.X.BX = EFI_OFFSET (*((UINT32 *)&EfiToLegacy16InitTable));\r | |
b522c77b HW |
435 | \r |
436 | Private->LegacyBios.FarCall86 (\r | |
ac0a286f MK |
437 | &Private->LegacyBios,\r |
438 | Table->Compatibility16CallSegment,\r | |
439 | Table->Compatibility16CallOffset,\r | |
440 | &Regs,\r | |
441 | NULL,\r | |
442 | 0\r | |
443 | );\r | |
b522c77b HW |
444 | \r |
445 | //\r | |
446 | // Restore original legacy interrupt mask value\r | |
447 | //\r | |
ac0a286f | 448 | Private->Legacy8259->SetMask (Private->Legacy8259, &OldMask, NULL, NULL, NULL);\r |
b522c77b HW |
449 | \r |
450 | if (Regs.X.AX != 0) {\r | |
451 | return EFI_DEVICE_ERROR;\r | |
452 | }\r | |
453 | \r | |
454 | //\r | |
455 | // start testtest\r | |
456 | // GetTimerValue (&Ticker);\r | |
457 | //\r | |
458 | // gRT->SetVariable (L"BackFromInitYourself",\r | |
459 | // &gEfiGlobalVariableGuid,\r | |
460 | // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
461 | // sizeof (UINT64),\r | |
462 | // (VOID *)&Ticker\r | |
463 | // );\r | |
464 | // end testtest\r | |
465 | //\r | |
466 | // Copy E820 table after InitializeYourself is completed\r | |
467 | //\r | |
468 | ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r | |
469 | Regs.X.AX = Legacy16GetTableAddress;\r | |
ac0a286f | 470 | Regs.X.CX = (UINT16)E820Size;\r |
b522c77b HW |
471 | Regs.X.DX = 1;\r |
472 | Private->LegacyBios.FarCall86 (\r | |
ac0a286f MK |
473 | &Private->LegacyBios,\r |
474 | Table->Compatibility16CallSegment,\r | |
475 | Table->Compatibility16CallOffset,\r | |
476 | &Regs,\r | |
477 | NULL,\r | |
478 | 0\r | |
479 | );\r | |
b522c77b | 480 | \r |
ac0a286f MK |
481 | Table->E820Pointer = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);\r |
482 | Table->E820Length = (UINT32)E820Size;\r | |
b522c77b | 483 | if (Regs.X.AX != 0) {\r |
70d5086c | 484 | DEBUG ((DEBUG_ERROR, "Legacy16 E820 length insufficient\n"));\r |
b522c77b HW |
485 | } else {\r |
486 | TempData = Table->E820Pointer;\r | |
ac0a286f | 487 | CopyMem ((VOID *)TempData, Private->E820Table, E820Size);\r |
b522c77b | 488 | }\r |
ac0a286f | 489 | \r |
b522c77b HW |
490 | //\r |
491 | // Get PnPInstallationCheck Info.\r | |
492 | //\r | |
ac0a286f MK |
493 | Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;\r |
494 | Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;\r | |
b522c77b HW |
495 | \r |
496 | //\r | |
497 | // Check if PCI Express is supported. If yes, Save base address.\r | |
498 | //\r | |
499 | Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r | |
500 | Private->LegacyBiosPlatform,\r | |
501 | EfiGetPlatformPciExpressBase,\r | |
502 | NULL,\r | |
503 | NULL,\r | |
504 | &Location,\r | |
505 | &Alignment,\r | |
506 | 0,\r | |
507 | 0\r | |
508 | );\r | |
509 | if (!EFI_ERROR (Status)) {\r | |
ac0a286f MK |
510 | Private->Legacy16Table->PciExpressBase = (UINT32)Location;\r |
511 | Location = 0;\r | |
b522c77b | 512 | }\r |
ac0a286f | 513 | \r |
b522c77b HW |
514 | //\r |
515 | // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it\r | |
516 | // into, copy it and update pointer to binary image. This needs to be\r | |
517 | // done prior to any OPROM for security purposes.\r | |
518 | //\r | |
519 | Status = Private->LegacyBiosPlatform->GetPlatformInfo (\r | |
520 | Private->LegacyBiosPlatform,\r | |
521 | EfiGetPlatformBinaryTpmBinary,\r | |
522 | &TpmBinaryImage,\r | |
523 | &TpmBinaryImageSize,\r | |
524 | &Location,\r | |
525 | &Alignment,\r | |
526 | 0,\r | |
527 | 0\r | |
528 | );\r | |
529 | if (!EFI_ERROR (Status)) {\r | |
b522c77b HW |
530 | ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));\r |
531 | Regs.X.AX = Legacy16GetTableAddress;\r | |
ac0a286f | 532 | Regs.X.CX = (UINT16)TpmBinaryImageSize;\r |
b522c77b HW |
533 | Regs.X.DX = 1;\r |
534 | Private->LegacyBios.FarCall86 (\r | |
ac0a286f MK |
535 | &Private->LegacyBios,\r |
536 | Table->Compatibility16CallSegment,\r | |
537 | Table->Compatibility16CallOffset,\r | |
538 | &Regs,\r | |
539 | NULL,\r | |
540 | 0\r | |
541 | );\r | |
542 | \r | |
543 | TpmPointer = (UINT32)(Regs.X.DS * 16 + Regs.X.BX);\r | |
b522c77b | 544 | if (Regs.X.AX != 0) {\r |
70d5086c | 545 | DEBUG ((DEBUG_ERROR, "TPM cannot be loaded\n"));\r |
b522c77b | 546 | } else {\r |
ac0a286f | 547 | CopyMem ((VOID *)(UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);\r |
b522c77b HW |
548 | Table->TpmSegment = Regs.X.DS;\r |
549 | Table->TpmOffset = Regs.X.BX;\r | |
b522c77b HW |
550 | }\r |
551 | }\r | |
ac0a286f | 552 | \r |
b522c77b HW |
553 | //\r |
554 | // Lock the Legacy BIOS region\r | |
555 | //\r | |
ac0a286f MK |
556 | Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32)LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);\r |
557 | Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32)LegacyBiosImageSize, &Granularity);\r | |
b522c77b HW |
558 | \r |
559 | //\r | |
560 | // Get the BbsTable from LOW_MEMORY_THUNK\r | |
561 | //\r | |
562 | BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;\r | |
563 | ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));\r | |
564 | \r | |
ac0a286f MK |
565 | EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;\r |
566 | Private->BbsTablePtr = (VOID *)BbsTable;\r | |
0ca62507 | 567 | \r |
b522c77b | 568 | //\r |
0ca62507 | 569 | // Populate entire table with BBS_IGNORE_ENTRY\r |
b522c77b | 570 | //\r |
0ca62507 | 571 | EfiToLegacy16BootTable->NumberBbsEntries = MAX_BBS_ENTRIES;\r |
b522c77b | 572 | \r |
0ca62507 | 573 | for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {\r |
b522c77b HW |
574 | BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;\r |
575 | }\r | |
ac0a286f | 576 | \r |
b522c77b HW |
577 | //\r |
578 | // Allocate space for Legacy HDD table\r | |
579 | //\r | |
ac0a286f | 580 | LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *)AllocateZeroPool ((UINTN)MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));\r |
b522c77b HW |
581 | ASSERT (LegacyEfiHddTable);\r |
582 | \r | |
583 | Private->LegacyEfiHddTable = LegacyEfiHddTable;\r | |
584 | Private->LegacyEfiHddTableIndex = 0x00;\r | |
585 | \r | |
586 | //\r | |
587 | // start testtest\r | |
588 | // GetTimerValue (&Ticker);\r | |
589 | //\r | |
590 | // gRT->SetVariable (L"EndOfLoadFv",\r | |
591 | // &gEfiGlobalVariableGuid,\r | |
592 | // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,\r | |
593 | // sizeof (UINT64),\r | |
594 | // (VOID *)&Ticker\r | |
595 | // );\r | |
596 | // end testtest\r | |
597 | //\r | |
598 | return EFI_SUCCESS;\r | |
599 | }\r | |
600 | \r | |
601 | /**\r | |
602 | Shadow all legacy16 OPROMs that haven't been shadowed.\r | |
603 | Warning: Use this with caution. This routine disconnects all EFI\r | |
604 | drivers. If used externally then caller must re-connect EFI\r | |
605 | drivers.\r | |
606 | \r | |
607 | @param This Protocol instance pointer.\r | |
608 | \r | |
609 | @retval EFI_SUCCESS OPROMs shadowed\r | |
610 | \r | |
611 | **/\r | |
612 | EFI_STATUS\r | |
613 | EFIAPI\r | |
614 | LegacyBiosShadowAllLegacyOproms (\r | |
ac0a286f | 615 | IN EFI_LEGACY_BIOS_PROTOCOL *This\r |
b522c77b HW |
616 | )\r |
617 | {\r | |
618 | LEGACY_BIOS_INSTANCE *Private;\r | |
619 | \r | |
620 | //\r | |
621 | // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;\r | |
622 | // EFI_LEGACY16_TABLE *Legacy16Table;\r | |
623 | //\r | |
624 | Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);\r | |
625 | \r | |
626 | //\r | |
627 | // LegacyBiosPlatform = Private->LegacyBiosPlatform;\r | |
628 | // Legacy16Table = Private->Legacy16Table;\r | |
629 | //\r | |
630 | // Shadow PCI ROMs. We must do this near the end since this will kick\r | |
631 | // of Native EFI drivers that may be needed to collect info for Legacy16\r | |
632 | //\r | |
633 | // WARNING: PciIo is gone after this call.\r | |
634 | //\r | |
635 | PciProgramAllInterruptLineRegisters (Private);\r | |
636 | \r | |
637 | PciShadowRoms (Private);\r | |
638 | \r | |
639 | //\r | |
640 | // Shadow PXE base code, BIS etc.\r | |
641 | //\r | |
642 | // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,\r | |
643 | // &Private->OptionRom,\r | |
644 | // Legacy16Table);\r | |
645 | //\r | |
646 | return EFI_SUCCESS;\r | |
647 | }\r | |
648 | \r | |
649 | /**\r | |
650 | Get the PCI BIOS interface version.\r | |
651 | \r | |
652 | @param Private Driver private data.\r | |
653 | \r | |
654 | @return The PCI interface version number in Binary Coded Decimal (BCD) format.\r | |
655 | E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00\r | |
656 | \r | |
657 | **/\r | |
658 | UINT16\r | |
659 | GetPciInterfaceVersion (\r | |
ac0a286f | 660 | IN LEGACY_BIOS_INSTANCE *Private\r |
b522c77b HW |
661 | )\r |
662 | {\r | |
ac0a286f MK |
663 | EFI_IA32_REGISTER_SET Reg;\r |
664 | BOOLEAN ThunkFailed;\r | |
665 | UINT16 PciInterfaceVersion;\r | |
b522c77b HW |
666 | \r |
667 | PciInterfaceVersion = 0;\r | |
668 | \r | |
ac0a286f | 669 | Reg.X.AX = 0xB101;\r |
b522c77b HW |
670 | Reg.E.EDI = 0;\r |
671 | \r | |
672 | ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);\r | |
673 | if (!ThunkFailed) {\r | |
674 | //\r | |
675 | // From PCI Firmware 3.0 Specification:\r | |
676 | // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the\r | |
677 | // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the\r | |
678 | // presence of the PCI function set. [BX] will further indicate the version level, with enough\r | |
679 | // granularity to allow for incremental changes in the code that don't affect the function interface.\r | |
680 | // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10\r | |
681 | // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.\r | |
682 | //\r | |
683 | if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {\r | |
684 | PciInterfaceVersion = Reg.X.BX;\r | |
685 | }\r | |
686 | }\r | |
ac0a286f | 687 | \r |
b522c77b HW |
688 | return PciInterfaceVersion;\r |
689 | }\r | |
690 | \r | |
691 | /**\r | |
692 | Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.\r | |
693 | SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.\r | |
694 | \r | |
695 | @param Event Event whose notification function is being invoked.\r | |
696 | @param Context The pointer to the notification function's context,\r | |
697 | which is implementation-dependent.\r | |
698 | \r | |
699 | **/\r | |
700 | VOID\r | |
701 | EFIAPI\r | |
702 | InstallSmbiosEventCallback (\r | |
ac0a286f MK |
703 | IN EFI_EVENT Event,\r |
704 | IN VOID *Context\r | |
b522c77b HW |
705 | )\r |
706 | {\r | |
ac0a286f MK |
707 | EFI_STATUS Status;\r |
708 | SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;\r | |
b522c77b HW |
709 | \r |
710 | //\r | |
711 | // Get SMBIOS table from EFI configuration table\r | |
712 | //\r | |
713 | Status = EfiGetSystemConfigurationTable (\r | |
ac0a286f MK |
714 | &gEfiSmbiosTableGuid,\r |
715 | &mRuntimeSmbiosEntryPoint\r | |
716 | );\r | |
b522c77b HW |
717 | if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {\r |
718 | return;\r | |
719 | }\r | |
720 | \r | |
ac0a286f | 721 | EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)mRuntimeSmbiosEntryPoint;\r |
b522c77b HW |
722 | \r |
723 | //\r | |
724 | // Allocate memory for SMBIOS Entry Point Structure.\r | |
725 | // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.\r | |
726 | //\r | |
727 | if (mReserveSmbiosEntryPoint == 0) {\r | |
728 | //\r | |
729 | // Entrypoint structure with fixed size is allocated only once.\r | |
730 | //\r | |
731 | mReserveSmbiosEntryPoint = SIZE_4GB - 1;\r | |
ac0a286f MK |
732 | Status = gBS->AllocatePages (\r |
733 | AllocateMaxAddress,\r | |
734 | EfiReservedMemoryType,\r | |
735 | EFI_SIZE_TO_PAGES ((UINTN)(EntryPointStructure->EntryPointLength)),\r | |
736 | &mReserveSmbiosEntryPoint\r | |
737 | );\r | |
b522c77b HW |
738 | if (EFI_ERROR (Status)) {\r |
739 | mReserveSmbiosEntryPoint = 0;\r | |
740 | return;\r | |
741 | }\r | |
ac0a286f | 742 | \r |
70d5086c | 743 | DEBUG ((DEBUG_INFO, "Allocate memory for Smbios Entry Point Structure\n"));\r |
b522c77b HW |
744 | }\r |
745 | \r | |
746 | if ((mStructureTableAddress != 0) &&\r | |
ac0a286f MK |
747 | (mStructureTablePages < EFI_SIZE_TO_PAGES ((UINT32)EntryPointStructure->TableLength)))\r |
748 | {\r | |
b522c77b HW |
749 | //\r |
750 | // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate\r | |
751 | //\r | |
752 | gBS->FreePages (mStructureTableAddress, mStructureTablePages);\r | |
753 | mStructureTableAddress = 0;\r | |
754 | mStructureTablePages = 0;\r | |
70d5086c | 755 | DEBUG ((DEBUG_INFO, "Original size is not enough. Re-allocate the memory.\n"));\r |
b522c77b HW |
756 | }\r |
757 | \r | |
758 | if (mStructureTableAddress == 0) {\r | |
759 | //\r | |
760 | // Allocate reserved memory below 4GB.\r | |
761 | // Smbios spec requires the structure table is below 4GB.\r | |
762 | //\r | |
763 | mStructureTableAddress = SIZE_4GB - 1;\r | |
764 | mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);\r | |
ac0a286f MK |
765 | Status = gBS->AllocatePages (\r |
766 | AllocateMaxAddress,\r | |
767 | EfiReservedMemoryType,\r | |
768 | mStructureTablePages,\r | |
769 | &mStructureTableAddress\r | |
770 | );\r | |
b522c77b HW |
771 | if (EFI_ERROR (Status)) {\r |
772 | gBS->FreePages (\r | |
ac0a286f MK |
773 | mReserveSmbiosEntryPoint,\r |
774 | EFI_SIZE_TO_PAGES ((UINTN)(EntryPointStructure->EntryPointLength))\r | |
775 | );\r | |
b522c77b HW |
776 | mReserveSmbiosEntryPoint = 0;\r |
777 | mStructureTableAddress = 0;\r | |
778 | mStructureTablePages = 0;\r | |
779 | return;\r | |
780 | }\r | |
ac0a286f | 781 | \r |
70d5086c | 782 | DEBUG ((DEBUG_INFO, "Allocate memory for Smbios Structure Table\n"));\r |
b522c77b HW |
783 | }\r |
784 | }\r | |
785 | \r | |
786 | /**\r | |
787 | Callback function to toggle EndOfDxe status. NULL pointer detection needs\r | |
788 | this status to decide if it's necessary to change attributes of page 0.\r | |
789 | \r | |
790 | @param Event Event whose notification function is being invoked.\r | |
791 | @param Context The pointer to the notification function's context,\r | |
792 | which is implementation-dependent.\r | |
793 | \r | |
794 | **/\r | |
795 | VOID\r | |
796 | EFIAPI\r | |
797 | ToggleEndOfDxeStatus (\r | |
ac0a286f MK |
798 | IN EFI_EVENT Event,\r |
799 | IN VOID *Context\r | |
b522c77b HW |
800 | )\r |
801 | {\r | |
802 | mEndOfDxe = TRUE;\r | |
803 | return;\r | |
804 | }\r | |
805 | \r | |
806 | /**\r | |
807 | Install Driver to produce Legacy BIOS protocol.\r | |
808 | \r | |
809 | @param ImageHandle Handle of driver image.\r | |
810 | @param SystemTable Pointer to system table.\r | |
811 | \r | |
812 | @retval EFI_SUCCESS Legacy BIOS protocol installed\r | |
813 | @retval No protocol installed, unload driver.\r | |
814 | \r | |
815 | **/\r | |
816 | EFI_STATUS\r | |
817 | EFIAPI\r | |
818 | LegacyBiosInstall (\r | |
ac0a286f MK |
819 | IN EFI_HANDLE ImageHandle,\r |
820 | IN EFI_SYSTEM_TABLE *SystemTable\r | |
b522c77b HW |
821 | )\r |
822 | {\r | |
823 | EFI_STATUS Status;\r | |
824 | LEGACY_BIOS_INSTANCE *Private;\r | |
825 | EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;\r | |
826 | EFI_PHYSICAL_ADDRESS MemoryAddress;\r | |
827 | EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;\r | |
828 | VOID *MemoryPtr;\r | |
829 | EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;\r | |
830 | UINTN Index;\r | |
831 | UINT32 *BaseVectorMaster;\r | |
832 | EFI_PHYSICAL_ADDRESS StartAddress;\r | |
833 | UINT32 *ClearPtr;\r | |
834 | EFI_PHYSICAL_ADDRESS MemStart;\r | |
835 | UINT32 IntRedirCode;\r | |
836 | UINT32 Granularity;\r | |
837 | BOOLEAN DecodeOn;\r | |
838 | UINT32 MemorySize;\r | |
839 | EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;\r | |
840 | UINT64 Length;\r | |
841 | UINT8 *SecureBoot;\r | |
842 | EFI_EVENT InstallSmbiosEvent;\r | |
843 | EFI_EVENT EndOfDxeEvent;\r | |
844 | \r | |
845 | //\r | |
846 | // Load this driver's image to memory\r | |
847 | //\r | |
848 | Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);\r | |
849 | if (EFI_ERROR (Status)) {\r | |
850 | return Status;\r | |
851 | }\r | |
852 | \r | |
853 | //\r | |
854 | // When UEFI Secure Boot is enabled, CSM module will not start any more.\r | |
855 | //\r | |
856 | SecureBoot = NULL;\r | |
ac0a286f | 857 | GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID **)&SecureBoot, NULL);\r |
b522c77b HW |
858 | if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {\r |
859 | FreePool (SecureBoot);\r | |
860 | return EFI_SECURITY_VIOLATION;\r | |
861 | }\r | |
862 | \r | |
863 | if (SecureBoot != NULL) {\r | |
864 | FreePool (SecureBoot);\r | |
865 | }\r | |
866 | \r | |
867 | Private = &mPrivateData;\r | |
868 | ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));\r | |
869 | \r | |
870 | //\r | |
871 | // Grab a copy of all the protocols we depend on. Any error would\r | |
872 | // be a dispatcher bug!.\r | |
873 | //\r | |
ac0a286f | 874 | Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **)&Private->Cpu);\r |
b522c77b HW |
875 | ASSERT_EFI_ERROR (Status);\r |
876 | \r | |
ac0a286f | 877 | Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **)&Private->Timer);\r |
b522c77b HW |
878 | ASSERT_EFI_ERROR (Status);\r |
879 | \r | |
ac0a286f | 880 | Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **)&Private->LegacyRegion);\r |
b522c77b HW |
881 | ASSERT_EFI_ERROR (Status);\r |
882 | \r | |
ac0a286f | 883 | Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **)&Private->LegacyBiosPlatform);\r |
b522c77b HW |
884 | ASSERT_EFI_ERROR (Status);\r |
885 | \r | |
ac0a286f | 886 | Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **)&Private->Legacy8259);\r |
b522c77b HW |
887 | ASSERT_EFI_ERROR (Status);\r |
888 | \r | |
ac0a286f | 889 | Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **)&Private->LegacyInterrupt);\r |
b522c77b HW |
890 | ASSERT_EFI_ERROR (Status);\r |
891 | \r | |
892 | //\r | |
893 | // Locate Memory Test Protocol if exists\r | |
894 | //\r | |
895 | Status = gBS->LocateProtocol (\r | |
896 | &gEfiGenericMemTestProtocolGuid,\r | |
897 | NULL,\r | |
ac0a286f | 898 | (VOID **)&Private->GenericMemoryTest\r |
b522c77b HW |
899 | );\r |
900 | ASSERT_EFI_ERROR (Status);\r | |
901 | \r | |
902 | //\r | |
903 | // Make sure all memory from 0-640K is tested\r | |
904 | //\r | |
905 | for (StartAddress = 0; StartAddress < 0xa0000; ) {\r | |
906 | gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r | |
907 | if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r | |
908 | StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r | |
909 | continue;\r | |
910 | }\r | |
ac0a286f | 911 | \r |
b522c77b HW |
912 | Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);\r |
913 | Private->GenericMemoryTest->CompatibleRangeTest (\r | |
914 | Private->GenericMemoryTest,\r | |
915 | StartAddress,\r | |
916 | Length\r | |
917 | );\r | |
918 | StartAddress = StartAddress + Length;\r | |
919 | }\r | |
ac0a286f | 920 | \r |
b522c77b HW |
921 | //\r |
922 | // Make sure all memory from 1MB to 16MB is tested and added to memory map\r | |
923 | //\r | |
924 | for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {\r | |
925 | gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);\r | |
926 | if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {\r | |
927 | StartAddress = Descriptor.BaseAddress + Descriptor.Length;\r | |
928 | continue;\r | |
929 | }\r | |
ac0a286f | 930 | \r |
b522c77b HW |
931 | Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);\r |
932 | Private->GenericMemoryTest->CompatibleRangeTest (\r | |
933 | Private->GenericMemoryTest,\r | |
934 | StartAddress,\r | |
935 | Length\r | |
936 | );\r | |
937 | StartAddress = StartAddress + Length;\r | |
938 | }\r | |
939 | \r | |
940 | Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;\r | |
941 | \r | |
ac0a286f MK |
942 | Private->LegacyBios.Int86 = LegacyBiosInt86;\r |
943 | Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;\r | |
944 | Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;\r | |
945 | Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;\r | |
946 | Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;\r | |
947 | Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;\r | |
948 | Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;\r | |
949 | Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;\r | |
950 | Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;\r | |
951 | Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;\r | |
952 | Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;\r | |
b522c77b HW |
953 | Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;\r |
954 | \r | |
955 | Private->ImageHandle = ImageHandle;\r | |
956 | \r | |
957 | //\r | |
958 | // Enable read attribute of legacy region.\r | |
959 | //\r | |
960 | DecodeOn = TRUE;\r | |
961 | Private->LegacyRegion->Decode (\r | |
962 | Private->LegacyRegion,\r | |
963 | 0xc0000,\r | |
964 | 0x40000,\r | |
965 | &Granularity,\r | |
966 | &DecodeOn\r | |
967 | );\r | |
968 | //\r | |
969 | // Set Cachebility for legacy region\r | |
970 | // BUGBUG: Comments about this legacy region cacheability setting\r | |
971 | // This setting will make D865GCHProduction CSM Unhappy\r | |
972 | //\r | |
973 | if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {\r | |
974 | gDS->SetMemorySpaceAttributes (\r | |
975 | 0x0,\r | |
976 | 0xA0000,\r | |
977 | EFI_MEMORY_WB\r | |
978 | );\r | |
979 | gDS->SetMemorySpaceAttributes (\r | |
980 | 0xc0000,\r | |
981 | 0x40000,\r | |
982 | EFI_MEMORY_WB\r | |
983 | );\r | |
984 | }\r | |
985 | \r | |
986 | gDS->SetMemorySpaceAttributes (\r | |
987 | 0xA0000,\r | |
988 | 0x20000,\r | |
989 | EFI_MEMORY_UC\r | |
990 | );\r | |
991 | \r | |
992 | //\r | |
48cf40b8 | 993 | // Allocate 0 - 4K for real mode interrupt vectors and BDA.\r |
b522c77b HW |
994 | //\r |
995 | AllocateLegacyMemory (\r | |
996 | AllocateAddress,\r | |
997 | EfiReservedMemoryType,\r | |
998 | 0,\r | |
999 | 1,\r | |
1000 | &MemoryAddress\r | |
1001 | );\r | |
1002 | ASSERT (MemoryAddress == 0x000000000);\r | |
1003 | \r | |
ac0a286f | 1004 | ClearPtr = (VOID *)((UINTN)0x0000);\r |
b522c77b HW |
1005 | \r |
1006 | //\r | |
1007 | // Initialize region from 0x0000 to 4k. This initializes interrupt vector\r | |
1008 | // range.\r | |
1009 | //\r | |
1010 | ACCESS_PAGE0_CODE (\r | |
ac0a286f MK |
1011 | gBS->SetMem ((VOID *)ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);\r |
1012 | ZeroMem ((VOID *)((UINTN)ClearPtr + 0x400), 0xC00);\r | |
1013 | );\r | |
b522c77b HW |
1014 | \r |
1015 | //\r | |
1016 | // Allocate pages for OPROM usage\r | |
1017 | //\r | |
1018 | MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);\r | |
1019 | ASSERT ((MemorySize & 0xFFF) == 0);\r | |
1020 | \r | |
1021 | Status = AllocateLegacyMemory (\r | |
1022 | AllocateAddress,\r | |
1023 | EfiReservedMemoryType,\r | |
1024 | CONVENTIONAL_MEMORY_TOP - MemorySize,\r | |
1025 | EFI_SIZE_TO_PAGES (MemorySize),\r | |
1026 | &MemoryAddress\r | |
1027 | );\r | |
1028 | ASSERT_EFI_ERROR (Status);\r | |
1029 | \r | |
ac0a286f | 1030 | ZeroMem ((VOID *)((UINTN)MemoryAddress), MemorySize);\r |
b522c77b HW |
1031 | \r |
1032 | //\r | |
1033 | // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that\r | |
1034 | // don't use PMM but look for zeroed memory. Note that various non-BBS\r | |
1035 | // OpROMs expect different areas to be free\r | |
1036 | //\r | |
1037 | EbdaReservedBaseAddress = MemoryAddress;\r | |
ac0a286f MK |
1038 | MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);\r |
1039 | MemorySize = PcdGet32 (PcdOpromReservedMemorySize);\r | |
b522c77b HW |
1040 | //\r |
1041 | // Check if base address and size for reserved memory are 4KB aligned.\r | |
1042 | //\r | |
1043 | ASSERT ((MemoryAddress & 0xFFF) == 0);\r | |
1044 | ASSERT ((MemorySize & 0xFFF) == 0);\r | |
1045 | //\r | |
1046 | // Check if the reserved memory is below EBDA reserved range.\r | |
1047 | //\r | |
1048 | ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));\r | |
1049 | for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {\r | |
1050 | Status = AllocateLegacyMemory (\r | |
1051 | AllocateAddress,\r | |
1052 | EfiBootServicesCode,\r | |
1053 | MemStart,\r | |
1054 | 1,\r | |
1055 | &StartAddress\r | |
1056 | );\r | |
1057 | if (!EFI_ERROR (Status)) {\r | |
ac0a286f | 1058 | MemoryPtr = (VOID *)((UINTN)StartAddress);\r |
b522c77b HW |
1059 | ZeroMem (MemoryPtr, 0x1000);\r |
1060 | } else {\r | |
70d5086c | 1061 | DEBUG ((DEBUG_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));\r |
b522c77b HW |
1062 | }\r |
1063 | }\r | |
1064 | \r | |
1065 | //\r | |
1066 | // Allocate low PMM memory and zero it out\r | |
1067 | //\r | |
1068 | MemorySize = PcdGet32 (PcdLowPmmMemorySize);\r | |
1069 | ASSERT ((MemorySize & 0xFFF) == 0);\r | |
1070 | Status = AllocateLegacyMemory (\r | |
1071 | AllocateMaxAddress,\r | |
1072 | EfiBootServicesCode,\r | |
1073 | CONVENTIONAL_MEMORY_TOP,\r | |
1074 | EFI_SIZE_TO_PAGES (MemorySize),\r | |
1075 | &MemoryAddressUnder1MB\r | |
1076 | );\r | |
1077 | ASSERT_EFI_ERROR (Status);\r | |
1078 | \r | |
ac0a286f | 1079 | ZeroMem ((VOID *)((UINTN)MemoryAddressUnder1MB), MemorySize);\r |
b522c77b HW |
1080 | \r |
1081 | //\r | |
1082 | // Allocate space for thunker and Init Thunker\r | |
1083 | //\r | |
1084 | Status = AllocateLegacyMemory (\r | |
1085 | AllocateMaxAddress,\r | |
1086 | EfiReservedMemoryType,\r | |
1087 | CONVENTIONAL_MEMORY_TOP,\r | |
1088 | (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,\r | |
1089 | &MemoryAddress\r | |
1090 | );\r | |
1091 | ASSERT_EFI_ERROR (Status);\r | |
ac0a286f | 1092 | Private->IntThunk = (LOW_MEMORY_THUNK *)(UINTN)MemoryAddress;\r |
b522c77b | 1093 | EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;\r |
ac0a286f MK |
1094 | EfiToLegacy16InitTable->ThunkStart = (UINT32)(EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;\r |
1095 | EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32)(sizeof (LOW_MEMORY_THUNK));\r | |
b522c77b HW |
1096 | \r |
1097 | Status = LegacyBiosInitializeThunk (Private);\r | |
1098 | ASSERT_EFI_ERROR (Status);\r | |
1099 | \r | |
1100 | //\r | |
1101 | // Init the legacy memory map in memory < 1 MB.\r | |
1102 | //\r | |
ac0a286f MK |
1103 | EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32)MemoryAddressUnder1MB;\r |
1104 | EfiToLegacy16InitTable->LowPmmMemory = (UINT32)MemoryAddressUnder1MB;\r | |
b522c77b HW |
1105 | EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;\r |
1106 | \r | |
1107 | MemorySize = PcdGet32 (PcdHighPmmMemorySize);\r | |
1108 | ASSERT ((MemorySize & 0xFFF) == 0);\r | |
1109 | //\r | |
1110 | // Allocate high PMM Memory under 16 MB\r | |
1111 | //\r | |
1112 | Status = AllocateLegacyMemory (\r | |
1113 | AllocateMaxAddress,\r | |
1114 | EfiBootServicesCode,\r | |
1115 | 0x1000000,\r | |
1116 | EFI_SIZE_TO_PAGES (MemorySize),\r | |
1117 | &MemoryAddress\r | |
1118 | );\r | |
1119 | if (EFI_ERROR (Status)) {\r | |
1120 | //\r | |
1121 | // If it fails, allocate high PMM Memory under 4GB\r | |
1122 | //\r | |
1123 | Status = AllocateLegacyMemory (\r | |
1124 | AllocateMaxAddress,\r | |
1125 | EfiBootServicesCode,\r | |
1126 | 0xFFFFFFFF,\r | |
1127 | EFI_SIZE_TO_PAGES (MemorySize),\r | |
1128 | &MemoryAddress\r | |
1129 | );\r | |
1130 | }\r | |
ac0a286f | 1131 | \r |
b522c77b | 1132 | if (!EFI_ERROR (Status)) {\r |
ac0a286f | 1133 | EfiToLegacy16InitTable->HiPmmMemory = (UINT32)(EFI_PHYSICAL_ADDRESS)(UINTN)MemoryAddress;\r |
b522c77b HW |
1134 | EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;\r |
1135 | }\r | |
1136 | \r | |
1137 | //\r | |
1138 | // ShutdownAPs();\r | |
1139 | //\r | |
1140 | // Start the Legacy BIOS;\r | |
1141 | //\r | |
1142 | Status = ShadowAndStartLegacy16 (Private);\r | |
1143 | if (EFI_ERROR (Status)) {\r | |
1144 | return Status;\r | |
1145 | }\r | |
ac0a286f | 1146 | \r |
b522c77b HW |
1147 | //\r |
1148 | // Initialize interrupt redirection code and entries;\r | |
1149 | // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.\r | |
1150 | //\r | |
1151 | CopyMem (\r | |
ac0a286f MK |
1152 | Private->IntThunk->InterruptRedirectionCode,\r |
1153 | (VOID *)(UINTN)InterruptRedirectionTemplate,\r | |
1154 | sizeof (Private->IntThunk->InterruptRedirectionCode)\r | |
1155 | );\r | |
b522c77b HW |
1156 | \r |
1157 | //\r | |
1158 | // Save Unexpected interrupt vector so can restore it just prior to boot\r | |
1159 | //\r | |
1160 | ACCESS_PAGE0_CODE (\r | |
ac0a286f | 1161 | BaseVectorMaster = (UINT32 *)(sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);\r |
b522c77b | 1162 | Private->BiosUnexpectedInt = BaseVectorMaster[0];\r |
ac0a286f | 1163 | IntRedirCode = (UINT32)(UINTN)Private->IntThunk->InterruptRedirectionCode;\r |
b522c77b | 1164 | for (Index = 0; Index < 8; Index++) {\r |
ac0a286f MK |
1165 | BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);\r |
1166 | }\r | |
1167 | \r | |
1168 | );\r | |
b522c77b HW |
1169 | \r |
1170 | //\r | |
1171 | // Save EFI value\r | |
1172 | //\r | |
ac0a286f | 1173 | Private->ThunkSeg = (UINT16)(EFI_SEGMENT (IntRedirCode));\r |
b522c77b HW |
1174 | \r |
1175 | //\r | |
1176 | // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists\r | |
1177 | //\r | |
1178 | InstallSmbiosEventCallback (NULL, NULL);\r | |
1179 | \r | |
1180 | //\r | |
1181 | // Create callback function to update the size of reserved memory after LegacyBiosDxe starts\r | |
1182 | //\r | |
1183 | Status = gBS->CreateEventEx (\r | |
1184 | EVT_NOTIFY_SIGNAL,\r | |
1185 | TPL_NOTIFY,\r | |
1186 | InstallSmbiosEventCallback,\r | |
1187 | NULL,\r | |
1188 | &gEfiSmbiosTableGuid,\r | |
1189 | &InstallSmbiosEvent\r | |
1190 | );\r | |
1191 | ASSERT_EFI_ERROR (Status);\r | |
1192 | \r | |
1193 | //\r | |
1194 | // Create callback to update status of EndOfDxe, which is needed by NULL\r | |
1195 | // pointer detection\r | |
1196 | //\r | |
1197 | Status = gBS->CreateEventEx (\r | |
1198 | EVT_NOTIFY_SIGNAL,\r | |
1199 | TPL_NOTIFY,\r | |
1200 | ToggleEndOfDxeStatus,\r | |
1201 | NULL,\r | |
1202 | &gEfiEndOfDxeEventGroupGuid,\r | |
1203 | &EndOfDxeEvent\r | |
1204 | );\r | |
1205 | ASSERT_EFI_ERROR (Status);\r | |
1206 | \r | |
1207 | //\r | |
1208 | // Make a new handle and install the protocol\r | |
1209 | //\r | |
1210 | Private->Handle = NULL;\r | |
ac0a286f MK |
1211 | Status = gBS->InstallProtocolInterface (\r |
1212 | &Private->Handle,\r | |
1213 | &gEfiLegacyBiosProtocolGuid,\r | |
1214 | EFI_NATIVE_INTERFACE,\r | |
1215 | &Private->LegacyBios\r | |
1216 | );\r | |
b522c77b HW |
1217 | Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);\r |
1218 | \r | |
ac0a286f MK |
1219 | DEBUG ((\r |
1220 | DEBUG_INFO,\r | |
1221 | "CSM16 PCI BIOS Interface Version: %02x.%02x\n",\r | |
1222 | (UINT8)(Private->Csm16PciInterfaceVersion >> 8),\r | |
1223 | (UINT8)Private->Csm16PciInterfaceVersion\r | |
1224 | ));\r | |
b522c77b HW |
1225 | ASSERT (Private->Csm16PciInterfaceVersion != 0);\r |
1226 | return Status;\r | |
1227 | }\r |