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