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