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