]> git.proxmox.com Git - mirror_edk2.git/blame - OvmfPkg/Csm/LegacyBiosDxe/LegacyBios.c
UefiCpuPkg: Move AsmRelocateApLoopStart from Mpfuncs.nasm to AmdSev.nasm
[mirror_edk2.git] / OvmfPkg / Csm / LegacyBiosDxe / LegacyBios.c
CommitLineData
b522c77b
HW
1/** @file\r
2\r
3Copyright (c) 2006 - 2018, Intel Corporation. All rights reserved.<BR>\r
4\r
5SPDX-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
23LEGACY_BIOS_INSTANCE mPrivateData;\r
24\r
25//\r
26// The SMBIOS table in EfiRuntimeServicesData memory\r
27//\r
ac0a286f 28VOID *mRuntimeSmbiosEntryPoint = NULL;\r
b522c77b
HW
29\r
30//\r
31// The SMBIOS table in EfiReservedMemoryType memory\r
32//\r
33EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;\r
34EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;\r
35UINTN mStructureTablePages = 0;\r
36BOOLEAN 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
51EFI_STATUS\r
52AllocateLegacyMemory (\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
126EFI_STATUS\r
127EFIAPI\r
128LegacyBiosGetLegacyRegion (\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
185EFI_STATUS\r
186EFIAPI\r
187LegacyBiosCopyLegacyRegion (\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
229EFI_STATUS\r
230ShadowAndStartLegacy16 (\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
612EFI_STATUS\r
613EFIAPI\r
614LegacyBiosShadowAllLegacyOproms (\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
658UINT16\r
659GetPciInterfaceVersion (\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
700VOID\r
701EFIAPI\r
702InstallSmbiosEventCallback (\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
795VOID\r
796EFIAPI\r
797ToggleEndOfDxeStatus (\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
816EFI_STATUS\r
817EFIAPI\r
818LegacyBiosInstall (\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