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