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