summaryrefslogtreecommitdiff
path: root/Core
diff options
context:
space:
mode:
authorGuo Mang <mang.guo@intel.com>2016-12-22 16:12:38 +0800
committerGuo Mang <mang.guo@intel.com>2016-12-26 19:14:44 +0800
commitd90e91b58c592155171c7ccc70e8172a5609f913 (patch)
treeed0d9f888be9c1069d36802ad51e9c43c5a47c5a /Core
parente76e21b0157d80044d202c9dcb1b3b679bbbce02 (diff)
downloadedk2-platforms-d90e91b58c592155171c7ccc70e8172a5609f913.tar.xz
IntelFrameworkModulePkg: Move to new location
Contributed-under: TianoCore Contribution Agreement 1.0 Signed-off-by: Guo Mang <mang.guo@intel.com>
Diffstat (limited to 'Core')
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c182
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h148
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaBus.h297
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaIo.h331
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c673
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf73
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.unibin0 -> 2658 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.unibin0 -> 1336 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c1463
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.c249
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.h146
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.c515
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.h1093
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyBlock.c375
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c1398
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf78
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.unibin0 -> 2444 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxeExtra.unibin0 -> 1348 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/Fdc.h235
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.c1759
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.h246
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.inf73
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.unibin0 -> 2348 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPeiExtra.unibin0 -> 1358 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.c182
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.h148
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.c326
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.h263
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c1803
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.h331
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.inf71
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.unibin0 -> 2414 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxeExtra.unibin0 -> 1334 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/ComponentName.c272
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf80
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.unibin0 -> 2094 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxeExtra.unibin0 -> 1366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c2038
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.h842
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c372
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c1908
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c683
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c642
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h550
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.unibin0 -> 1928 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.unibin0 -> 1358 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf85
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.c923
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.h435
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/ComponentName.c241
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.c778
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.h400
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf77
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.unibin0 -> 2064 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxeExtra.unibin0 -> 1394 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c921
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h435
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c241
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c792
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h400
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf76
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.unibin0 -> 1628 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.unibin0 -> 1346 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c2799
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c1952
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c278
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h166
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c292
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c245
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c1330
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.h835
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.c1571
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.h540
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf88
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.unibin0 -> 1764 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxeExtra.unibin0 -> 1328 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeData.h311
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/ComponentName.c168
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.c331
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.h271
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.unibin0 -> 2038 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf57
-rw-r--r--Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortExtra.unibin0 -> 1352 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Contributions.txt218
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c780
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h432
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c1495
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf65
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.unibin0 -> 2138 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxeExtra.unibin0 -> 1366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c309
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h209
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c2428
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h743
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c183
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h153
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf77
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.unibin0 -> 2044 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxeExtra.unibin0 -> 1366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c3522
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h1655
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.unibin0 -> 1824 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16Extra.unibin0 -> 1392 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c309
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c962
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h613
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c1254
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf73
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c3296
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h539
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.unibin0 -> 1984 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.unibin0 -> 1362 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c313
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h466
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf87
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S67
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm73
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c277
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h102
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i89
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s524
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c550
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c384
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c66
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c1154
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf150
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.unibin0 -> 1848 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.unibin0 -> 1378 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h1541
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c2165
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c124
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c317
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c3007
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c234
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c419
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S72
-rw-r--r--Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm71
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/AcpiVariableCompatibility.h69
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/BdsHii.h55
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/BdsLibHii.h25
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/BlockIoVendor.h31
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/CapsuleDataFile.h23
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/DataHubStatusCodeRecord.h61
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/HdBootVariable.h31
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/IntelFrameworkModulePkgTokenSpace.h27
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/LastEnumLang.h31
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h36
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/LegacyDevOrder.h45
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Guid/TianoDecompress.h28
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Library/GenericBdsLib.h1114
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Library/PlatformBdsLib.h156
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/ExitPmAuth.h25
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/IsaAcpi.h304
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/IsaIo.h362
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/OEMBadging.h88
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/Ps2Policy.h41
-rw-r--r--Core/IntelFrameworkModulePkg/Include/Protocol/VgaMiniPort.h94
-rw-r--r--Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec283
-rw-r--r--Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc198
-rw-r--r--Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.unibin0 -> 37484 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/IntelFrameworkModulePkgExtra.unibin0 -> 1398 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.c1050
-rw-r--r--Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf48
-rw-r--r--Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLibInternals.h220
-rw-r--r--Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoDecompressLib.unibin0 -> 2040 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c518
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf55
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.unibin0 -> 1840 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf58
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.unibin0 -> 1986 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/ReportStatusCodeLib.c634
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c4356
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c435
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c1301
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c1589
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c33
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf145
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.unibin0 -> 2378 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.unibin0 -> 3852 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h194
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c313
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c32
-rw-r--r--Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h48
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.c1456
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.h255
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf69
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.unibin0 -> 1800 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.unibin0 -> 6380 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr73
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h85
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h66
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c1536
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf64
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.unibin0 -> 1736 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c218
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c201
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt4
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf66
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.unibin0 -> 2480 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf62
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c220
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.unibin0 -> 2274 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h96
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h7
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h60
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c85
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h69
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c770
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h107
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h54
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c1026
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h223
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h231
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt236
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt594
-rw-r--r--Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h47
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c468
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf54
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.unibin0 -> 1896 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.c50
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.inf50
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.unibin0 -> 2272 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.c51
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.inf49
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.unibin0 -> 2392 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c187
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h28
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLib.unibin0 -> 1880 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf47
-rw-r--r--Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformData.c21
-rw-r--r--Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLib.c493
-rw-r--r--Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLibInternal.h73
-rw-r--r--Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.inf73
-rw-r--r--Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.unibin0 -> 2844 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeSupport.c335
-rw-r--r--Core/IntelFrameworkModulePkg/License.txt25
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c643
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h59
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf89
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.unibin0 -> 1916 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxeExtra.unibin0 -> 1368 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c224
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.c91
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.h166
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportAcpiSupportProtocol.c1918
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.inf81
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.unibin0 -> 2246 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxeExtra.unibin0 -> 1366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h237
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf228
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.unibin0 -> 5172 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxeExtra.unibin0 -> 1370 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c754
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c254
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h82
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr365
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BmLib.c411
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bmstring.unibin0 -> 38776 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c1690
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h1679
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c1823
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c1198
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Data.c332
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FE.vfr127
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c469
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h243
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c1391
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Variable.c1380
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.c399
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.h103
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.unibin0 -> 3344 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr50
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c233
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c2591
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h523
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.unibin0 -> 13366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr93
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.h56
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DriverHealthVfr.Vfr38
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.c1480
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.h254
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageStrings.unibin0 -> 9974 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr137
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.c597
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.h67
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.c48
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.h32
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.c499
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.h51
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/MemoryTest.c436
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.c59
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.h65
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/BdsDxe/Strings.unibin0 -> 7444 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/ComponentName.c167
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.c1288
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.h484
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf64
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.unibin0 -> 2006 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxeExtra.unibin0 -> 1346 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.c536
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.h226
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf51
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.unibin0 -> 2066 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxeExtra.unibin0 -> 1338 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.c587
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.h131
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf85
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.unibin0 -> 8204 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxeExtra.unibin0 -> 1332 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErr.c151
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf57
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.unibin0 -> 1992 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxeExtra.unibin0 -> 1358 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c608
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c1228
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c798
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c220
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h761
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf74
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.unibin0 -> 1960 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxeExtra.unibin0 -> 1354 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c629
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c1586
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c1218
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c1133
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c846
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h213
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf76
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.unibin0 -> 2360 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxeExtra.unibin0 -> 1366 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.unibin0 -> 2410 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegion.c170
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf55
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.unibin0 -> 3044 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxeExtra.unibin0 -> 1362 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtraction.c1456
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf57
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.unibin0 -> 2552 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.unibin0 -> 1400 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DataHubStatusCodeWorker.c376
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.c88
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.h91
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf72
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.unibin0 -> 1782 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxeExtra.unibin0 -> 1390 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/MemoryStausCodeWorker.c118
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/SerialStatusCodeWorker.c162
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.c146
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.h147
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.inf78
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.unibin0 -> 1718 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePeiExtra.unibin0 -> 1344 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/DataHubStatusCodeWorker.c390
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/RtMemoryStatusCodeWorker.c104
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/SerialStatusCodeWorker.c160
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.c301
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.h240
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf88
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.unibin0 -> 1886 bytes
-rw-r--r--Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxeExtra.unibin0 -> 1374 bytes
360 files changed, 133851 insertions, 0 deletions
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c
new file mode 100644
index 0000000000..1663d7fcd5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.c
@@ -0,0 +1,182 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for IsaBus driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalIsaBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIsaBusComponentName = {
+ IsaBusComponentNameGetDriverName,
+ IsaBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIsaBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IsaBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IsaBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIsaBusDriverNameTable[] = {
+ {
+ "eng;en",
+ L"ISA Bus Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIsaBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gIsaBusComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h
new file mode 100644
index 0000000000..ffacf44063
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/ComponentName.h
@@ -0,0 +1,148 @@
+/** @file
+ Header file for implementation of UEFI Component Name(2) protocol.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIsaBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gIsaBusComponentName2;
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaBus.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaBus.h
new file mode 100644
index 0000000000..9e559da72b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaBus.h
@@ -0,0 +1,297 @@
+/** @file
+ The header file for ISA bus driver
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_ISA_BUS_H_
+#define _INTERNAL_ISA_BUS_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/IsaAcpi.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+#include "ComponentName.h"
+
+//
+// 8237 DMA registers
+//
+#define R_8237_DMA_BASE_CA_CH0 0x00
+#define R_8237_DMA_BASE_CA_CH1 0x02
+#define R_8237_DMA_BASE_CA_CH2 0x04
+#define R_8237_DMA_BASE_CA_CH3 0xd6
+#define R_8237_DMA_BASE_CA_CH5 0xc4
+#define R_8237_DMA_BASE_CA_CH6 0xc8
+#define R_8237_DMA_BASE_CA_CH7 0xcc
+
+#define R_8237_DMA_BASE_CC_CH0 0x01
+#define R_8237_DMA_BASE_CC_CH1 0x03
+#define R_8237_DMA_BASE_CC_CH2 0x05
+#define R_8237_DMA_BASE_CC_CH3 0xd7
+#define R_8237_DMA_BASE_CC_CH5 0xc6
+#define R_8237_DMA_BASE_CC_CH6 0xca
+#define R_8237_DMA_BASE_CC_CH7 0xce
+
+#define R_8237_DMA_MEM_LP_CH0 0x87
+#define R_8237_DMA_MEM_LP_CH1 0x83
+#define R_8237_DMA_MEM_LP_CH2 0x81
+#define R_8237_DMA_MEM_LP_CH3 0x82
+#define R_8237_DMA_MEM_LP_CH5 0x8B
+#define R_8237_DMA_MEM_LP_CH6 0x89
+#define R_8237_DMA_MEM_LP_CH7 0x8A
+
+
+#define R_8237_DMA_COMMAND_CH0_3 0x08
+#define R_8237_DMA_COMMAND_CH4_7 0xd0
+#define B_8237_DMA_COMMAND_GAP 0x10
+#define B_8237_DMA_COMMAND_CGE 0x04
+
+
+#define R_8237_DMA_STA_CH0_3 0xd8
+#define R_8237_DMA_STA_CH4_7 0xd0
+
+#define R_8237_DMA_WRSMSK_CH0_3 0x0a
+#define R_8237_DMA_WRSMSK_CH4_7 0xd4
+#define B_8237_DMA_WRSMSK_CMS 0x04
+
+
+#define R_8237_DMA_CHMODE_CH0_3 0x0b
+#define R_8237_DMA_CHMODE_CH4_7 0xd6
+#define V_8237_DMA_CHMODE_DEMAND 0x00
+#define V_8237_DMA_CHMODE_SINGLE 0x40
+#define V_8237_DMA_CHMODE_CASCADE 0xc0
+#define B_8237_DMA_CHMODE_DECREMENT 0x20
+#define B_8237_DMA_CHMODE_INCREMENT 0x00
+#define B_8237_DMA_CHMODE_AE 0x10
+#define V_8237_DMA_CHMODE_VERIFY 0
+#define V_8237_DMA_CHMODE_IO2MEM 0x04
+#define V_8237_DMA_CHMODE_MEM2IO 0x08
+
+#define R_8237_DMA_CBPR_CH0_3 0x0c
+#define R_8237_DMA_CBPR_CH4_7 0xd8
+
+#define R_8237_DMA_MCR_CH0_3 0x0d
+#define R_8237_DMA_MCR_CH4_7 0xda
+
+#define R_8237_DMA_CLMSK_CH0_3 0x0e
+#define R_8237_DMA_CLMSK_CH4_7 0xdc
+
+#define R_8237_DMA_WRMSK_CH0_3 0x0f
+#define R_8237_DMA_WRMSK_CH4_7 0xde
+
+typedef enum {
+ IsaAccessTypeUnknown,
+ IsaAccessTypeIo,
+ IsaAccessTypeMem,
+ IsaAccessTypeMaxType
+} ISA_ACCESS_TYPE;
+
+//
+// 16 MB Memory Range
+//
+#define ISA_MAX_MEMORY_ADDRESS 0x1000000
+//
+// 64K I/O Range
+//
+#define ISA_MAX_IO_ADDRESS 0x10000
+
+typedef struct {
+ UINT8 Address;
+ UINT8 Page;
+ UINT8 Count;
+} EFI_ISA_DMA_REGISTERS;
+
+//
+// ISA I/O Device Structure
+//
+#define ISA_IO_DEVICE_SIGNATURE SIGNATURE_32 ('i', 's', 'a', 'i')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_ISA_IO_PROTOCOL IsaIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+} ISA_IO_DEVICE;
+
+#define ISA_IO_DEVICE_FROM_ISA_IO_THIS(a) CR (a, ISA_IO_DEVICE, IsaIo, ISA_IO_DEVICE_SIGNATURE)
+
+//
+// Mapping structure for performing ISA DMA to a buffer above 16 MB
+//
+typedef struct {
+ EFI_ISA_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} ISA_MAP_INFO;
+
+//
+// EFI Driver Binding Protocol Interface Functions
+//
+
+/**
+ Tests to see if a controller can be managed by the ISA Bus Driver. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
+ How the Start() function of a driver is implemented can affect how the Supported() function is implemented.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+ @retval EFI_UNSUPPORTED The device is is not supported by this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle.
+
+ Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
+ );
+
+//
+// Function Prototypes
+//
+
+/**
+ Create EFI Handle for a ISA device found via ISA ACPI Protocol
+
+ @param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of ISA bus controller(PCI to ISA bridge)
+ @param[in] PciIo The Pointer to the PCI protocol
+ @param[in] ParentDevicePath Device path of the ISA bus controller
+ @param[in] IsaDeviceResourceList The resource list of the ISA device
+ @param[out] ChildDevicePath The pointer to the child device.
+
+ @retval EFI_SUCCESS The handle for the child device was created.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The handle for the child device can not be created.
+**/
+EFI_STATUS
+IsaCreateDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ChildDevicePath
+ );
+
+/**
+ Initializes an ISA I/O Instance
+
+ @param[in] IsaIoDevice The iso device to be initialized.
+ @param[in] IsaDeviceResourceList The resource list.
+
+**/
+VOID
+InitializeIsaIoInstance (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDevice
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaIo.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaIo.h
new file mode 100644
index 0000000000..054a6b9bab
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/InternalIsaIo.h
@@ -0,0 +1,331 @@
+/** @file
+ The header file for EFI_ISA_IO protocol implementation.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_ISA_IO_H_
+#define _INTERNAL_ISA_IO_H_
+
+#include "InternalIsaBus.h"
+
+//
+// Bits definition of PcdIsaBusSupportedFeatures
+//
+#define PCD_ISA_BUS_SUPPORT_DMA BIT0
+#define PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA BIT1
+#define PCD_ISA_BUS_SUPPORT_ISA_MEMORY BIT2
+
+//
+// ISA I/O Support Function Prototypes
+//
+
+/**
+ Verifies access to an ISA device
+
+ @param[in] IsaIoDevice The ISA device to be verified.
+ @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
+ @param[in] Width The width of the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+
+ @retval EFI_SUCCESS Verify success.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The device ont support the access type.
+**/
+EFI_STATUS
+IsaIoVerifyAccess (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN ISA_ACCESS_TYPE Type,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT32 Offset
+ );
+
+/**
+ Performs an ISA I/O Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Performs an ISA I/O Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was writen to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Maps a memory region for DMA
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Unmaps a memory region for DMA
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoUnmap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Flushes any posted write data to the system memory.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The buffers were flushed.
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFlush (
+ IN EFI_ISA_IO_PROTOCOL *This
+ );
+
+/**
+ Writes I/O operation base address and count number to a 8 bit I/O Port.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] AddrOffset The address' offset.
+ @param[in] PageOffset The page's offest.
+ @param[in] CountOffset The count's offset.
+ @param[in] BaseAddress The base address.
+ @param[in] Count The number of I/O operations to perform.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WriteDmaPort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 AddrOffset,
+ IN UINT32 PageOffset,
+ IN UINT32 CountOffset,
+ IN UINT32 BaseAddress,
+ IN UINT16 Count
+ );
+
+/**
+ Writes an 8-bit I/O Port
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Offset The offset in ISA IO space to start the IO operation.
+ @param[in] Value The data to write port.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WritePort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 Offset,
+ IN UINT8 Value
+ );
+
+/**
+ Performs an ISA Memory Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device successfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+
+/**
+ Performs an ISA Memory Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was written to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory copy operation.
+ @param[in] DestOffset The offset of the destination
+ @param[in] SrcOffset The offset of the source
+ @param[in] Count The number of memory copy operations to perform
+
+ @retval EFI_SUCCESS The data was copied sucessfully.
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoCopyMem (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 DestOffset,
+ IN UINT32 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Type The type allocation to perform.
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of pages to allocate.
+ @param[out] HostAddress A pointer to store the base address of the allocated range.
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
+ @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
+ by HostAddress, Pages, and Type is not available for common buffer use.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoAllocateBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Pages The number of pages to free.
+ @param[in] HostAddress The base address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFreeBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
new file mode 100644
index 0000000000..1312f260f9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBus.c
@@ -0,0 +1,673 @@
+/** @file
+ ISA Bus UEFI driver.
+
+ Discovers all the ISA Controllers and their resources by using the ISA ACPI
+ Protocol, produces an instance of the ISA I/O Protocol for every ISA
+ Controller found. This driver is designed to manage a PCI-to-ISA bridge Device
+ such as LPC bridge.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalIsaBus.h"
+
+//
+// ISA Bus Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gIsaBusControllerDriver = {
+ IsaBusControllerDriverSupported,
+ IsaBusControllerDriverStart,
+ IsaBusControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ The main entry point for the ISA Bus driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+**/
+EFI_STATUS
+EFIAPI
+InitializeIsaBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gIsaBusControllerDriver,
+ ImageHandle,
+ &gIsaBusComponentName,
+ &gIsaBusComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Tests to see if a controller can be managed by the ISA Bus Driver. If a child device is provided,
+ it further tests to see if this driver supports creating a handle for the specified child device.
+
+ Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
+ How the Start() function of a driver is implemented can affect how the Supported() function is implemented.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+ @retval EFI_UNSUPPORTED The device is is not supported by this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
+
+ //
+ // If RemainingDevicePath is not NULL, it should verify that the first device
+ // path node in RemainingDevicePath is an ACPI Device path node which is a
+ // legal Device Path Node for this bus driver's children.
+ //
+ if (RemainingDevicePath != NULL) {
+ if (RemainingDevicePath->Type != ACPI_DEVICE_PATH) {
+ return EFI_UNSUPPORTED;
+ } else if (RemainingDevicePath->SubType == ACPI_DP) {
+ if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_HID_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else if (RemainingDevicePath->SubType == ACPI_EXTENDED_DP) {
+ if (DevicePathNodeLength (RemainingDevicePath) != sizeof (ACPI_EXTENDED_HID_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Try to open EFI DEVICE PATH protocol on the controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ //
+ // Although this driver creates all child handles at one time,
+ // but because all child handles may be not stopped at one time in EFI Driver Binding.Stop(),
+ // So it is allowed to create child handles again in successive calls to EFI Driver Binding.Start().
+ //
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Try to get Pci IO Protocol because it is assumed
+ // to have been opened by ISA ACPI driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Try to open the Isa Acpi protocol on the controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ (VOID **) &IsaAcpi,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Add more check to see if the child device is valid by calling IsaAcpi->DeviceEnumerate?
+ //
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle.
+
+ Note that the ISA Bus driver always creates all of its child handles on the first call to Start().
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_ISA_ACPI_PROTOCOL *IsaAcpi;
+ EFI_ISA_ACPI_DEVICE_ID *IsaDevice;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
+
+ //
+ // Local variables declaration for StatusCode reporting
+ //
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathData;
+
+ DevicePathData = NULL;
+
+ //
+ // Get Pci IO Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open Device Path Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+
+ //
+ // Open ISA Acpi Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ (VOID **) &IsaAcpi,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ //
+ // Close opened protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+ //
+ // The IsaBus driver will use memory below 16M, which is not tested yet,
+ // so call CompatibleRangeTest to test them. Since memory below 1M should
+ // be reserved to CSM, and 15M~16M might be reserved for Isa hole, test 1M
+ // ~15M here
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &GenMemoryTest
+ );
+
+ if (!EFI_ERROR (Status)) {
+ Status = GenMemoryTest->CompatibleRangeTest (
+ GenMemoryTest,
+ 0x100000,
+ 0xE00000
+ );
+ }
+ //
+ // Report Status Code here since we will initialize the host controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_INIT),
+ ParentDevicePath
+ );
+
+ //
+ // first init ISA interface
+ //
+ IsaAcpi->InterfaceInit (IsaAcpi);
+
+ //
+ // Report Status Code here since we will enable the host controller
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_PC_ENABLE),
+ ParentDevicePath
+ );
+
+ //
+ // Create each ISA device handle in this ISA bus
+ //
+ IsaDevice = NULL;
+ do {
+ Status = IsaAcpi->DeviceEnumerate (IsaAcpi, &IsaDevice);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Get current resource of this ISA device
+ //
+ ResourceList = NULL;
+ Status = IsaAcpi->GetCurResource (IsaAcpi, IsaDevice, &ResourceList);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Create handle for this ISA device
+ //
+ // If any child device handle was created in previous call to Start() and not stopped
+ // in previous call to Stop(), it will not be created again because the
+ // InstallMultipleProtocolInterfaces() boot service will reject same device path.
+ //
+ Status = IsaCreateDevice (
+ This,
+ Controller,
+ PciIo,
+ ParentDevicePath,
+ ResourceList,
+ &DevicePathData
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Initialize ISA device
+ //
+ IsaAcpi->InitDevice (IsaAcpi, IsaDevice);
+
+ //
+ // Set resources for this ISA device
+ //
+ Status = IsaAcpi->SetResource (IsaAcpi, IsaDevice, ResourceList);
+
+ //
+ // Report Status Code here when failed to resource conflicts
+ //
+ if (EFI_ERROR (Status) && (Status != EFI_UNSUPPORTED)) {
+ //
+ // It's hard to tell which resource conflicts
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ (EFI_IO_BUS_LPC | EFI_IOB_EC_RESOURCE_CONFLICT),
+ DevicePathData
+ );
+
+ }
+ //
+ // Set power for this ISA device
+ //
+ IsaAcpi->SetPower (IsaAcpi, IsaDevice, TRUE);
+
+ //
+ // Enable this ISA device
+ //
+ IsaAcpi->EnableDevice (IsaAcpi, IsaDevice, TRUE);
+
+ } while (TRUE);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+IsaBusControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ ISA_IO_DEVICE *IsaIoDevice;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaAcpiProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+ }
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ //
+ // Stop all the children
+ // Find all the ISA devices that were discovered on this PCI to ISA Bridge
+ // with the Start() function.
+ //
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
+
+ //
+ // Close the child handle
+ //
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ FreePool (IsaIoDevice->DevicePath);
+ FreePool (IsaIoDevice);
+ } else {
+ //
+ // Re-open PCI IO Protocol on behalf of the child device
+ // because of failure of destroying the child device handle
+ //
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// Internal Function
+//
+
+/**
+ Create EFI Handle for a ISA device found via ISA ACPI Protocol
+
+ @param[in] This The EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of ISA bus controller(PCI to ISA bridge)
+ @param[in] PciIo The Pointer to the PCI protocol
+ @param[in] ParentDevicePath Device path of the ISA bus controller
+ @param[in] IsaDeviceResourceList The resource list of the ISA device
+ @param[out] ChildDevicePath The pointer to the child device.
+
+ @retval EFI_SUCCESS The handle for the child device was created.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval EFI_DEVICE_ERROR The handle for the child device can not be created.
+**/
+EFI_STATUS
+IsaCreateDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList,
+ OUT EFI_DEVICE_PATH_PROTOCOL **ChildDevicePath
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+ EFI_DEV_PATH Node;
+
+ //
+ // Initialize the PCI_IO_DEVICE structure
+ //
+ IsaIoDevice = AllocateZeroPool (sizeof (ISA_IO_DEVICE));
+ if (IsaIoDevice == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IsaIoDevice->Signature = ISA_IO_DEVICE_SIGNATURE;
+ IsaIoDevice->Handle = NULL;
+ IsaIoDevice->PciIo = PciIo;
+
+ //
+ // Initialize the ISA I/O instance structure
+ //
+ InitializeIsaIoInstance (IsaIoDevice, IsaDeviceResourceList);
+
+ //
+ // Build the child device path
+ //
+ Node.DevPath.Type = ACPI_DEVICE_PATH;
+ Node.DevPath.SubType = ACPI_DP;
+ SetDevicePathNodeLength (&Node.DevPath, sizeof (ACPI_HID_DEVICE_PATH));
+ Node.Acpi.HID = IsaDeviceResourceList->Device.HID;
+ Node.Acpi.UID = IsaDeviceResourceList->Device.UID;
+
+ IsaIoDevice->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ &Node.DevPath
+ );
+
+ if (IsaIoDevice->DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ *ChildDevicePath = IsaIoDevice->DevicePath;
+
+ //
+ // Create a child handle and install Device Path and ISA I/O protocols
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &IsaIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ IsaIoDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ IsaIoDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IsaIoDevice->DevicePath,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ }
+
+Done:
+
+ if (EFI_ERROR (Status)) {
+ if (IsaIoDevice->DevicePath != NULL) {
+ FreePool (IsaIoDevice->DevicePath);
+ }
+
+ FreePool (IsaIoDevice);
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
new file mode 100644
index 0000000000..be6dd43ea6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
@@ -0,0 +1,73 @@
+## @file
+# Generates ISA I/O Protocols based on the ISA ACPI Protocol instances.
+#
+# Discovers all the ISA Controllers and their resources by using the ISA ACPI
+# Protocol, produces an instance of the ISA I/O Protocol for every ISA
+# Controller found. This driver is designed to manage a PCI-to-ISA bridge Device
+# such as an LPC bridge.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaBusDxe
+ MODULE_UNI_FILE = IsaBusDxe.uni
+ FILE_GUID = 240612B5-A063-11d4-9A3A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIsaBus
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gIsaBusControllerDriver
+# COMPONENT_NAME = gIsaBusComponentName;
+# COMPONENT_NAME2 = gIsaBusComponentName2;
+#
+
+[Sources]
+ ComponentName.c
+ IsaIo.c
+ IsaBus.c
+ InternalIsaIo.h
+ InternalIsaBus.h
+ ComponentName.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiIsaAcpiProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiGenericMemTestProtocolGuid ## TO_START
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSupportedFeatures ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaBusDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni
new file mode 100644
index 0000000000..204dc2d336
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni
new file mode 100644
index 0000000000..47d9737806
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c
new file mode 100644
index 0000000000..6f1cd1b8b1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaIo.c
@@ -0,0 +1,1463 @@
+/** @file
+ The implementation for EFI_ISA_IO_PROTOCOL.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalIsaIo.h"
+
+//
+// Module Variables
+//
+EFI_ISA_IO_PROTOCOL mIsaIoInterface = {
+ {
+ IsaIoMemRead,
+ IsaIoMemWrite
+ },
+ {
+ IsaIoIoRead,
+ IsaIoIoWrite
+ },
+ IsaIoCopyMem,
+ IsaIoMap,
+ IsaIoUnmap,
+ IsaIoAllocateBuffer,
+ IsaIoFreeBuffer,
+ IsaIoFlush,
+ NULL,
+ 0,
+ NULL
+};
+
+EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {
+ {
+ 0x00,
+ 0x87,
+ 0x01
+ },
+ {
+ 0x02,
+ 0x83,
+ 0x03
+ },
+ {
+ 0x04,
+ 0x81,
+ 0x05
+ },
+ {
+ 0x06,
+ 0x82,
+ 0x07
+ },
+ {
+ 0x00,
+ 0x00,
+ 0x00
+ }, // Channel 4 is invalid
+ {
+ 0xC4,
+ 0x8B,
+ 0xC6
+ },
+ {
+ 0xC8,
+ 0x89,
+ 0xCA
+ },
+ {
+ 0xCC,
+ 0x8A,
+ 0xCE
+ },
+};
+
+/**
+ Initializes an ISA I/O Instance
+
+ @param[in] IsaIoDevice The iso device to be initialized.
+ @param[in] IsaDeviceResourceList The resource list.
+
+**/
+VOID
+InitializeIsaIoInstance (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *IsaDeviceResourceList
+ )
+{
+ //
+ // Use the ISA IO Protocol structure template to initialize the ISA IO instance
+ //
+ CopyMem (
+ &IsaIoDevice->IsaIo,
+ &mIsaIoInterface,
+ sizeof (EFI_ISA_IO_PROTOCOL)
+ );
+
+ IsaIoDevice->IsaIo.ResourceList = IsaDeviceResourceList;
+}
+
+/**
+ Performs an ISA I/O Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeIo,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Io.Read (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA I/O Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was writen to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeIo,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Io.Write (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Writes an 8-bit I/O Port
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Offset The offset in ISA IO space to start the IO operation.
+ @param[in] Value The data to write port.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WritePort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 Offset,
+ IN UINT8 Value
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ Status = IsaIoDevice->PciIo->Io.Write (
+ IsaIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ 1,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ return Status;
+ }
+
+ gBS->Stall (50);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes I/O operation base address and count number to a 8 bit I/O Port.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] AddrOffset The address' offset.
+ @param[in] PageOffset The page's offest.
+ @param[in] CountOffset The count's offset.
+ @param[in] BaseAddress The base address.
+ @param[in] Count The number of I/O operations to perform.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WriteDmaPort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 AddrOffset,
+ IN UINT32 PageOffset,
+ IN UINT32 CountOffset,
+ IN UINT32 BaseAddress,
+ IN UINT16 Count
+ )
+{
+ EFI_STATUS Status;
+
+ Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
+ return Status;
+}
+
+/**
+ Unmaps a memory region for DMA
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoUnmap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ ISA_MAP_INFO *IsaMapInfo;
+
+ //
+ // Check if DMA is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // See if the Map() operation associated with this Unmap() required a mapping
+ // buffer.If a mapping buffer was not required, then this function simply
+ // returns EFI_SUCCESS.
+ //
+ if (Mapping != NULL) {
+ //
+ // Get the MAP_INFO structure from Mapping
+ //
+ IsaMapInfo = (ISA_MAP_INFO *) Mapping;
+
+ //
+ // If this is a write operation from the Agent's point of view,
+ // then copy the contents of the mapped buffer into the real buffer
+ // so the processor can read the contents of the real buffer.
+ //
+ if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // Free the mapped buffer and the MAP_INFO structure.
+ //
+ gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
+ FreePool (IsaMapInfo);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Flushes any posted write data to the system memory.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The buffers were flushed.
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFlush (
+ IN EFI_ISA_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Verifies access to an ISA device
+
+ @param[in] IsaIoDevice The ISA device to be verified.
+ @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
+ @param[in] Width The width of the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+
+ @retval EFI_SUCCESS Verify success.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The device ont support the access type.
+**/
+EFI_STATUS
+IsaIoVerifyAccess (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN ISA_ACCESS_TYPE Type,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT32 Offset
+ )
+{
+ EFI_ISA_ACPI_RESOURCE *Item;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width >= EfiIsaIoWidthMaximum ||
+ Width == EfiIsaIoWidthReserved ||
+ Width == EfiIsaIoWidthFifoReserved ||
+ Width == EfiIsaIoWidthFillReserved
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
+ // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
+ //
+ if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
+ Count = 1;
+ }
+
+ Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ Status = EFI_UNSUPPORTED;
+ Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
+ while (Item->Type != EfiIsaAcpiResourceEndOfList) {
+ if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
+ (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
+ if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
+ return EFI_SUCCESS;
+ }
+
+ if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Item++;
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA Memory Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device successfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify the Isa Io Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Mem.Read (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA Memory Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was written to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Mem.Write (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory copy operation.
+ @param[in] DestOffset The offset of the destination
+ @param[in] SrcOffset The offset of the source
+ @param[in] Count The number of memory copy operations to perform
+
+ @retval EFI_SUCCESS The data was copied sucessfully.
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoCopyMem (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 DestOffset,
+ IN UINT32 SrcOffset,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access for destination and source
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ DestOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ SrcOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->CopyMem (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ DestOffset,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ SrcOffset,
+ Count
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Maps a memory region for DMA, note this implementation
+ only supports slave read/write operation to save code size.
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+IsaIoMapOnlySupportSlaveReadWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ ISA_MAP_INFO *IsaMapInfo;
+ UINT8 DmaMode;
+ UINTN MaxNumberOfBytes;
+ UINT32 BaseAddress;
+ UINT16 Count;
+ UINT8 DmaMask;
+ UINT8 DmaClear;
+ UINT8 DmaChannelMode;
+
+ if ((NULL == This) ||
+ (NULL == HostAddress) ||
+ (NULL == NumberOfBytes) ||
+ (NULL == DeviceAddress) ||
+ (NULL == Mapping)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the return values to their defaults
+ //
+ *Mapping = NULL;
+
+ //
+ // Make sure the Operation parameter is valid.
+ // Light IsaIo only supports two operations.
+ //
+ if (!(Operation == EfiIsaIoOperationSlaveRead ||
+ Operation == EfiIsaIoOperationSlaveWrite)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber >= 4) {
+ //
+ // The Light IsaIo doesn't support channelNumber larger than 4.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Map the HostAddress to a DeviceAddress.
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((PhysicalAddress + *NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // is above 16MB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
+ // is called later.
+ //
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
+ if (IsaMapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = IsaMapInfo;
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ IsaMapInfo->Operation = Operation;
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
+ IsaMapInfo->HostAddress = PhysicalAddress;
+ IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;
+
+ //
+ // Allocate a buffer below 16MB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ IsaMapInfo->NumberOfPages,
+ &IsaMapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (IsaMapInfo);
+ *NumberOfBytes = 0;
+ *Mapping = NULL;
+ return Status;
+ }
+ //
+ // If this is a read operation from the DMA agents's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the DMA agent can read the contents of the real buffer.
+ //
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // The DeviceAddress is the address of the maped buffer below 16 MB
+ //
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;
+ } else {
+ //
+ // The transfer is below 16 MB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ }
+
+ //
+ // Figure out what to program into the DMA Channel Mode Register
+ //
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
+ } else {
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
+ }
+ //
+ // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
+ //
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;
+
+ //
+ // A Slave DMA transfer can not cross a 64K boundary.
+ // Compute *NumberOfBytes based on this restriction.
+ //
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
+ if (*NumberOfBytes > MaxNumberOfBytes) {
+ *NumberOfBytes = MaxNumberOfBytes;
+ }
+ //
+ // Compute the values to program into the BaseAddress and Count registers
+ // of the Slave DMA controller
+ //
+ BaseAddress = (UINT32) (*DeviceAddress);
+ Count = (UINT16) (*NumberOfBytes - 1);
+ //
+ // Program the DMA Write Single Mask Register for ChannelNumber
+ // Clear the DMA Byte Pointer Register
+ //
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;
+ DmaClear = R_8237_DMA_CBPR_CH0_3;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaClear,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, DmaChannelMode, DmaMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WriteDmaPort (
+ This,
+ mDmaRegisters[ChannelNumber].Address,
+ mDmaRegisters[ChannelNumber].Page,
+ mDmaRegisters[ChannelNumber].Count,
+ BaseAddress,
+ Count
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (ChannelNumber & 0x03)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Maps a memory region for DMA. This implementation implement the
+ the full mapping support.
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
+**/
+EFI_STATUS
+IsaIoMapFullSupport (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Master;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ ISA_MAP_INFO *IsaMapInfo;
+ UINT8 DmaMode;
+ UINTN MaxNumberOfBytes;
+ UINT32 BaseAddress;
+ UINT16 Count;
+ UINT8 DmaMask;
+ UINT8 DmaClear;
+ UINT8 DmaChannelMode;
+
+ if ((NULL == This) ||
+ (NULL == HostAddress) ||
+ (NULL == NumberOfBytes) ||
+ (NULL == DeviceAddress) ||
+ (NULL == Mapping)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the return values to their defaults
+ //
+ *Mapping = NULL;
+
+ //
+ // Make sure the Operation parameter is valid
+ //
+ if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber >= 8) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // See if this is a Slave DMA Operation
+ //
+ Master = TRUE;
+ Read = FALSE;
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ Operation = EfiIsaIoOperationBusMasterRead;
+ Master = FALSE;
+ Read = TRUE;
+ }
+
+ if (Operation == EfiIsaIoOperationSlaveWrite) {
+ Operation = EfiIsaIoOperationBusMasterWrite;
+ Master = FALSE;
+ Read = FALSE;
+ }
+
+ if (!Master) {
+ //
+ // Make sure that ChannelNumber is a valid channel number
+ // Channel 4 is used to cascade, so it is illegal.
+ //
+ if (ChannelNumber == 4 || ChannelNumber > 7) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // This implementation only support COMPATIBLE DMA Transfers
+ //
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ChannelAttributes &
+ (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber < 4) {
+ //
+ // If this is Channel 0..3, then the width must be 8 bit
+ //
+ if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // If this is Channel 4..7, then the width must be 16 bit
+ //
+ if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Either Demand Mode or Single Mode must be selected, but not both
+ //
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ //
+ // Map the HostAddress to a DeviceAddress.
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((PhysicalAddress +*NumberOfBytes) > ISA_MAX_MEMORY_ADDRESS) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // is above 16MB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
+ // is called later.
+ //
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
+ if (IsaMapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = IsaMapInfo;
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ IsaMapInfo->Operation = Operation;
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
+ IsaMapInfo->HostAddress = PhysicalAddress;
+ IsaMapInfo->MappedHostAddress = ISA_MAX_MEMORY_ADDRESS - 1;
+
+ //
+ // Allocate a buffer below 16MB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ IsaMapInfo->NumberOfPages,
+ &IsaMapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (IsaMapInfo);
+ *NumberOfBytes = 0;
+ *Mapping = NULL;
+ return Status;
+ }
+ //
+ // If this is a read operation from the DMA agents's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the DMA agent can read the contents of the real buffer.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterRead) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // The DeviceAddress is the address of the maped buffer below 16 MB
+ //
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;
+ } else {
+ //
+ // The transfer is below 16 MB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ }
+ //
+ // If this is a Bus Master operation then return
+ //
+ if (Master) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Figure out what to program into the DMA Channel Mode Register
+ //
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
+ if (Read) {
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
+ } else {
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
+ DmaMode |= B_8237_DMA_CHMODE_AE;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
+ DmaMode |= V_8237_DMA_CHMODE_DEMAND;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;
+ }
+ //
+ // A Slave DMA transfer can not cross a 64K boundary.
+ // Compute *NumberOfBytes based on this restriction.
+ //
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
+ if (*NumberOfBytes > MaxNumberOfBytes) {
+ *NumberOfBytes = MaxNumberOfBytes;
+ }
+ //
+ // Compute the values to program into the BaseAddress and Count registers
+ // of the Slave DMA controller
+ //
+ if (ChannelNumber < 4) {
+ BaseAddress = (UINT32) (*DeviceAddress);
+ Count = (UINT16) (*NumberOfBytes - 1);
+ } else {
+ BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
+ Count = (UINT16) ((*NumberOfBytes - 1) >> 1);
+ }
+ //
+ // Program the DMA Write Single Mask Register for ChannelNumber
+ // Clear the DMA Byte Pointer Register
+ //
+ if (ChannelNumber < 4) {
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;
+ DmaClear = R_8237_DMA_CBPR_CH0_3;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
+ } else {
+ DmaMask = R_8237_DMA_WRSMSK_CH4_7;
+ DmaClear = R_8237_DMA_CBPR_CH4_7;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaClear,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, DmaChannelMode, DmaMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WriteDmaPort (
+ This,
+ mDmaRegisters[ChannelNumber].Address,
+ mDmaRegisters[ChannelNumber].Page,
+ mDmaRegisters[ChannelNumber].Count,
+ BaseAddress,
+ Count
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (ChannelNumber & 0x03)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Maps a memory region for DMA
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ //
+ // Check if DMA is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
+ // ISA Bus Master.
+ //
+ // So we just return EFI_UNSUPPORTED for these functions.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
+ return IsaIoMapOnlySupportSlaveReadWrite (
+ This,
+ Operation,
+ ChannelNumber,
+ ChannelAttributes,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+
+ } else {
+ return IsaIoMapFullSupport (
+ This,
+ Operation,
+ ChannelNumber,
+ ChannelAttributes,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ }
+}
+
+/**
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Type The type allocation to perform.
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of pages to allocate.
+ @param[out] HostAddress A pointer to store the base address of the allocated range.
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
+ @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
+ by HostAddress, Pages, and Type is not available for common buffer use.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoAllocateBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
+ // ISA Bus Master.
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
+ //
+ if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Type >= MaxAllocateType) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (ISA_MAX_MEMORY_ADDRESS - 1);
+ if (Type == AllocateAddress) {
+ if ((UINTN) (*HostAddress) >= ISA_MAX_MEMORY_ADDRESS) {
+ return EFI_UNSUPPORTED;
+ } else {
+ PhysicalAddress = (UINTN) (*HostAddress);
+ }
+ }
+
+ if (Type == AllocateAnyPages) {
+ Type = AllocateMaxAddress;
+ }
+
+ Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ return Status;
+ }
+
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Pages The number of pages to free.
+ @param[in] HostAddress The base address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFreeBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
+ // ISA Bus Master.
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
+ //
+ if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
+ Pages
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.c
new file mode 100644
index 0000000000..f3341ed884
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.c
@@ -0,0 +1,249 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Isa Floppy driver.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaFloppy.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIsaFloppyComponentName = {
+ IsaFloppyComponentNameGetDriverName,
+ IsaFloppyComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIsaFloppyComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IsaFloppyComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IsaFloppyComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIsaFloppyDriverNameTable[] = {
+ {
+ "eng;en",
+ L"ISA Floppy Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param[out] DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+**/
+EFI_STATUS
+EFIAPI
+IsaFloppyComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIsaFloppyDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gIsaFloppyComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param[in] ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param[out] ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+**/
+EFI_STATUS
+EFIAPI
+IsaFloppyComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ FDC_BLK_IO_DEV *FdcDev;
+
+ if (Language == NULL || ControllerName == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check if this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gFdcControllerDriver.DriverBindingHandle,
+ &gEfiIsaIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ gFdcControllerDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FdcDev = FDD_BLK_IO_FROM_THIS (BlkIo);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ FdcDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gIsaFloppyComponentName)
+ );
+}
+
+/**
+ Add the component name for the floppy device
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ CHAR16 FloppyDriveName[FLOPPY_DRIVE_NAME_LEN + 1];
+
+ if (!(FeaturePcdGet(PcdComponentNameDisable) && FeaturePcdGet(PcdComponentName2Disable))) {
+ StrCpyS (FloppyDriveName, FLOPPY_DRIVE_NAME_LEN + 1, FLOPPY_DRIVE_NAME);
+ FloppyDriveName[FLOPPY_DRIVE_NAME_LEN - 1] = (CHAR16) (L'0' + FdcDev->Disk);
+
+ AddUnicodeString2 (
+ "eng",
+ gIsaFloppyComponentName.SupportedLanguages,
+ &FdcDev->ControllerNameTable,
+ FloppyDriveName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gIsaFloppyComponentName2.SupportedLanguages,
+ &FdcDev->ControllerNameTable,
+ FloppyDriveName,
+ FALSE
+ );
+ }
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.h
new file mode 100644
index 0000000000..a136022ceb
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/ComponentName.h
@@ -0,0 +1,146 @@
+/** @file
+ Header file for implementation of UEFI Component Name(2) protocol.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+#define FLOPPY_DRIVE_NAME L"ISA Floppy Drive # "
+#define FLOPPY_DRIVE_NAME_LEN ((sizeof (FLOPPY_DRIVE_NAME) / sizeof (CHAR16)) - 1)
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIsaFloppyComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gIsaFloppyComponentName2;
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param[out] DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+**/
+EFI_STATUS
+EFIAPI
+IsaFloppyComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param[in] This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param[in] ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param[in] Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param[out] ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+**/
+EFI_STATUS
+EFIAPI
+IsaFloppyComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Add the component name for the floppy device
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.c
new file mode 100644
index 0000000000..65555d3eb1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.c
@@ -0,0 +1,515 @@
+/** @file
+ ISA Floppy Disk UEFI Driver conforming to the UEFI driver model
+
+ 1. Support two types diskette drive
+ 1.44M drive and 2.88M drive (and now only support 1.44M)
+ 2. Support two diskette drives per floppy disk controller
+ 3. Use DMA channel 2 to transfer data
+ 4. Do not use interrupt
+ 5. Support diskette change line signal and write protect
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaFloppy.h"
+
+LIST_ENTRY mControllerHead = INITIALIZE_LIST_HEAD_VARIABLE (mControllerHead);
+
+//
+// ISA Floppy Driver Binding Protocol
+//
+EFI_DRIVER_BINDING_PROTOCOL gFdcControllerDriver = {
+ FdcControllerDriverSupported,
+ FdcControllerDriverStart,
+ FdcControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+/**
+ The main Entry Point for this driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+**/
+EFI_STATUS
+EFIAPI
+InitializeIsaFloppy(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gFdcControllerDriver,
+ ImageHandle,
+ &gIsaFloppyComponentName,
+ &gIsaFloppyComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Test if the controller is a floppy disk drive device
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+ @retval EFI_UNSUPPORTED The device is is not supported by this driver.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ //
+ // Ignore the parameter RemainingDevicePath because this is a device driver.
+ //
+
+ //
+ // Open the device path protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is a floppy disk drive device
+ //
+ Status = EFI_SUCCESS;
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
+ Status = EFI_UNSUPPORTED;
+ }
+ //
+ // Close the ISA I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on Controller.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ FDC_BLK_IO_DEV *FdcDev;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINTN Index;
+ LIST_ENTRY *List;
+ BOOLEAN Found;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ FdcDev = NULL;
+ IsaIo = NULL;
+
+ //
+ // Open the device path protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Report enable progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+
+ //
+ // Open the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Allocate the floppy device's Device structure
+ //
+ FdcDev = AllocateZeroPool (sizeof (FDC_BLK_IO_DEV));
+ if (FdcDev == NULL) {
+ goto Done;
+ }
+ //
+ // Initialize the floppy device's device structure
+ //
+ FdcDev->Signature = FDC_BLK_IO_DEV_SIGNATURE;
+ FdcDev->Handle = Controller;
+ FdcDev->IsaIo = IsaIo;
+ FdcDev->Disk = (EFI_FDC_DISK) IsaIo->ResourceList->Device.UID;
+ FdcDev->Cache = NULL;
+ FdcDev->Event = NULL;
+ FdcDev->ControllerState = NULL;
+ FdcDev->DevicePath = ParentDevicePath;
+
+ FdcDev->ControllerNameTable = NULL;
+ AddName (FdcDev);
+
+ //
+ // Look up the base address of the Floppy Disk Controller which controls this floppy device
+ //
+ for (Index = 0; FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
+ if (FdcDev->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
+ FdcDev->BaseAddress = (UINT16) FdcDev->IsaIo->ResourceList->ResourceItem[Index].StartRange;
+ }
+ }
+ //
+ // Maintain the list of floppy disk controllers
+ //
+ Found = FALSE;
+ List = mControllerHead.ForwardLink;
+ while (List != &mControllerHead) {
+ FdcDev->ControllerState = FLOPPY_CONTROLLER_FROM_LIST_ENTRY (List);
+ if (FdcDev->BaseAddress == FdcDev->ControllerState->BaseAddress) {
+ Found = TRUE;
+ break;
+ }
+
+ List = List->ForwardLink;
+ }
+
+ if (!Found) {
+ //
+ // A new floppy disk controller controlling this floppy disk drive is found
+ //
+ FdcDev->ControllerState = AllocatePool (sizeof (FLOPPY_CONTROLLER_CONTEXT));
+ if (FdcDev->ControllerState == NULL) {
+ goto Done;
+ }
+
+ FdcDev->ControllerState->Signature = FLOPPY_CONTROLLER_CONTEXT_SIGNATURE;
+ FdcDev->ControllerState->FddResetPerformed = FALSE;
+ FdcDev->ControllerState->NeedRecalibrate = FALSE;
+ FdcDev->ControllerState->BaseAddress = FdcDev->BaseAddress;
+ FdcDev->ControllerState->NumberOfDrive = 0;
+
+ InsertTailList (&mControllerHead, &FdcDev->ControllerState->Link);
+ }
+ //
+ // Create a timer event for each floppy disk drive device.
+ // This timer event is used to control the motor on and off
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ FddTimerProc,
+ FdcDev,
+ &FdcDev->Event
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Reset the Floppy Disk Controller
+ //
+ if (!FdcDev->ControllerState->FddResetPerformed) {
+ FdcDev->ControllerState->FddResetPerformed = TRUE;
+ FdcDev->ControllerState->FddResetStatus = FddReset (FdcDev);
+ }
+
+ if (EFI_ERROR (FdcDev->ControllerState->FddResetStatus)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_PRESENCE_DETECT,
+ ParentDevicePath
+ );
+
+ //
+ // Discover the Floppy Drive
+ //
+ Status = DiscoverFddDevice (FdcDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ //
+ // Install protocol interfaces for the serial device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiBlockIoProtocolGuid,
+ &FdcDev->BlkIo,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ FdcDev->ControllerState->NumberOfDrive++;
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_EC_CONTROLLER_ERROR,
+ ParentDevicePath
+ );
+
+ //
+ // If a floppy drive device structure was allocated, then free it
+ //
+ if (FdcDev != NULL) {
+ if (FdcDev->Event != NULL) {
+ //
+ // Close the event for turning the motor off
+ //
+ gBS->CloseEvent (FdcDev->Event);
+ }
+
+ FreeUnicodeStringTable (FdcDev->ControllerNameTable);
+ FreePool (FdcDev);
+ }
+
+ //
+ // Close the ISA I/O Protocol
+ //
+ if (IsaIo != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ //
+ // Close the device path protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ FDC_BLK_IO_DEV *FdcDev;
+
+ //
+ // Ignore NumberOfChildren since this is a device driver
+ //
+
+ //
+ // Get the Block I/O Protocol on Controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the floppy drive device's Device structure
+ //
+ FdcDev = FDD_BLK_IO_FROM_THIS (BlkIo);
+
+ //
+ // Report disable progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_DISABLE,
+ FdcDev->DevicePath
+ );
+
+ //
+ // Uninstall the Block I/O Protocol
+ //
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiBlockIoProtocolGuid,
+ &FdcDev->BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the event for turning the motor off
+ //
+ gBS->CloseEvent (FdcDev->Event);
+
+ //
+ // Turn the motor off on the floppy drive device
+ //
+ FddTimerProc (FdcDev->Event, FdcDev);
+
+ //
+ // Close the device path protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Close the ISA I/O Protocol
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free the controller list if needed
+ //
+ FdcDev->ControllerState->NumberOfDrive--;
+
+ //
+ // Free the cache if one was allocated
+ //
+ FdcFreeCache (FdcDev);
+
+ //
+ // Free the floppy drive device's device structure
+ //
+ FreeUnicodeStringTable (FdcDev->ControllerNameTable);
+ FreePool (FdcDev);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.h
new file mode 100644
index 0000000000..30a2d7bf0c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppy.h
@@ -0,0 +1,1093 @@
+/** @file
+ Include file for ISA Floppy Driver
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ISA_FLOPPY_H_
+#define _ISA_FLOPPY_H_
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Library/TimerLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+extern EFI_DRIVER_BINDING_PROTOCOL gFdcControllerDriver;
+
+#define STALL_1_SECOND 1000000
+#define STALL_1_MSECOND 1000
+
+#define DATA_IN 1
+#define DATA_OUT 0
+#define READ 0
+#define WRITE 1
+
+//
+// Internal Data Structures
+//
+#define FDC_BLK_IO_DEV_SIGNATURE SIGNATURE_32 ('F', 'B', 'I', 'O')
+#define FLOPPY_CONTROLLER_CONTEXT_SIGNATURE SIGNATURE_32 ('F', 'D', 'C', 'C')
+
+typedef enum {
+ FdcDisk0 = 0,
+ FdcDisk1 = 1,
+ FdcMaxDisk = 2
+} EFI_FDC_DISK;
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ BOOLEAN FddResetPerformed;
+ EFI_STATUS FddResetStatus;
+ BOOLEAN NeedRecalibrate;
+ UINT8 NumberOfDrive;
+ UINT16 BaseAddress;
+} FLOPPY_CONTROLLER_CONTEXT;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL BlkIo;
+ EFI_BLOCK_IO_MEDIA BlkMedia;
+
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ UINT16 BaseAddress;
+
+ EFI_FDC_DISK Disk;
+ UINT8 PresentCylinderNumber;
+ UINT8 *Cache;
+
+ EFI_EVENT Event;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ FLOPPY_CONTROLLER_CONTEXT *ControllerState;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} FDC_BLK_IO_DEV;
+
+#include "ComponentName.h"
+
+#define FDD_BLK_IO_FROM_THIS(a) CR (a, FDC_BLK_IO_DEV, BlkIo, FDC_BLK_IO_DEV_SIGNATURE)
+#define FLOPPY_CONTROLLER_FROM_LIST_ENTRY(a) \
+ CR (a, \
+ FLOPPY_CONTROLLER_CONTEXT, \
+ Link, \
+ FLOPPY_CONTROLLER_CONTEXT_SIGNATURE \
+ )
+
+#define DISK_1440K_EOT 0x12
+#define DISK_1440K_GPL 0x1b
+#define DISK_1440K_DTL 0xff
+#define DISK_1440K_NUMBER 0x02
+#define DISK_1440K_MAXTRACKNUM 0x4f
+#define DISK_1440K_BYTEPERSECTOR 512
+
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+ UINT8 Cylinder;
+ UINT8 Head;
+ UINT8 Sector;
+ UINT8 Number;
+ UINT8 EndOfTrack;
+ UINT8 GapLength;
+ UINT8 DataLength;
+} FDD_COMMAND_PACKET1;
+
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+} FDD_COMMAND_PACKET2;
+
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 SrtHut;
+ UINT8 HltNd;
+} FDD_SPECIFY_CMD;
+
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+ UINT8 NewCylinder;
+} FDD_SEEK_CMD;
+
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+ UINT8 Cylinder;
+ UINT8 Head;
+ UINT8 Sector;
+ UINT8 EndOfTrack;
+ UINT8 GapLength;
+ UINT8 ScanTestPause;
+} FDD_SCAN_CMD;
+
+typedef struct {
+ UINT8 Status0;
+ UINT8 Status1;
+ UINT8 Status2;
+ UINT8 Cylinder;
+ UINT8 Head;
+ UINT8 Sector;
+ UINT8 Number;
+} FDD_RESULT_PACKET;
+
+//
+// FDC Registers
+//
+//
+// Digital Output Register address offset
+//
+#define FDC_REGISTER_DOR 2
+
+//
+// Main Status Register address offset
+//
+#define FDC_REGISTER_MSR 4
+
+//
+// Data Register address offset
+//
+#define FDC_REGISTER_DTR 5
+
+//
+// Configuration Control Register(data rate select) address offset
+//
+#define FDC_REGISTER_CCR 7
+
+//
+// Digital Input Register(diskchange) address offset
+//
+#define FDC_REGISTER_DIR 7
+
+
+//
+// FDC Register Bit Definitions
+//
+//
+// Digital Out Register(WO)
+//
+//
+// Select Drive: 0=A 1=B
+//
+#define SELECT_DRV BIT0
+
+//
+// Reset FDC
+//
+#define RESET_FDC BIT2
+
+//
+// Enable Int & DMA
+//
+#define INT_DMA_ENABLE BIT3
+
+//
+// Turn On Drive A Motor
+//
+#define DRVA_MOTOR_ON BIT4
+
+//
+// Turn On Drive B Motor
+//
+#define DRVB_MOTOR_ON BIT5
+
+//
+// Main Status Register(RO)
+//
+//
+// Drive A Busy
+//
+#define MSR_DAB BIT0
+
+//
+// Drive B Busy
+//
+#define MSR_DBB BIT1
+
+//
+// FDC Busy
+//
+#define MSR_CB BIT4
+
+//
+// Non-DMA Mode
+//
+#define MSR_NDM BIT5
+
+//
+// Data Input/Output
+//
+#define MSR_DIO BIT6
+
+//
+// Request For Master
+//
+#define MSR_RQM BIT7
+
+//
+// Configuration Control Register(WO)
+//
+//
+// Data Rate select
+//
+#define CCR_DRC (BIT0 | BIT1)
+
+//
+// Digital Input Register(RO)
+//
+//
+// Disk change line
+//
+#define DIR_DCL BIT7
+//
+// #define CCR_DCL BIT7 // Diskette change
+//
+// 500K
+//
+#define DRC_500KBS 0x0
+
+//
+// 300K
+//
+#define DRC_300KBS 0x01
+
+//
+// 250K
+//
+#define DRC_250KBS 0x02
+
+//
+// FDC Command Code
+//
+#define READ_DATA_CMD 0x06
+#define WRITE_DATA_CMD 0x05
+#define WRITE_DEL_DATA_CMD 0x09
+#define READ_DEL_DATA_CMD 0x0C
+#define READ_TRACK_CMD 0x02
+#define READ_ID_CMD 0x0A
+#define FORMAT_TRACK_CMD 0x0D
+#define SCAN_EQU_CMD 0x11
+#define SCAN_LOW_EQU_CMD 0x19
+#define SCAN_HIGH_EQU_CMD 0x1D
+#define SEEK_CMD 0x0F
+#define RECALIBRATE_CMD 0x07
+#define SENSE_INT_STATUS_CMD 0x08
+#define SPECIFY_CMD 0x03
+#define SENSE_DRV_STATUS_CMD 0x04
+
+//
+// CMD_MT: Multi_Track Selector
+// when set , this flag selects the multi-track operating mode.
+// In this mode, the FDC treats a complete cylinder under head0 and 1
+// as a single track
+//
+#define CMD_MT BIT7
+
+//
+// CMD_MFM: MFM/FM Mode Selector
+// A one selects the double density(MFM) mode
+// A zero selects single density (FM) mode
+//
+#define CMD_MFM BIT6
+
+//
+// CMD_SK: Skip Flag
+// When set to 1, sectors containing a deleted data address mark will
+// automatically be skipped during the execution of Read Data.
+// When set to 0, the sector is read or written the same as the read and
+// write commands.
+//
+#define CMD_SK BIT5
+
+//
+// FDC Status Register Bit Definitions
+//
+//
+// Status Register 0
+//
+//
+// Interrupt Code
+//
+#define STS0_IC (BIT7 | BIT6)
+
+//
+// Seek End: the FDC completed a seek or recalibrate command
+//
+#define STS0_SE BIT5
+
+//
+// Equipment Check
+//
+#define STS0_EC BIT4
+
+//
+// Not Ready(unused), this bit is always 0
+//
+#define STS0_NR BIT3
+
+//
+// Head Address: the current head address
+//
+#define STS0_HA BIT2
+
+//
+// STS0_US1 & STS0_US0: Drive Select(the current selected drive)
+//
+//
+// Unit Select1
+//
+#define STS0_US1 BIT1
+
+//
+// Unit Select0
+//
+#define STS0_US0 BIT0
+
+//
+// Status Register 1
+//
+//
+// End of Cylinder
+//
+#define STS1_EN BIT7
+
+//
+// BIT6 is unused
+//
+//
+// Data Error: The FDC detected a CRC error in either the ID field or
+// data field of a sector
+//
+#define STS1_DE BIT5
+
+//
+// Overrun/Underrun: Becomes set if FDC does not receive CPU or DMA service
+// within the required time interval
+//
+#define STS1_OR BIT4
+
+//
+// BIT3 is unused
+//
+//
+// No data
+//
+#define STS1_ND BIT2
+
+//
+// Not Writable
+//
+#define STS1_NW BIT1
+
+//
+// Missing Address Mark
+//
+#define STS1_MA BIT0
+
+//
+// Control Mark
+//
+#define STS2_CM BIT6
+
+//
+// Data Error in Data Field: The FDC detected a CRC error in the data field
+//
+#define STS2_DD BIT5
+
+//
+// Wrong Cylinder: The track address from sector ID field is different from
+// the track address maintained inside FDC
+//
+#define STS2_WC BIT4
+
+//
+// Bad Cylinder
+//
+#define STS2_BC BIT1
+
+//
+// Missing Address Mark in Data Field
+//
+#define STS2_MD BIT0
+
+//
+// Write Protected
+//
+#define STS3_WP BIT6
+
+//
+// Track 0
+//
+#define STS3_T0 BIT4
+
+//
+// Head Address
+//
+#define STS3_HD BIT2
+
+//
+// STS3_US1 & STS3_US0 : Drive Select
+//
+#define STS3_US1 BIT1
+#define STS3_US0 BIT0
+
+//
+// Status Register 0 Interrupt Code Description
+//
+//
+// Normal Termination of Command
+//
+#define IC_NT 0x0
+
+//
+// Abnormal Termination of Command
+//
+#define IC_AT 0x40
+
+//
+// Invalid Command
+//
+#define IC_IC 0x80
+
+//
+// Abnormal Termination caused by Polling
+//
+#define IC_ATRC 0xC0
+
+//
+// EFI Driver Binding Protocol Functions
+//
+
+/**
+ Test controller is a floppy disk drive device
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on Controller.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+FdcControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Block I/O Protocol Functions
+//
+
+/**
+ Reset the Floppy Logic Drive, call the FddReset function.
+
+ @param This EFI_BLOCK_IO *: A pointer to the Block I/O protocol interface
+ @param ExtendedVerification BOOLEAN: Indicate that the driver may perform a more
+ exhaustive verification operation of the device during
+ reset, now this par is ignored in this driver
+ @retval EFI_SUCCESS: The Floppy Logic Drive is reset
+ @retval EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly
+ and can not be reset
+
+**/
+EFI_STATUS
+EFIAPI
+FdcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Flush block via fdd controller.
+
+ @param This EFI_BLOCK_IO *: A pointer to the Block I/O protocol interface
+ @return EFI_SUCCESS
+
+**/
+EFI_STATUS
+EFIAPI
+FddFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Read the requested number of blocks from the device.
+
+ @param This EFI_BLOCK_IO *: A pointer to the Block I/O protocol interface
+ @param MediaId UINT32: The media id that the read request is for
+ @param Lba EFI_LBA: The starting logic block address to read from on the device
+ @param BufferSize UINTN: The size of the Buffer in bytes
+ @param Buffer VOID *: A pointer to the destination buffer for the data
+
+ @retval EFI_SUCCESS: The data was read correctly from the device
+ @retval EFI_DEVICE_ERROR:The device reported an error while attempting to perform
+ the read operation
+ @retval EFI_NO_MEDIA: There is no media in the device
+ @retval EFI_MEDIA_CHANGED: The MediaId is not for the current media
+ @retval EFI_BAD_BUFFER_SIZE: The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device
+ @retval EFI_INVALID_PARAMETER:The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment
+
+**/
+EFI_STATUS
+EFIAPI
+FddReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write a specified number of blocks to the device.
+
+ @param This EFI_BLOCK_IO *: A pointer to the Block I/O protocol interface
+ @param MediaId UINT32: The media id that the write request is for
+ @param Lba EFI_LBA: The starting logic block address to be written
+ @param BufferSize UINTN: The size in bytes in Buffer
+ @param Buffer VOID *: A pointer to the source buffer for the data
+
+ @retval EFI_SUCCESS: The data were written correctly to the device
+ @retval EFI_WRITE_PROTECTED: The device can not be written to
+ @retval EFI_NO_MEDIA: There is no media in the device
+ @retval EFI_MEDIA_CHANGED: The MediaId is not for the current media
+ @retval EFI_DEVICE_ERROR: The device reported an error while attempting to perform
+ the write operation
+ @retval EFI_BAD_BUFFER_SIZE: The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device
+ @retval EFI_INVALID_PARAMETER:The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment
+**/
+EFI_STATUS
+EFIAPI
+FddWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+//
+// Prototypes of internal functions
+//
+/**
+
+ Detect the floppy drive is presented or not.
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
+ @retval EFI_SUCCESS Drive is presented
+ @retval EFI_NOT_FOUND Drive is not presented
+
+**/
+EFI_STATUS
+DiscoverFddDevice (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+
+ Do recalibrate and see the drive is presented or not.
+ Set the media parameters.
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
+ @return the drive is presented or not
+
+**/
+EFI_STATUS
+FddIdentify (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+
+ Reset the Floppy Logic Drive.
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: The Floppy Logic Drive is reset
+ @retval EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
+ can not be reset
+
+**/
+EFI_STATUS
+FddReset (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+
+ Turn the drive's motor on.
+ The drive's motor must be on before any command can be executed.
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: Turn the drive's motor on successfully
+ @retval EFI_DEVICE_ERROR: The drive is busy, so can not turn motor on
+ @retval EFI_INVALID_PARAMETER: Fail to Set timer(Cancel timer)
+
+**/
+EFI_STATUS
+MotorOn (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+
+ Set a Timer and when Timer goes off, turn the motor off.
+
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: Set the Timer successfully
+ @retval EFI_INVALID_PARAMETER: Fail to Set the timer
+
+**/
+EFI_STATUS
+MotorOff (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Detect the disk in the drive is changed or not.
+
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: No disk media change
+ @retval EFI_DEVICE_ERROR: Fail to do the recalibrate or seek operation
+ @retval EFI_NO_MEDIA: No disk in the drive
+ @retval EFI_MEDIA_CHANGED: There is a new disk in the drive
+**/
+EFI_STATUS
+DisketChanged (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Do the Specify command, this command sets DMA operation
+ and the initial values for each of the three internal
+ times: HUT, SRT and HLT.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: Execute the Specify command successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the command
+
+**/
+EFI_STATUS
+Specify (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Set the head of floppy drive to track 0.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @retval EFI_SUCCESS: Execute the Recalibrate operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
+
+**/
+EFI_STATUS
+Recalibrate (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Set the head of floppy drive to the new cylinder.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param Lba EFI_LBA : The logic block address want to seek
+
+ @retval EFI_SUCCESS: Execute the Seek operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the Seek operation
+
+**/
+EFI_STATUS
+Seek (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba
+ );
+
+/**
+ Do the Sense Interrupt Status command, this command resets the interrupt signal.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
+ @param PresentCylinderNumber UINT8 *: Be used to save present cylinder number
+ read from FDC
+
+ @retval EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the command
+
+**/
+EFI_STATUS
+SenseIntStatus (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN OUT UINT8 *StatusRegister0,
+ IN OUT UINT8 *PresentCylinderNumber
+ );
+
+/**
+ Do the Sense Drive Status command.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param Lba EFI_LBA : Logic block address
+
+ @retval EFI_SUCCESS: Execute the Sense Drive Status command successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the command
+ @retval EFI_WRITE_PROTECTED:The disk is write protected
+
+**/
+EFI_STATUS
+SenseDrvStatus (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba
+ );
+
+/**
+ Update the disk media properties and if necessary reinstall Block I/O interface.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: Do the operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to the operation
+
+**/
+EFI_STATUS
+DetectMedia (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Set the data rate and so on.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS success to set the data rate
+**/
+EFI_STATUS
+Setup (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Read or Write a number of blocks in the same cylinder.
+
+ @param FdcDev A pointer to Data Structure FDC_BLK_IO_DEV
+ @param HostAddress device address
+ @param Lba The starting logic block address to read from on the device
+ @param NumberOfBlocks The number of block wanted to be read or write
+ @param Read Operation type: read or write
+
+ @retval EFI_SUCCESS Success operate
+
+**/
+EFI_STATUS
+ReadWriteDataSector (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN VOID *HostAddress,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN BOOLEAN Read
+ );
+
+/**
+ Fill in FDD command's parameter.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Lba The starting logic block address to read from on the device
+ @param Command FDD command
+
+**/
+VOID
+FillPara (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba,
+ IN FDD_COMMAND_PACKET1 *Command
+ );
+
+/**
+ Read result byte from Data Register of FDC.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Pointer Buffer to store the byte read from FDC
+
+ @retval EFI_SUCCESS Read result byte from FDC successfully
+ @retval EFI_DEVICE_ERROR The FDC is not ready to be read
+
+**/
+EFI_STATUS
+DataInByte (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ OUT UINT8 *Pointer
+ );
+
+/**
+ Write command byte to Data Register of FDC.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Pointer Be used to save command byte written to FDC
+
+ @retval EFI_SUCCESS: Write command byte to FDC successfully
+ @retval EFI_DEVICE_ERROR: The FDC is not ready to be written
+
+**/
+EFI_STATUS
+DataOutByte (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT8 *Pointer
+ );
+
+/**
+ Detect the specified floppy logic drive is busy or not within a period of time.
+
+ @param FdcDev Indicate it is drive A or drive B
+ @param Timeout The time period for waiting
+
+ @retval EFI_SUCCESS: The drive and command are not busy
+ @retval EFI_TIMEOUT: The drive or command is still busy after a period time that
+ set by Timeout
+
+**/
+EFI_STATUS
+FddWaitForBSYClear (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINTN Timeout
+ );
+
+/**
+ Determine whether FDC is ready to write or read.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Dio BOOLEAN: Indicate the FDC is waiting to write or read
+ @param Timeout The time period for waiting
+
+ @retval EFI_SUCCESS: FDC is ready to write or read
+ @retval EFI_NOT_READY: FDC is not ready within the specified time period
+
+**/
+EFI_STATUS
+FddDRQReady (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN BOOLEAN Dio,
+ IN UINTN Timeout
+ );
+
+/**
+ Set FDC control structure's attribute according to result.
+
+ @param Result Point to result structure
+ @param FdcDev FDC control structure
+
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+
+**/
+EFI_STATUS
+CheckResult (
+ IN FDD_RESULT_PACKET *Result,
+ IN OUT FDC_BLK_IO_DEV *FdcDev
+ );
+
+/**
+ Check the drive status information.
+
+ @param StatusRegister3 the value of Status Register 3
+
+ @retval EFI_SUCCESS The disk is not write protected
+ @retval EFI_WRITE_PROTECTED: The disk is write protected
+
+**/
+EFI_STATUS
+CheckStatus3 (
+ IN UINT8 StatusRegister3
+ );
+
+/**
+ Calculate the number of block in the same cylinder according to Lba.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param Lba EFI_LBA: The starting logic block address
+ @param NumberOfBlocks UINTN: The number of blocks
+
+ @return The number of blocks in the same cylinder which the starting
+ logic block address is Lba
+
+**/
+UINTN
+GetTransferBlockCount (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ );
+
+/**
+ When the Timer(2s) off, turn the drive's motor off.
+
+ @param Event EFI_EVENT: Event(the timer) whose notification function is being
+ invoked
+ @param Context VOID *: Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+FddTimerProc (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Read I/O port for FDC.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param Offset The offset address of port
+
+**/
+UINT8
+FdcReadPort (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT32 Offset
+ );
+
+/**
+ Write I/O port for FDC.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to Data Structure FDC_BLK_IO_DEV
+ @param Offset The offset address of port
+ @param Data Value written to port
+
+**/
+VOID
+FdcWritePort (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ );
+
+/**
+ Read or Write a number of blocks to floppy device.
+
+ @param This Pointer to instance of EFI_BLOCK_IO_PROTOCOL
+ @param MediaId The media id of read/write request
+ @param Lba The starting logic block address to read from on the device
+ @param BufferSize The size of the Buffer in bytes
+ @param Operation - GC_TODO: add argument description
+ @param Buffer - GC_TODO: add argument description
+
+ @retval EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_NO_MEDIA - GC_TODO: Add description for return value
+ @retval EFI_MEDIA_CHANGED - GC_TODO: Add description for return value
+ @retval EFI_WRITE_PROTECTED - GC_TODO: Add description for return value
+ @retval EFI_BAD_BUFFER_SIZE - GC_TODO: Add description for return value
+ @retval EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
+ @retval EFI_INVALID_PARAMETER - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+
+**/
+EFI_STATUS
+FddReadWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN BOOLEAN Operation,
+ OUT VOID *Buffer
+ );
+
+/**
+ Common interface for free cache.
+
+ @param FdcDev Pointer of FDC_BLK_IO_DEV instance
+
+**/
+VOID
+FdcFreeCache (
+ IN FDC_BLK_IO_DEV *FdcDev
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyBlock.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyBlock.c
new file mode 100644
index 0000000000..39f0ba0191
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyBlock.c
@@ -0,0 +1,375 @@
+/** @file
+ Implementation of the EFI Block IO Protocol for ISA Floppy driver
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaFloppy.h"
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+**/
+EFI_STATUS
+EFIAPI
+FdcReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ FDC_BLK_IO_DEV *FdcDev;
+
+ //
+ // Reset the Floppy Disk Controller
+ //
+ FdcDev = FDD_BLK_IO_FROM_THIS (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_RESET | EFI_PERIPHERAL_REMOVABLE_MEDIA,
+ FdcDev->DevicePath
+ );
+
+ return FddReset (FdcDev);
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+FddFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // Not supported yet
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Common report status code interface.
+
+ @param This Pointer of FDC_BLK_IO_DEV instance
+ @param Read Read or write operation when error occurrs
+**/
+VOID
+FddReportStatus (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN Read
+ )
+{
+ FDC_BLK_IO_DEV *FdcDev;
+
+ FdcDev = FDD_BLK_IO_FROM_THIS (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ ((Read) ? EFI_P_EC_INPUT_ERROR : EFI_P_EC_OUTPUT_ERROR) | EFI_PERIPHERAL_REMOVABLE_MEDIA,
+ FdcDev->DevicePath
+ );
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+FddReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, READ, Buffer);
+
+ if (EFI_ERROR (Status)) {
+ FddReportStatus (This, TRUE);
+ }
+
+ return Status;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+FddWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+
+ Status = FddReadWriteBlocks (This, MediaId, Lba, BufferSize, WRITE, Buffer);
+
+ if (EFI_ERROR (Status)) {
+ FddReportStatus (This, FALSE);
+ }
+
+ return Status;
+}
+
+/**
+ Read or Write a number of blocks to floppy disk
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Operation Specifies the read or write operation.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+
+**/
+EFI_STATUS
+FddReadWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN BOOLEAN Operation,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ FDC_BLK_IO_DEV *FdcDev;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ UINTN BlockCount;
+ EFI_STATUS Status;
+ EFI_LBA Lba0;
+ UINT8 *Pointer;
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+ FdcDev = FDD_BLK_IO_FROM_THIS (This);
+
+ if (Operation == WRITE) {
+ if (Lba == 0) {
+ FdcFreeCache (FdcDev);
+ }
+ }
+
+ //
+ // Set the drive motor on
+ //
+ Status = MotorOn (FdcDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check to see if media can be detected
+ //
+ Status = DetectMedia (FdcDev);
+ if (EFI_ERROR (Status)) {
+ MotorOff (FdcDev);
+ FdcFreeCache (FdcDev);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check to see if media is present
+ //
+ if (!(Media->MediaPresent)) {
+ MotorOff (FdcDev);
+ FdcFreeCache (FdcDev);
+ return EFI_NO_MEDIA;
+ }
+ //
+ // Check to see if media has been changed
+ //
+ if (MediaId != Media->MediaId) {
+ MotorOff (FdcDev);
+ FdcFreeCache (FdcDev);
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize == 0) {
+ MotorOff (FdcDev);
+ return EFI_SUCCESS;
+ }
+
+ if (Operation == WRITE) {
+ if (Media->ReadOnly) {
+ MotorOff (FdcDev);
+ return EFI_WRITE_PROTECTED;
+ }
+ }
+ //
+ // Check the parameters for this read/write operation
+ //
+ if (Buffer == NULL) {
+ MotorOff (FdcDev);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ MotorOff (FdcDev);
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > Media->LastBlock) {
+ MotorOff (FdcDev);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((BufferSize / BlockSize) + Lba - 1) > Media->LastBlock) {
+ MotorOff (FdcDev);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Operation == READ) {
+ //
+ // See if the data that is being read is already in the cache
+ //
+ if (FdcDev->Cache != NULL) {
+ if (Lba == 0 && BufferSize == BlockSize) {
+ MotorOff (FdcDev);
+ CopyMem ((UINT8 *) Buffer, (UINT8 *) FdcDev->Cache, BlockSize);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ //
+ // Set up Floppy Disk Controller
+ //
+ Status = Setup (FdcDev);
+ if (EFI_ERROR (Status)) {
+ MotorOff (FdcDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+ Lba0 = Lba;
+ Pointer = Buffer;
+
+ //
+ // read blocks in the same cylinder.
+ // in a cylinder , there are 18 * 2 = 36 blocks
+ //
+ BlockCount = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
+ while ((BlockCount != 0) && !EFI_ERROR (Status)) {
+ Status = ReadWriteDataSector (FdcDev, Buffer, Lba, BlockCount, Operation);
+ if (EFI_ERROR (Status)) {
+ MotorOff (FdcDev);
+ FddReset (FdcDev);
+ return EFI_DEVICE_ERROR;
+ }
+
+ Lba += BlockCount;
+ NumberOfBlocks -= BlockCount;
+ Buffer = (VOID *) ((UINTN) Buffer + BlockCount * BlockSize);
+ BlockCount = GetTransferBlockCount (FdcDev, Lba, NumberOfBlocks);
+ }
+
+ Buffer = Pointer;
+
+ //
+ // Turn the motor off
+ //
+ MotorOff (FdcDev);
+
+ if (Operation == READ) {
+ //
+ // Cache the data read
+ //
+ if (Lba0 == 0 && FdcDev->Cache == NULL) {
+ FdcDev->Cache = AllocateCopyPool (BlockSize, Buffer);
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Free cache for a floppy disk.
+
+ @param FdcDev A Pointer to FDC_BLK_IO_DEV instance
+
+**/
+VOID
+FdcFreeCache (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ if (FdcDev->Cache != NULL) {
+ FreePool (FdcDev->Cache);
+ FdcDev->Cache = NULL;
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
new file mode 100644
index 0000000000..16ad6b02e3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyCtrl.c
@@ -0,0 +1,1398 @@
+/** @file
+ Internal floppy disk controller programming functions for the floppy driver.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaFloppy.h"
+
+/**
+ Detect whether a floppy drive is present or not.
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS The floppy disk drive is present
+ @retval EFI_NOT_FOUND The floppy disk drive is not present
+**/
+EFI_STATUS
+DiscoverFddDevice (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+
+ FdcDev->BlkIo.Media = &FdcDev->BlkMedia;
+
+ Status = FddIdentify (FdcDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ FdcDev->BlkIo.Reset = FdcReset;
+ FdcDev->BlkIo.FlushBlocks = FddFlushBlocks;
+ FdcDev->BlkIo.ReadBlocks = FddReadBlocks;
+ FdcDev->BlkIo.WriteBlocks = FddWriteBlocks;
+ FdcDev->BlkMedia.LogicalPartition = FALSE;
+ FdcDev->BlkMedia.WriteCaching = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do recalibrate and check if the drive is present or not
+ and set the media parameters if the driver is present.
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS The floppy disk drive is present
+ @retval EFI_DEVICE_ERROR The floppy disk drive is not present
+**/
+EFI_STATUS
+FddIdentify (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Set Floppy Disk Controller's motor on
+ //
+ Status = MotorOn (FdcDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Recalibrate (FdcDev);
+
+ if (EFI_ERROR (Status)) {
+ MotorOff (FdcDev);
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set Media Parameter
+ //
+ FdcDev->BlkIo.Media->RemovableMedia = TRUE;
+ FdcDev->BlkIo.Media->MediaPresent = TRUE;
+ FdcDev->BlkIo.Media->MediaId = 0;
+
+ //
+ // Check Media
+ //
+ Status = DisketChanged (FdcDev);
+
+ if (Status == EFI_NO_MEDIA) {
+ FdcDev->BlkIo.Media->MediaPresent = FALSE;
+ } else if ((Status != EFI_MEDIA_CHANGED) &&
+ (Status != EFI_SUCCESS)) {
+ MotorOff (FdcDev);
+ return Status;
+ }
+
+ //
+ // Check Disk Write Protected
+ //
+ Status = SenseDrvStatus (FdcDev, 0);
+
+ if (Status == EFI_WRITE_PROTECTED) {
+ FdcDev->BlkIo.Media->ReadOnly = TRUE;
+ } else if (Status == EFI_SUCCESS) {
+ FdcDev->BlkIo.Media->ReadOnly = FALSE;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+ MotorOff (FdcDev);
+
+ //
+ // Set Media Default Type
+ //
+ FdcDev->BlkIo.Media->BlockSize = DISK_1440K_BYTEPERSECTOR;
+ FdcDev->BlkIo.Media->LastBlock = DISK_1440K_EOT * 2 * (DISK_1440K_MAXTRACKNUM + 1) - 1;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Floppy Logic Drive.
+
+ @param FdcDev FDC_BLK_IO_DEV * : A pointer to the FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: The Floppy Logic Drive is reset
+ @retval EFI_DEVICE_ERROR: The Floppy Logic Drive is not functioning correctly and
+ can not be reset
+
+**/
+EFI_STATUS
+FddReset (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ UINT8 Data;
+ UINT8 StatusRegister0;
+ UINT8 PresentCylinderNumber;
+ UINTN Index;
+
+ //
+ // Report reset progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA | EFI_P_PC_RESET,
+ FdcDev->DevicePath
+ );
+
+ //
+ // Reset specified Floppy Logic Drive according to FdcDev -> Disk
+ // Set Digital Output Register(DOR) to do reset work
+ // bit0 & bit1 of DOR : Drive Select
+ // bit2 : Reset bit
+ // bit3 : DMA and Int bit
+ // Reset : a "0" written to bit2 resets the FDC, this reset will remain
+ // active until
+ // a "1" is written to this bit.
+ // Reset step 1:
+ // use bit0 & bit1 to select the logic drive
+ // write "0" to bit2
+ //
+ Data = 0x0;
+ Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));
+ FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
+
+ //
+ // wait some time,at least 120us
+ //
+ MicroSecondDelay (500);
+
+ //
+ // Reset step 2:
+ // write "1" to bit2
+ // write "1" to bit3 : enable DMA
+ //
+ Data |= 0x0C;
+ FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
+
+ //
+ // Experience value
+ //
+ MicroSecondDelay (2000);
+
+ //
+ // wait specified floppy logic drive is not busy
+ //
+ if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set the Transfer Data Rate
+ //
+ FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);
+
+ //
+ // Experience value
+ //
+ MicroSecondDelay (100);
+
+ //
+ // Issue Sense interrupt command for each drive (total 4 drives)
+ //
+ for (Index = 0; Index < 4; Index++) {
+ if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // issue Specify command
+ //
+ if (EFI_ERROR (Specify (FdcDev))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Turn the floppy disk drive's motor on.
+ The drive's motor must be on before any command can be executed.
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS The drive's motor was turned on successfully
+ @retval EFI_DEVICE_ERROR The drive is busy, so can not turn motor on
+**/
+EFI_STATUS
+MotorOn (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DorData;
+
+ //
+ // Control of the floppy drive motors is a big pain. If motor is off, you have
+ // to turn it on first. But you can not leave the motor on all the time, since
+ // that would wear out the disk. On the other hand, if you turn the motor off
+ // after each operation, the system performance will be awful. The compromise
+ // used in this driver is to leave the motor on for 2 seconds after
+ // each operation. If a new operation is started in that interval(2s),
+ // the motor need not be turned on again. If no new operation is started,
+ // a timer goes off and the motor is turned off
+ //
+ //
+ // Cancel the timer
+ //
+ Status = gBS->SetTimer (FdcDev->Event, TimerCancel, 0);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Get the motor status
+ //
+ DorData = FdcReadPort (FdcDev, FDC_REGISTER_DOR);
+
+ if (((FdcDev->Disk == FdcDisk0) && ((DorData & 0x10) == 0x10)) ||
+ ((FdcDev->Disk == FdcDisk1) && ((DorData & 0x21) == 0x21))
+ ) {
+ return EFI_SUCCESS;
+ }
+ //
+ // The drive's motor is off, so need turn it on
+ // first look at command and drive are busy or not
+ //
+ if (EFI_ERROR (FddWaitForBSYClear (FdcDev, 1))) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // for drive A: 1CH, drive B: 2DH
+ //
+ DorData = 0x0C;
+ DorData = (UINT8) (DorData | (SELECT_DRV & FdcDev->Disk));
+ if (FdcDev->Disk == FdcDisk0) {
+ //
+ // drive A
+ //
+ DorData |= DRVA_MOTOR_ON;
+ } else {
+ //
+ // drive B
+ //
+ DorData |= DRVB_MOTOR_ON;
+ }
+
+ FdcWritePort (FdcDev, FDC_REGISTER_DOR, DorData);
+
+ //
+ // Experience value
+ //
+ MicroSecondDelay (4000);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set a Timer and when Timer goes off, turn the motor off.
+
+ @param[in] FdcDev A pointer to the FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS Set the Timer successfully
+ @retval EFI_INVALID_PARAMETER Fail to Set the timer
+**/
+EFI_STATUS
+MotorOff (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ //
+ // Set the timer : 2s
+ //
+ return gBS->SetTimer (FdcDev->Event, TimerRelative, 20000000);
+}
+
+/**
+ Detect whether the disk in the drive is changed or not.
+
+ @param[in] FdcDev A pointer to FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS No disk media change
+ @retval EFI_DEVICE_ERROR Fail to do the recalibrate or seek operation
+ @retval EFI_NO_MEDIA No disk in the drive
+ @retval EFI_MEDIA_CHANGED There is a new disk in the drive
+**/
+EFI_STATUS
+DisketChanged (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Check change line
+ //
+ Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
+
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ if ((Data & DIR_DCL) == 0x80) {
+ //
+ // disk change line is active
+ //
+ if (FdcDev->PresentCylinderNumber != 0) {
+ Status = Recalibrate (FdcDev);
+ } else {
+ Status = Seek (FdcDev, 0x30);
+ }
+
+ if (EFI_ERROR (Status)) {
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ //
+ // Fail to do the seek or recalibrate operation
+ //
+ }
+
+ Data = FdcReadPort (FdcDev, FDC_REGISTER_DIR);
+
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ if ((Data & DIR_DCL) == 0x80) {
+ return EFI_NO_MEDIA;
+ }
+
+ return EFI_MEDIA_CHANGED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do the Specify command, this command sets DMA operation
+ and the initial values for each of the three internal
+ times: HUT, SRT and HLT.
+
+ @param[in] FdcDev Pointer to instance of FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS Execute the Specify command successfully
+ @retval EFI_DEVICE_ERROR Fail to execute the command
+**/
+EFI_STATUS
+Specify (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ FDD_SPECIFY_CMD Command;
+ UINTN Index;
+ UINT8 *CommandPointer;
+
+ ZeroMem (&Command, sizeof (FDD_SPECIFY_CMD));
+ Command.CommandCode = SPECIFY_CMD;
+ //
+ // set SRT, HUT
+ //
+ Command.SrtHut = 0xdf;
+ //
+ // 0xdf;
+ //
+ // set HLT and DMA
+ //
+ Command.HltNd = 0x02;
+
+ CommandPointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDD_SPECIFY_CMD); Index++) {
+ if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the head of floppy drive to track 0.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+ @retval EFI_SUCCESS: Execute the Recalibrate operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the Recalibrate operation
+
+**/
+EFI_STATUS
+Recalibrate (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ FDD_COMMAND_PACKET2 Command;
+ UINTN Index;
+ UINT8 StatusRegister0;
+ UINT8 PresentCylinderNumber;
+ UINT8 *CommandPointer;
+ UINT8 Count;
+
+ Count = 2;
+
+ while (Count > 0) {
+ ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));
+ Command.CommandCode = RECALIBRATE_CMD;
+ //
+ // drive select
+ //
+ if (FdcDev->Disk == FdcDisk0) {
+ Command.DiskHeadSel = 0;
+ //
+ // 0
+ //
+ } else {
+ Command.DiskHeadSel = 1;
+ //
+ // 1
+ //
+ }
+
+ CommandPointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {
+ if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Experience value
+ //
+ MicroSecondDelay (250000);
+ //
+ // need modify according to 1.44M or 2.88M
+ //
+ if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((StatusRegister0 & 0xf0) == 0x20 && PresentCylinderNumber == 0) {
+ FdcDev->PresentCylinderNumber = 0;
+ FdcDev->ControllerState->NeedRecalibrate = FALSE;
+ return EFI_SUCCESS;
+ } else {
+ Count--;
+ if (Count == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+ //
+ // end while
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the head of floppy drive to the new cylinder.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+ @param Lba EFI_LBA : The logic block address want to seek
+
+ @retval EFI_SUCCESS: Execute the Seek operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the Seek operation
+
+**/
+EFI_STATUS
+Seek (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba
+ )
+{
+ FDD_SEEK_CMD Command;
+ UINT8 EndOfTrack;
+ UINT8 Head;
+ UINT8 Cylinder;
+ UINT8 StatusRegister0;
+ UINT8 *CommandPointer;
+ UINT8 PresentCylinderNumber;
+ UINTN Index;
+ UINT8 DelayTime;
+
+ if (FdcDev->ControllerState->NeedRecalibrate) {
+ if (EFI_ERROR (Recalibrate (FdcDev))) {
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ EndOfTrack = DISK_1440K_EOT;
+ //
+ // Calculate cylinder based on Lba and EOT
+ //
+ Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
+
+ //
+ // if the destination cylinder is the present cylinder, unnecessary to do the
+ // seek operation
+ //
+ if (FdcDev->PresentCylinderNumber == Cylinder) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Calculate the head : 0 or 1
+ //
+ Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+
+ ZeroMem (&Command, sizeof (FDD_SEEK_CMD));
+ Command.CommandCode = SEEK_CMD;
+ if (FdcDev->Disk == FdcDisk0) {
+ Command.DiskHeadSel = 0;
+ //
+ // 0
+ //
+ } else {
+ Command.DiskHeadSel = 1;
+ //
+ // 1
+ //
+ }
+
+ Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));
+ Command.NewCylinder = Cylinder;
+
+ CommandPointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDD_SEEK_CMD); Index++) {
+ if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Io delay
+ //
+ MicroSecondDelay (100);
+
+ //
+ // Calculate waiting time
+ //
+ if (FdcDev->PresentCylinderNumber > Cylinder) {
+ DelayTime = (UINT8) (FdcDev->PresentCylinderNumber - Cylinder);
+ } else {
+ DelayTime = (UINT8) (Cylinder - FdcDev->PresentCylinderNumber);
+ }
+
+ MicroSecondDelay ((DelayTime + 1) * 4000);
+
+ if (EFI_ERROR (SenseIntStatus (FdcDev, &StatusRegister0, &PresentCylinderNumber))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((StatusRegister0 & 0xf0) == 0x20) {
+ FdcDev->PresentCylinderNumber = Command.NewCylinder;
+ return EFI_SUCCESS;
+ } else {
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Do the Sense Interrupt Status command, this command
+ resets the interrupt signal.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+ @param StatusRegister0 UINT8 *: Be used to save Status Register 0 read from FDC
+ @param PresentCylinderNumber UINT8 *: Be used to save present cylinder number
+ read from FDC
+
+ @retval EFI_SUCCESS: Execute the Sense Interrupt Status command successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the command
+
+**/
+EFI_STATUS
+SenseIntStatus (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN OUT UINT8 *StatusRegister0,
+ IN OUT UINT8 *PresentCylinderNumber
+ )
+{
+ UINT8 Command;
+
+ Command = SENSE_INT_STATUS_CMD;
+ if (EFI_ERROR (DataOutByte (FdcDev, &Command))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (EFI_ERROR (DataInByte (FdcDev, StatusRegister0))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (EFI_ERROR (DataInByte (FdcDev, PresentCylinderNumber))) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Do the Sense Drive Status command.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+ @param Lba EFI_LBA : Logic block address
+
+ @retval EFI_SUCCESS: Execute the Sense Drive Status command successfully
+ @retval EFI_DEVICE_ERROR: Fail to execute the command
+ @retval EFI_WRITE_PROTECTED:The disk is write protected
+
+**/
+EFI_STATUS
+SenseDrvStatus (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba
+ )
+{
+ FDD_COMMAND_PACKET2 Command;
+ UINT8 Head;
+ UINT8 EndOfTrack;
+ UINTN Index;
+ UINT8 StatusRegister3;
+ UINT8 *CommandPointer;
+
+ //
+ // Sense Drive Status command obtains drive status information,
+ // it has not execution phase and goes directly to the result phase from the
+ // command phase, Status Register 3 contains the drive status information
+ //
+ ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET2));
+ Command.CommandCode = SENSE_DRV_STATUS_CMD;
+
+ if (FdcDev->Disk == FdcDisk0) {
+ Command.DiskHeadSel = 0;
+ } else {
+ Command.DiskHeadSel = 1;
+ }
+
+ EndOfTrack = DISK_1440K_EOT;
+ Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+ Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));
+
+ CommandPointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET2); Index++) {
+ if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (EFI_ERROR (DataInByte (FdcDev, &StatusRegister3))) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ //
+ // Check Status Register 3 to get drive status information
+ //
+ return CheckStatus3 (StatusRegister3);
+}
+
+/**
+ Update the disk media properties and if necessary reinstall Block I/O interface.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS: Do the operation successfully
+ @retval EFI_DEVICE_ERROR: Fail to the operation
+
+**/
+EFI_STATUS
+DetectMedia (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Reset;
+ BOOLEAN ReadOnlyLastTime;
+ BOOLEAN MediaPresentLastTime;
+
+ Reset = FALSE;
+ ReadOnlyLastTime = FdcDev->BlkIo.Media->ReadOnly;
+ MediaPresentLastTime = FdcDev->BlkIo.Media->MediaPresent;
+
+ //
+ // Check disk change
+ //
+ Status = DisketChanged (FdcDev);
+
+ if (Status == EFI_MEDIA_CHANGED) {
+ FdcDev->BlkIo.Media->MediaId++;
+ FdcDev->BlkIo.Media->MediaPresent = TRUE;
+ Reset = TRUE;
+ } else if (Status == EFI_NO_MEDIA) {
+ FdcDev->BlkIo.Media->MediaPresent = FALSE;
+ } else if (Status != EFI_SUCCESS) {
+ MotorOff (FdcDev);
+ return Status;
+ //
+ // EFI_DEVICE_ERROR
+ //
+ }
+
+ if (FdcDev->BlkIo.Media->MediaPresent) {
+ //
+ // Check disk write protected
+ //
+ Status = SenseDrvStatus (FdcDev, 0);
+ if (Status == EFI_WRITE_PROTECTED) {
+ FdcDev->BlkIo.Media->ReadOnly = TRUE;
+ } else {
+ FdcDev->BlkIo.Media->ReadOnly = FALSE;
+ }
+ }
+
+ if (FdcDev->BlkIo.Media->MediaPresent && (ReadOnlyLastTime != FdcDev->BlkIo.Media->ReadOnly)) {
+ Reset = TRUE;
+ }
+
+ if (MediaPresentLastTime != FdcDev->BlkIo.Media->MediaPresent) {
+ Reset = TRUE;
+ }
+
+ if (Reset) {
+ Status = gBS->ReinstallProtocolInterface (
+ FdcDev->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &FdcDev->BlkIo,
+ &FdcDev->BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set the data rate and so on.
+
+ @param FdcDev A pointer to FDC_BLK_IO_DEV
+
+ @retval EFI_SUCCESS success to set the data rate
+**/
+EFI_STATUS
+Setup (
+ IN FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Set data rate 500kbs
+ //
+ FdcWritePort (FdcDev, FDC_REGISTER_CCR, 0x0);
+
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ Status = Specify (FdcDev);
+
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read or Write a number of blocks in the same cylinder.
+
+ @param FdcDev A pointer to FDC_BLK_IO_DEV
+ @param HostAddress device address
+ @param Lba The starting logic block address to read from on the device
+ @param NumberOfBlocks The number of block wanted to be read or write
+ @param Read Operation type: read or write
+
+ @retval EFI_SUCCESS Success operate
+
+**/
+EFI_STATUS
+ReadWriteDataSector (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN VOID *HostAddress,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks,
+ IN BOOLEAN Read
+ )
+{
+ EFI_STATUS Status;
+ FDD_COMMAND_PACKET1 Command;
+ FDD_RESULT_PACKET Result;
+ UINTN Index;
+ UINTN Times;
+ UINT8 *CommandPointer;
+
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINTN NumberofBytes;
+ VOID *Mapping;
+ EFI_ISA_IO_PROTOCOL_OPERATION Operation;
+ EFI_STATUS Status1;
+ UINT8 Channel;
+ EFI_ISA_ACPI_RESOURCE *ResourceItem;
+ UINT32 Attribute;
+
+ Status = Seek (FdcDev, Lba);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Map Dma
+ //
+ IsaIo = FdcDev->IsaIo;
+ NumberofBytes = NumberOfBlocks * 512;
+ if (Read == READ) {
+ Operation = EfiIsaIoOperationSlaveWrite;
+ } else {
+ Operation = EfiIsaIoOperationSlaveRead;
+ }
+
+ ResourceItem = IsaIo->ResourceList->ResourceItem;
+ Index = 0;
+ while (ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList) {
+ if (ResourceItem[Index].Type == EfiIsaAcpiResourceDma) {
+ break;
+ }
+
+ Index++;
+ }
+
+ if (ResourceItem[Index].Type == EfiIsaAcpiResourceEndOfList) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Channel = (UINT8) IsaIo->ResourceList->ResourceItem[Index].StartRange;
+ Attribute = IsaIo->ResourceList->ResourceItem[Index].Attribute;
+
+ Status1 = IsaIo->Map (
+ IsaIo,
+ Operation,
+ Channel,
+ Attribute,
+ HostAddress,
+ &NumberofBytes,
+ &DeviceAddress,
+ &Mapping
+ );
+ if (EFI_ERROR (Status1)) {
+ return Status1;
+ }
+
+ //
+ // Allocate Read or Write command packet
+ //
+ ZeroMem (&Command, sizeof (FDD_COMMAND_PACKET1));
+ if (Read == READ) {
+ Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK;
+ } else {
+ Command.CommandCode = WRITE_DATA_CMD | CMD_MT | CMD_MFM;
+ }
+
+ FillPara (FdcDev, Lba, &Command);
+
+ //
+ // Write command bytes to FDC
+ //
+ CommandPointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDD_COMMAND_PACKET1); Index++) {
+ if (EFI_ERROR (DataOutByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // wait for some time
+ //
+ Times = (STALL_1_SECOND / 50) + 1;
+ do {
+ if ((FdcReadPort (FdcDev, FDC_REGISTER_MSR) & 0xc0) == 0xc0) {
+ break;
+ }
+
+ MicroSecondDelay (50);
+ Times = Times - 1;
+ } while (Times > 0);
+
+ if (Times == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Read result bytes from FDC
+ //
+ CommandPointer = (UINT8 *) (&Result);
+ for (Index = 0; Index < sizeof (FDD_RESULT_PACKET); Index++) {
+ if (EFI_ERROR (DataInByte (FdcDev, CommandPointer++))) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Flush before Unmap
+ //
+ if (Read == READ) {
+ Status1 = IsaIo->Flush (IsaIo);
+ if (EFI_ERROR (Status1)) {
+ return Status1;
+ }
+ }
+ //
+ // Unmap Dma
+ //
+ Status1 = IsaIo->Unmap (IsaIo, Mapping);
+ if (EFI_ERROR (Status1)) {
+ return Status1;
+ }
+
+ return CheckResult (&Result, FdcDev);
+}
+
+/**
+ Fill in FDD command's parameter.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Lba The starting logic block address to read from on the device
+ @param Command FDD command
+
+**/
+VOID
+FillPara (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA Lba,
+ IN FDD_COMMAND_PACKET1 *Command
+ )
+{
+ UINT8 EndOfTrack;
+
+ //
+ // Get EndOfTrack from the Para table
+ //
+ EndOfTrack = DISK_1440K_EOT;
+
+ //
+ // Fill the command parameter
+ //
+ if (FdcDev->Disk == FdcDisk0) {
+ Command->DiskHeadSel = 0;
+ } else {
+ Command->DiskHeadSel = 1;
+ }
+
+ Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
+ Command->Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+ Command->Sector = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);
+ Command->DiskHeadSel = (UINT8) (Command->DiskHeadSel | (Command->Head << 2));
+ Command->Number = DISK_1440K_NUMBER;
+ Command->EndOfTrack = DISK_1440K_EOT;
+ Command->GapLength = DISK_1440K_GPL;
+ Command->DataLength = DISK_1440K_DTL;
+}
+
+/**
+ Read result byte from Data Register of FDC.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Pointer Buffer to store the byte read from FDC
+
+ @retval EFI_SUCCESS Read result byte from FDC successfully
+ @retval EFI_DEVICE_ERROR The FDC is not ready to be read
+
+**/
+EFI_STATUS
+DataInByte (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ OUT UINT8 *Pointer
+ )
+{
+ UINT8 Data;
+
+ //
+ // wait for 1ms and detect the FDC is ready to be read
+ //
+ if (EFI_ERROR (FddDRQReady (FdcDev, DATA_IN, 1))) {
+ return EFI_DEVICE_ERROR;
+ //
+ // is not ready
+ //
+ }
+
+ Data = FdcReadPort (FdcDev, FDC_REGISTER_DTR);
+
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ *Pointer = Data;
+ return EFI_SUCCESS;
+}
+
+/**
+ Write command byte to Data Register of FDC.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Pointer Be used to save command byte written to FDC
+
+ @retval EFI_SUCCESS: Write command byte to FDC successfully
+ @retval EFI_DEVICE_ERROR: The FDC is not ready to be written
+
+**/
+EFI_STATUS
+DataOutByte (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT8 *Pointer
+ )
+{
+ UINT8 Data;
+
+ //
+ // wait for 1ms and detect the FDC is ready to be written
+ //
+ if (EFI_ERROR (FddDRQReady (FdcDev, DATA_OUT, 1))) {
+ //
+ // Not ready
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Data = *Pointer;
+
+ FdcWritePort (FdcDev, FDC_REGISTER_DTR, Data);
+
+ //
+ // Io delay
+ //
+ MicroSecondDelay (50);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect the specified floppy logic drive is busy or not within a period of time.
+
+ @param FdcDev Indicate it is drive A or drive B
+ @param Timeout The time period for waiting
+
+ @retval EFI_SUCCESS: The drive and command are not busy
+ @retval EFI_TIMEOUT: The drive or command is still busy after a period time that
+ set by Timeout
+
+**/
+EFI_STATUS
+FddWaitForBSYClear (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 StatusRegister;
+ UINT8 Mask;
+
+ //
+ // How to determine drive and command are busy or not: by the bits of
+ // Main Status Register
+ // bit0: Drive 0 busy (drive A)
+ // bit1: Drive 1 busy (drive B)
+ // bit4: Command busy
+ //
+ //
+ // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
+ //
+ Mask = (UINT8) ((FdcDev->Disk == FdcDisk0 ? MSR_DAB : MSR_DBB) | MSR_CB);
+
+ Delay = ((Timeout * STALL_1_MSECOND) / 50) + 1;
+ do {
+ StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
+ if ((StatusRegister & Mask) == 0x00) {
+ break;
+ //
+ // not busy
+ //
+ }
+
+ MicroSecondDelay (50);
+ Delay = Delay - 1;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Determine whether FDC is ready to write or read.
+
+ @param FdcDev Pointer to instance of FDC_BLK_IO_DEV
+ @param Dio BOOLEAN: Indicate the FDC is waiting to write or read
+ @param Timeout The time period for waiting
+
+ @retval EFI_SUCCESS: FDC is ready to write or read
+ @retval EFI_NOT_READY: FDC is not ready within the specified time period
+
+**/
+EFI_STATUS
+FddDRQReady (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN BOOLEAN Dio,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 StatusRegister;
+ UINT8 DataInOut;
+
+ //
+ // Before writing to FDC or reading from FDC, the Host must examine
+ // the bit7(RQM) and bit6(DIO) of the Main Status Register.
+ // That is to say:
+ // command bytes can not be written to Data Register
+ // unless RQM is 1 and DIO is 0
+ // result bytes can not be read from Data Register
+ // unless RQM is 1 and DIO is 1
+ //
+ DataInOut = (UINT8) (Dio << 6);
+ //
+ // in order to compare bit6
+ //
+ Delay = ((Timeout * STALL_1_MSECOND) / 50) + 1;
+ do {
+ StatusRegister = FdcReadPort (FdcDev, FDC_REGISTER_MSR);
+ if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == DataInOut) {
+ break;
+ //
+ // FDC is ready
+ //
+ }
+
+ MicroSecondDelay (50);
+ //
+ // Stall for 50 us
+ //
+ Delay = Delay - 1;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_NOT_READY;
+ //
+ // FDC is not ready within the specified time period
+ //
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Set FDC control structure's attribute according to result.
+
+ @param Result Point to result structure
+ @param FdcDev FDC control structure
+
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_DEVICE_ERROR - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+
+**/
+EFI_STATUS
+CheckResult (
+ IN FDD_RESULT_PACKET *Result,
+ IN OUT FDC_BLK_IO_DEV *FdcDev
+ )
+{
+ //
+ // Check Status Register0
+ //
+ if ((Result->Status0 & STS0_IC) != IC_NT) {
+ if ((Result->Status0 & STS0_SE) == 0x20) {
+ //
+ // seek error
+ //
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ }
+
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check Status Register1
+ //
+ if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check Status Register2
+ //
+ if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {
+ FdcDev->ControllerState->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check the drive status information.
+
+ @param StatusRegister3 the value of Status Register 3
+
+ @retval EFI_SUCCESS The disk is not write protected
+ @retval EFI_WRITE_PROTECTED: The disk is write protected
+
+**/
+EFI_STATUS
+CheckStatus3 (
+ IN UINT8 StatusRegister3
+ )
+{
+ if ((StatusRegister3 & STS3_WP) != 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Calculate the number of block in the same cylinder according to LBA.
+
+ @param FdcDev FDC_BLK_IO_DEV *: A pointer to FDC_BLK_IO_DEV
+ @param LBA EFI_LBA: The starting logic block address
+ @param NumberOfBlocks UINTN: The number of blocks
+
+ @return The number of blocks in the same cylinder which the starting
+ logic block address is LBA
+
+**/
+UINTN
+GetTransferBlockCount (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN EFI_LBA LBA,
+ IN UINTN NumberOfBlocks
+ )
+{
+ UINT8 EndOfTrack;
+ UINT8 Head;
+ UINT8 SectorsInTrack;
+
+ //
+ // Calculate the number of block in the same cylinder
+ //
+ EndOfTrack = DISK_1440K_EOT;
+ Head = (UINT8) ((UINTN) LBA / EndOfTrack % 2);
+
+ SectorsInTrack = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) LBA % EndOfTrack));
+ if (SectorsInTrack < NumberOfBlocks) {
+ return SectorsInTrack;
+ } else {
+ return NumberOfBlocks;
+ }
+}
+
+/**
+ When the Timer(2s) off, turn the drive's motor off.
+
+ @param Event EFI_EVENT: Event(the timer) whose notification function is being
+ invoked
+ @param Context VOID *: Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+FddTimerProc (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ FDC_BLK_IO_DEV *FdcDev;
+ UINT8 Data;
+
+ FdcDev = (FDC_BLK_IO_DEV *) Context;
+
+ //
+ // Get the motor status
+ //
+ Data = FdcReadPort (FdcDev, FDC_REGISTER_DOR);
+
+ if (((FdcDev->Disk == FdcDisk0) && ((Data & 0x10) != 0x10)) ||
+ ((FdcDev->Disk == FdcDisk1) && ((Data & 0x21) != 0x21))
+ ) {
+ return ;
+ }
+ //
+ // the motor is on, so need motor off
+ //
+ Data = 0x0C;
+ Data = (UINT8) (Data | (SELECT_DRV & FdcDev->Disk));
+ FdcWritePort (FdcDev, FDC_REGISTER_DOR, Data);
+ MicroSecondDelay (500);
+}
+
+/**
+ Read an I/O port of FDC.
+
+ @param[in] FdcDev A pointer to FDC_BLK_IO_DEV.
+ @param[in] Offset The address offset of the I/O port.
+
+ @retval 8-bit data read from the I/O port.
+**/
+UINT8
+FdcReadPort (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT32 Offset
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Status = FdcDev->IsaIo->Io.Read (
+ FdcDev->IsaIo,
+ EfiIsaIoWidthUint8,
+ FdcDev->BaseAddress + Offset,
+ 1,
+ &Data
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Data;
+}
+
+/**
+ Write an I/O port of FDC.
+
+ @param[in] FdcDev A pointer to FDC_BLK_IO_DEV
+ @param[in] Offset The address offset of the I/O port
+ @param[in] Data 8-bit Value written to the I/O port
+**/
+VOID
+FdcWritePort (
+ IN FDC_BLK_IO_DEV *FdcDev,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+
+ Status = FdcDev->IsaIo->Io.Write (
+ FdcDev->IsaIo,
+ EfiIsaIoWidthUint8,
+ FdcDev->BaseAddress + Offset,
+ 1,
+ &Data
+ );
+ ASSERT_EFI_ERROR (Status);
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf
new file mode 100644
index 0000000000..65756209f5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf
@@ -0,0 +1,78 @@
+## @file
+# Provides ISA Floppy Disk support.
+#
+# Provides ISA Floppy Disk UEFI Driver conforming to the UEFI driver model. The
+# driver provides support for two drives per controller, DMA channel 2, diskette
+# change line and write protect. Currently only 1.44MB drives are supported.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaFloppyDxe
+ MODULE_UNI_FILE = IsaFloppyDxe.uni
+ FILE_GUID = 0abd8284-6da3-4616-971a-83a5148067ba
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIsaFloppy
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gFdcControllerDriver;
+# COMPONENT_NAME = gIsaFloppyComponentName;
+# COMPONENT_NAME2 = gIsaFloppyComponentName2;
+#
+[Sources]
+ ComponentName.c
+ ComponentName.h
+ IsaFloppyCtrl.c
+ IsaFloppyBlock.c
+ IsaFloppy.c
+ IsaFloppy.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+ TimerLib
+ PcdLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdComponentNameDisable ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdComponentName2Disable ## CONSUMES
+
+#
+# [Event]
+# ##
+# # Floppy motor control timer event.
+# #
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaFloppyDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.uni
new file mode 100644
index 0000000000..b33eb0ebad
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxeExtra.uni
new file mode 100644
index 0000000000..e9e4b5bfd1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/Fdc.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/Fdc.h
new file mode 100644
index 0000000000..a6a7e42aee
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/Fdc.h
@@ -0,0 +1,235 @@
+/** @file
+Definition of FDC registers and structures.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PEI_RECOVERY_FDC_H_
+#define _PEI_RECOVERY_FDC_H_
+
+//
+// FDC Registers
+//
+#define FDC_REGISTER_DOR 2 //Digital Output Register
+#define FDC_REGISTER_MSR 4 //Main Status Register
+#define FDC_REGISTER_DTR 5 //Data Register
+#define FDC_REGISTER_CCR 7 //Configuration Control Register(data rate select)
+#define FDC_REGISTER_DIR 7 //Digital Input Register(diskchange)
+//
+// FDC Register Bit Definitions
+//
+//
+// Digital Out Register(WO)
+//
+#define SELECT_DRV BIT0 // Select Drive: 0=A 1=B
+#define RESET_FDC BIT2 // Reset FDC
+#define INT_DMA_ENABLE BIT3 // Enable Int & DMA
+#define DRVA_MOTOR_ON BIT4 // Turn On Drive A Motor
+#define DRVB_MOTOR_ON BIT5 // Turn On Drive B Motor
+//
+// Main Status Register(RO)
+//
+#define MSR_DAB BIT0 // Drive A Busy
+#define MSR_DBB BIT1 // Drive B Busy
+#define MSR_CB BIT4 // FDC Busy
+#define MSR_NDM BIT5 // Non-DMA Mode
+#define MSR_DIO BIT6 // Data Input/Output
+#define MSR_RQM BIT7 // Request For Master
+//
+// Configuration Control Register(WO)
+//
+#define CCR_DRC (BIT0 | BIT1) // Data Rate select
+//
+// Digital Input Register(RO)
+//
+#define DIR_DCL BIT7 // Disk change line
+#define DRC_500KBS 0x0 // 500K
+#define DRC_300KBS 0x01 // 300K
+#define DRC_250KBS 0x02 // 250K
+//
+// FDC Command Code
+//
+#define READ_DATA_CMD 0x06
+#define SEEK_CMD 0x0F
+#define RECALIBRATE_CMD 0x07
+#define SENSE_INT_STATUS_CMD 0x08
+#define SPECIFY_CMD 0x03
+#define SENSE_DRV_STATUS_CMD 0x04
+
+///
+/// CMD_MT: Multi_Track Selector
+/// when set , this flag selects the multi-track operating mode.
+/// In this mode, the FDC treats a complete cylinder under head0 and 1 as a single track
+///
+#define CMD_MT BIT7
+
+///
+/// CMD_MFM: MFM/FM Mode Selector
+/// A one selects the double density(MFM) mode
+/// A zero selects single density (FM) mode
+///
+#define CMD_MFM BIT6
+
+///
+/// CMD_SK: Skip Flag
+/// When set to 1, sectors containing a deleted data address mark will automatically be skipped
+/// during the execution of Read Data.
+/// When set to 0, the sector is read or written the same as the read and write commands.
+///
+#define CMD_SK BIT5
+
+//
+// FDC Status Register Bit Definitions
+//
+//
+// Status Register 0
+//
+#define STS0_IC (BIT7 | BIT6) // Interrupt Code
+#define STS0_SE BIT5 // Seek End: the FDC completed a seek or recalibrate command
+#define STS0_EC BIT4 // Equipment Check
+#define STS0_NR BIT3 // Not Ready(unused), this bit is always 0
+#define STS0_HA BIT2 // Head Address: the current head address
+//
+// STS0_US1 & STS0_US0: Drive Select(the current selected drive)
+//
+#define STS0_US1 BIT1 // Unit Select1
+#define STS0_US0 BIT0 // Unit Select0
+//
+// Status Register 1
+//
+#define STS1_EN BIT7 // End of Cylinder
+//
+// BIT6 is unused
+//
+#define STS1_DE BIT5 // Data Error: The FDC detected a CRC error in either the ID field or data field of a sector
+#define STS1_OR BIT4 // Overrun/Underrun: Becomes set if FDC does not receive CPU or DMA service within the required time interval
+//
+// BIT3 is unused
+//
+#define STS1_ND BIT2 // No data
+#define STS1_NW BIT1 // Not Writable
+#define STS1_MA BIT0 // Missing Address Mark
+
+//
+// Status Register 2
+//
+// BIT7 is unused
+//
+#define STS2_CM BIT6 // Control Mark
+#define STS2_DD BIT5 // Data Error in Data Field: The FDC detected a CRC error in the data field
+#define STS2_WC BIT4 // Wrong Cylinder: The track address from sector ID field is different from the track address maintained inside FDC
+//
+// BIT3 is unused
+// BIT2 is unused
+//
+#define STS2_BC BIT1 // Bad Cylinder
+#define STS2_MD BIT0 // Missing Address Mark in DataField
+
+//
+// Status Register 3
+//
+// BIT7 is unused
+//
+#define STS3_WP BIT6 // Write Protected
+//
+// BIT5 is unused
+//
+#define STS3_T0 BIT4 // Track 0
+//
+// BIT3 is unused
+//
+#define STS3_HD BIT2 // Head Address
+//
+// STS3_US1 & STS3_US0 : Drive Select
+//
+#define STS3_US1 BIT1 // Unit Select1
+#define STS3_US0 BIT0 // Unit Select0
+
+//
+// Status Register 0 Interrupt Code Description
+//
+#define IC_NT 0x0 // Normal Termination of Command
+#define IC_AT 0x40 // Abnormal Termination of Command
+#define IC_IC 0x80 // Invalid Command
+#define IC_ATRC 0xC0 // Abnormal Termination caused by Polling
+
+///
+/// Table of parameters for diskette
+///
+typedef struct {
+ UINT8 EndOfTrack; ///< End of track
+ UINT8 GapLength; ///< Gap length
+ UINT8 DataLength; ///< Data length
+ UINT8 Number; ///< Number of bytes per sector
+ UINT8 MaxTrackNum;
+ UINT8 MotorStartTime;
+ UINT8 MotorOffTime;
+ UINT8 HeadSettlingTime;
+ UINT8 DataTransferRate;
+} DISKET_PARA_TABLE;
+
+///
+/// Structure for FDC Command Packet 1
+///
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+ UINT8 Cylinder;
+ UINT8 Head;
+ UINT8 Sector;
+ UINT8 Number;
+ UINT8 EndOfTrack;
+ UINT8 GapLength;
+ UINT8 DataLength;
+} FDC_COMMAND_PACKET1;
+
+///
+/// Structure for FDC Command Packet 2
+///
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+} FDC_COMMAND_PACKET2;
+
+///
+/// Structure for FDC Specify Command
+///
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 SrtHut;
+ UINT8 HltNd;
+} FDC_SPECIFY_CMD;
+
+///
+/// Structure for FDC Seek Command
+///
+typedef struct {
+ UINT8 CommandCode;
+ UINT8 DiskHeadSel;
+ UINT8 NewCylinder;
+} FDC_SEEK_CMD;
+
+///
+/// Structure for FDC Result Packet
+///
+typedef struct {
+ UINT8 Status0;
+ UINT8 Status1;
+ UINT8 Status2;
+ UINT8 CylinderNumber;
+ UINT8 HeaderAddress;
+ UINT8 Record;
+ UINT8 Number;
+} FDC_RESULT_PACKET;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.c
new file mode 100644
index 0000000000..765a46dd31
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.c
@@ -0,0 +1,1759 @@
+/** @file
+Floppy Peim to support Recovery function from Floppy device.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "FloppyPeim.h"
+
+
+PEI_DMA_TABLE mRegisterTable[] = {
+ //
+ // DMA2: Clear Byte Ptr, Enable
+ //
+ {
+ R_8237_DMA_CBPR_CH4_7,
+ 0
+ },
+ {
+ R_8237_DMA_COMMAND_CH4_7,
+ 0
+ },
+ //
+ // DMA1: Clear Byte Ptr, Enable
+ //
+ {
+ R_8237_DMA_CBPR_CH0_3,
+ 0
+ },
+ {
+ R_8237_DMA_COMMAND_CH0_3,
+ 0
+ },
+ //
+ // Configure Channel 4 for Cascade Mode
+ // Clear DMA Request and enable DREQ
+ //
+ {
+ R_8237_DMA_CHMODE_CH4_7,
+ V_8237_DMA_CHMODE_CASCADE | 0
+ },
+ {
+ R_8237_DMA_STA_CH4_7,
+ 0
+ },
+ {
+ R_8237_DMA_WRSMSK_CH4_7,
+ 0
+ },
+ //
+ // Configure DMA1 (Channels 0-3) for Single Mode
+ // Clear DMA Request and enable DREQ
+ //
+ {
+ R_8237_DMA_CHMODE_CH0_3,
+ V_8237_DMA_CHMODE_SINGLE | 0
+ },
+ {
+ R_8237_DMA_STA_CH0_3,
+ 0
+ },
+ {
+ R_8237_DMA_WRSMSK_CH0_3,
+ 0
+ },
+ {
+ R_8237_DMA_CHMODE_CH0_3,
+ V_8237_DMA_CHMODE_SINGLE | 1
+ },
+ {
+ R_8237_DMA_STA_CH0_3,
+ 1
+ },
+ {
+ R_8237_DMA_WRSMSK_CH0_3,
+ 1
+ },
+ {
+ R_8237_DMA_CHMODE_CH0_3,
+ V_8237_DMA_CHMODE_SINGLE | 2
+ },
+ {
+ R_8237_DMA_STA_CH0_3,
+ 2
+ },
+ {
+ R_8237_DMA_WRSMSK_CH0_3,
+ 2
+ },
+ {
+ R_8237_DMA_CHMODE_CH0_3,
+ V_8237_DMA_CHMODE_SINGLE | 3
+ },
+ {
+ R_8237_DMA_STA_CH0_3,
+ 3
+ },
+ {
+ R_8237_DMA_WRSMSK_CH0_3,
+ 3
+ },
+ //
+ // Configure DMA2 (Channels 5-7) for Single Mode
+ // Clear DMA Request and enable DREQ
+ //
+ {
+ R_8237_DMA_CHMODE_CH4_7,
+ V_8237_DMA_CHMODE_SINGLE | 1
+ },
+ {
+ R_8237_DMA_STA_CH4_7,
+ 1
+ },
+ {
+ R_8237_DMA_WRSMSK_CH4_7,
+ 1
+ },
+ {
+ R_8237_DMA_CHMODE_CH4_7,
+ V_8237_DMA_CHMODE_SINGLE | 2
+ },
+ {
+ R_8237_DMA_STA_CH4_7,
+ 2
+ },
+ {
+ R_8237_DMA_WRSMSK_CH4_7,
+ 2
+ },
+ {
+ R_8237_DMA_CHMODE_CH4_7,
+ V_8237_DMA_CHMODE_SINGLE | 3
+ },
+ {
+ R_8237_DMA_STA_CH4_7,
+ 3
+ },
+ {
+ R_8237_DMA_WRSMSK_CH4_7,
+ 3
+ }
+};
+
+//
+// Table of diskette parameters of various diskette types
+//
+DISKET_PARA_TABLE DiskPara[9] = {
+ {
+ 0x09,
+ 0x50,
+ 0xff,
+ 0x2,
+ 0x27,
+ 0x4,
+ 0x25,
+ 0x14,
+ 0x80
+ },
+ {
+ 0x09,
+ 0x2a,
+ 0xff,
+ 0x2,
+ 0x27,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x40
+ },
+ {
+ 0x0f,
+ 0x54,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x0
+ },
+ {
+ 0x09,
+ 0x50,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x80
+ },
+ {
+ 0x09,
+ 0x2a,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x80
+ },
+ {
+ 0x12,
+ 0x1b,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x0
+ },
+ {
+ 0x09,
+ 0x2a,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x80
+ },
+ {
+ 0x12,
+ 0x1b,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0x0
+ },
+ {
+ 0x24,
+ 0x1b,
+ 0xff,
+ 0x2,
+ 0x4f,
+ 0x4,
+ 0x25,
+ 0x0f,
+ 0xc0
+ }
+};
+
+//
+// Byte per sector corresponding to various device types.
+//
+UINTN BytePerSector[6] = { 0, 256, 512, 1024, 2048, 4096 };
+
+FDC_BLK_IO_DEV mBlockIoDevTemplate = {
+ FDC_BLK_IO_DEV_SIGNATURE,
+ {
+ FdcGetNumberOfBlockDevices,
+ FdcGetBlockDeviceMediaInfo,
+ FdcReadBlocks,
+ },
+ {
+ (EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST),
+ &gEfiPeiVirtualBlockIoPpiGuid,
+ NULL
+ },
+ 0,
+ {{0}}
+};
+
+/**
+ Wait and check if bits for DIO and RQM of FDC Main Status Register
+ indicates FDC is ready for read or write.
+
+ Before writing to FDC or reading from FDC, the Host must examine
+ the bit7(RQM) and bit6(DIO) of the Main Status Register.
+ That is to say:
+ Command bytes can not be written to Data Register unless RQM is 1 and DIO is 0.
+ Result bytes can not be read from Data Register unless RQM is 1 and DIO is 1.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param DataIn Indicates data input or output.
+ TRUE means input.
+ FALSE means output.
+ @param TimeoutInMseconds Timeout value to wait.
+
+ @retval EFI_SUCCESS FDC is ready.
+ @retval EFI_NOT_READY FDC is not ready within the specified time period.
+
+**/
+EFI_STATUS
+FdcDRQReady (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN BOOLEAN DataIn,
+ IN UINTN TimeoutInMseconds
+ )
+{
+ UINTN Delay;
+ UINT8 StatusRegister;
+ UINT8 BitInOut;
+
+ //
+ // Check bit6 of Main Status Register.
+ //
+ BitInOut = 0;
+ if (DataIn) {
+ BitInOut = BIT6;
+ }
+
+ Delay = ((TimeoutInMseconds * STALL_1_MSECOND) / FDC_CHECK_INTERVAL) + 1;
+ do {
+ StatusRegister = IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_MSR));
+ if ((StatusRegister & MSR_RQM) == MSR_RQM && (StatusRegister & MSR_DIO) == BitInOut) {
+ //
+ // FDC is ready
+ //
+ break;
+ }
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+ } while (--Delay > 0);
+
+ if (Delay == 0) {
+ //
+ // FDC is not ready within the specified time period
+ //
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read a byte from FDC data register.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Pointer Pointer to buffer to hold data read from FDC.
+
+ @retval EFI_SUCCESS Byte successfully read.
+ @retval EFI_DEVICE_ERROR FDC is not ready.
+
+**/
+EFI_STATUS
+DataInByte (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ OUT UINT8 *Pointer
+ )
+{
+ UINT8 Data;
+
+ //
+ // Wait for 1ms and detect the FDC is ready to be read
+ //
+ if (FdcDRQReady (FdcBlkIoDev, TRUE, 1) != EFI_SUCCESS) {
+ //
+ // FDC is not ready.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Data = IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DTR));
+ MicroSecondDelay (FDC_SHORT_DELAY);
+ *Pointer = Data;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write a byte to FDC data register.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Pointer Pointer to data to write.
+
+ @retval EFI_SUCCESS Byte successfully written.
+ @retval EFI_DEVICE_ERROR FDC is not ready.
+
+**/
+EFI_STATUS
+DataOutByte (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN UINT8 *Pointer
+ )
+{
+ UINT8 Data;
+
+ //
+ // Wait for 1ms and detect the FDC is ready to be written
+ //
+ if (FdcDRQReady (FdcBlkIoDev, FALSE, 1) != EFI_SUCCESS) {
+ //
+ // FDC is not ready.
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Data = *Pointer;
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DTR), Data);
+ MicroSecondDelay (FDC_SHORT_DELAY);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get Sts0 and Pcn status from FDC
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV
+ @param Sts0 Value of Sts0
+ @param Pcn Value of Pcn
+
+ @retval EFI_SUCCESS Successfully retrieved status value of Sts0 and Pcn.
+ @retval EFI_DEVICE_ERROR Fail to send SENSE_INT_STATUS_CMD.
+ @retval EFI_DEVICE_ERROR Fail to read Sts0.
+ @retval EFI_DEVICE_ERROR Fail to read Pcn.
+
+**/
+EFI_STATUS
+SenseIntStatus (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ OUT UINT8 *Sts0,
+ OUT UINT8 *Pcn
+ )
+{
+ UINT8 Command;
+
+ Command = SENSE_INT_STATUS_CMD;
+
+ if (DataOutByte (FdcBlkIoDev, &Command) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (DataInByte (FdcBlkIoDev, Sts0) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (DataInByte (FdcBlkIoDev, Pcn) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue Specify command.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+
+ @retval EFI_SUCCESS Specify command successfully issued.
+ @retval EFI_DEVICE_ERROR FDC device has errors.
+
+**/
+EFI_STATUS
+Specify (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev
+ )
+{
+ FDC_SPECIFY_CMD Command;
+ UINTN Index;
+ UINT8 *Pointer;
+
+ ZeroMem (&Command, sizeof (FDC_SPECIFY_CMD));
+ Command.CommandCode = SPECIFY_CMD;
+ //
+ // set SRT, HUT
+ //
+ Command.SrtHut = 0xdf;
+ //
+ // 0xdf;
+ // set HLT and DMA
+ //
+ Command.HltNd = 0x02;
+
+ Pointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDC_SPECIFY_CMD); Index++) {
+ if (DataOutByte (FdcBlkIoDev, Pointer++) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait until busy bit is cleared.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param DevPos Position of FDC (Driver A or B)
+ @param TimeoutInMseconds Timeout value to wait.
+
+ @retval EFI_SUCCESS Busy bit has been cleared before timeout.
+ @retval EFI_TIMEOUT Time goes out before busy bit is cleared.
+
+**/
+EFI_STATUS
+FdcWaitForBSYClear (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN UINT8 DevPos,
+ IN UINTN TimeoutInMseconds
+ )
+{
+ UINTN Delay;
+ UINT8 StatusRegister;
+ UINT8 Mask;
+
+ //
+ // How to determine drive and command are busy or not: by the bits of Main Status Register
+ // bit0: Drive 0 busy (drive A)
+ // bit1: Drive 1 busy (drive B)
+ // bit4: Command busy
+ //
+ // set mask: for drive A set bit0 & bit4; for drive B set bit1 & bit4
+ //
+ Mask = (UINT8) ((DevPos == 0 ? MSR_DAB : MSR_DBB) | MSR_CB);
+
+ Delay = ((TimeoutInMseconds * STALL_1_MSECOND) / FDC_CHECK_INTERVAL) + 1;
+
+ do {
+ StatusRegister = IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_MSR));
+
+ if ((StatusRegister & Mask) == 0x00) {
+ //
+ // not busy
+ //
+ break;
+ }
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+ } while (--Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset FDC device.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV
+ @param DevPos Index of FDC device.
+
+ @retval EFI_SUCCESS FDC device successfully reset.
+ @retval EFI_DEVICE_ERROR Fail to reset FDC device.
+
+**/
+EFI_STATUS
+FdcReset (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN UINT8 DevPos
+ )
+{
+ UINT8 Data;
+ UINT8 Sts0;
+ UINT8 Pcn;
+ UINTN Index;
+
+ //
+ // Reset specified Floppy Logic Drive according to Fdd -> Disk
+ // Set Digital Output Register(DOR) to do reset work
+ // bit0 & bit1 of DOR : Drive Select
+ // bit2 : Reset bit
+ // bit3 : DMA and Int bit
+ // Reset : A "0" written to bit2 resets the FDC, this reset will remain active until
+ // a "1" is written to this bit.
+ // Reset step 1:
+ // use bit0 & bit1 to select the logic drive
+ // write "0" to bit2
+ //
+ Data = 0x0;
+ Data = (UINT8) (Data | (SELECT_DRV & DevPos));
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DOR), Data);
+
+ //
+ // Wait some time, at least 120us.
+ //
+ MicroSecondDelay (FDC_RESET_DELAY);
+ //
+ // Reset step 2:
+ // write "1" to bit2
+ // write "1" to bit3 : enable DMA
+ //
+ Data |= 0x0C;
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DOR), Data);
+
+ MicroSecondDelay (FDC_RESET_DELAY);
+
+ //
+ // Wait until specified floppy logic drive is not busy
+ //
+ if (FdcWaitForBSYClear (FdcBlkIoDev, DevPos, 1) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set the Transfer Data Rate
+ //
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_CCR), 0x0);
+
+ MicroSecondDelay (FDC_MEDIUM_DELAY);
+
+ //
+ // Issue Sense interrupt command for each drive (totally 4 drives)
+ //
+ for (Index = 0; Index < 4; Index++) {
+ if (SenseIntStatus (FdcBlkIoDev, &Sts0, &Pcn) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Issue Specify command
+ //
+ if (Specify (FdcBlkIoDev) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Turn on the motor of floppy drive.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Info Information of floppy device.
+
+ @retval EFI_SUCCESS Motor is successfully turned on.
+ @retval EFI_SUCCESS Motor is already on.
+ @retval EFI_DEVICE_ERROR Busy bit of FDC cannot be cleared.
+
+**/
+EFI_STATUS
+MotorOn (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info
+ )
+{
+ UINT8 Data;
+ UINT8 DevPos;
+
+ //
+ // Control of the floppy drive motors is a big pain. If motor is off, you have to turn it
+ // on first. But you can not leave the motor on all the time, since that would wear out the
+ // disk. On the other hand, if you turn the motor off after each operation, the system performance
+ // will be awful. The compromise used in this driver is to leave the motor on for 2 seconds after
+ // each operation. If a new operation is started in that interval(2s), the motor need not be
+ // turned on again. If no new operation is started, a timer goes off and the motor is turned off.
+ //
+ DevPos = Info->DevPos;
+
+ //
+ // If the Motor is already on, just return EFI_SUCCESS.
+ //
+ if (Info->MotorOn) {
+ return EFI_SUCCESS;
+ }
+ //
+ // The drive's motor is off, so need turn it on.
+ // First check if command and drive are busy or not.
+ //
+ if (FdcWaitForBSYClear (FdcBlkIoDev, DevPos, 1) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // for drive A: 1CH, drive B: 2DH
+ //
+ Data = 0x0C;
+ Data = (UINT8) (Data | (SELECT_DRV & DevPos));
+ if (DevPos == 0) {
+ Data |= DRVA_MOTOR_ON;
+ } else {
+ Data |= DRVB_MOTOR_ON;
+ }
+
+ Info->MotorOn = FALSE;
+
+ //
+ // Turn on the motor and wait for some time to ensure it takes effect.
+ //
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DOR), Data);
+ MicroSecondDelay (FDC_LONG_DELAY);
+
+ Info->MotorOn = TRUE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Turn off the motor of floppy drive.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Info Information of floppy device.
+
+**/
+VOID
+MotorOff (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info
+ )
+{
+ UINT8 Data;
+ UINT8 DevPos;
+
+ DevPos = Info->DevPos;
+
+ if (!Info->MotorOn) {
+ return;
+ }
+ //
+ // The motor is on, so need motor off
+ //
+ Data = 0x0C;
+ Data = (UINT8) (Data | (SELECT_DRV & DevPos));
+
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DOR), Data);
+ MicroSecondDelay (FDC_SHORT_DELAY);
+
+ Info->MotorOn = FALSE;
+}
+
+/**
+ Recalibrate the FDC device.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Info Information of floppy device.
+
+ @retval EFI_SUCCESS FDC successfully recalibrated.
+ @retval EFI_DEVICE_ERROR Fail to send RECALIBRATE_CMD.
+ @retval EFI_DEVICE_ERROR Fail to get status value of Sts0 and Pcn.
+ @retval EFI_DEVICE_ERROR Fail to recalibrate FDC device.
+
+**/
+EFI_STATUS
+Recalibrate (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info
+ )
+{
+ FDC_COMMAND_PACKET2 Command;
+ UINTN Index;
+ UINT8 Sts0;
+ UINT8 Pcn;
+ UINT8 *Pointer;
+ UINT8 Count;
+ UINT8 DevPos;
+
+ DevPos = Info->DevPos;
+
+ //
+ // We would try twice.
+ //
+ Count = 2;
+ while (Count > 0) {
+ ZeroMem (&Command, sizeof (FDC_COMMAND_PACKET2));
+ Command.CommandCode = RECALIBRATE_CMD;
+ //
+ // drive select
+ //
+ if (DevPos == 0) {
+ Command.DiskHeadSel = 0;
+ } else {
+ Command.DiskHeadSel = 1;
+ }
+
+ Pointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDC_COMMAND_PACKET2); Index++) {
+ if (DataOutByte (FdcBlkIoDev, Pointer++) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ MicroSecondDelay (FDC_RECALIBRATE_DELAY);
+
+ if (SenseIntStatus (FdcBlkIoDev, &Sts0, &Pcn) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Sts0 & 0xf0) == BIT5 && Pcn == 0) {
+ //
+ // Recalibration is successful.
+ //
+ Info->Pcn = 0;
+ Info->NeedRecalibrate = FALSE;
+
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Recalibration is not successful. Try again.
+ // If trial is used out, return EFI_DEVICE_ERROR.
+ //
+ Count--;
+ if (Count == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Seek for the cylinder according to given LBA.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Info Information of floppy device.
+ @param Lba LBA for which to seek for cylinder.
+
+ @retval EFI_SUCCESS Successfully moved to the destination cylinder.
+ @retval EFI_SUCCESS Destination cylinder is just the present cylinder.
+ @retval EFI_DEVICE_ERROR Fail to move to the destination cylinder.
+
+**/
+EFI_STATUS
+Seek (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info,
+ IN EFI_PEI_LBA Lba
+ )
+{
+ FDC_SEEK_CMD Command;
+ DISKET_PARA_TABLE *Para;
+ UINT8 EndOfTrack;
+ UINT8 Head;
+ UINT8 Cylinder;
+ UINT8 Sts0;
+ UINT8 *Pointer;
+ UINT8 Pcn;
+ UINTN Index;
+ UINT8 Gap;
+ UINT8 DevPos;
+
+ DevPos = Info->DevPos;
+ if (Info->NeedRecalibrate) {
+ if (Recalibrate (FdcBlkIoDev, Info) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Recalibrate Success
+ //
+ Info->NeedRecalibrate = FALSE;
+ }
+
+ //
+ // Get the base of disk parameter information corresponding to its type.
+ //
+ Para = (DISKET_PARA_TABLE *) ((UINT8 *) DiskPara + sizeof (DISKET_PARA_TABLE) * Info->Type);
+ EndOfTrack = Para->EndOfTrack;
+ //
+ // Calculate cylinder based on Lba and EOT
+ //
+ Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
+
+ //
+ // If the dest cylinder is the present cylinder, unnecessary to do the seek operation
+ //
+ if (Info->Pcn == Cylinder) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Calculate the head : 0 or 1
+ //
+ Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+
+ ZeroMem (&Command, sizeof (FDC_SEEK_CMD));
+ Command.CommandCode = SEEK_CMD;
+ if (DevPos == 0) {
+ Command.DiskHeadSel = 0;
+ } else {
+ Command.DiskHeadSel = 1;
+ }
+
+ //
+ // Send command to move to destination cylinder.
+ //
+ Command.DiskHeadSel = (UINT8) (Command.DiskHeadSel | (Head << 2));
+ Command.NewCylinder = Cylinder;
+
+ Pointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDC_SEEK_CMD); Index++) {
+ if (DataOutByte (FdcBlkIoDev, Pointer++) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+
+ //
+ // Calculate waiting time, which is proportional to the gap between destination
+ // cylinder and present cylinder.
+ //
+ if (Info->Pcn > Cylinder) {
+ Gap = (UINT8) (Info->Pcn - Cylinder);
+ } else {
+ Gap = (UINT8) (Cylinder - Info->Pcn);
+ }
+
+ MicroSecondDelay ((Gap + 1) * FDC_LONG_DELAY);
+
+ //
+ // Confirm if the new cylinder is the destination and status is correct.
+ //
+ if (SenseIntStatus (FdcBlkIoDev, &Sts0, &Pcn) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Sts0 & 0xf0) == BIT5) {
+ Info->Pcn = Command.NewCylinder;
+ Info->NeedRecalibrate = FALSE;
+ return EFI_SUCCESS;
+ } else {
+ Info->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Check if diskette is changed.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV
+ @param Info Information of floppy device.
+
+ @retval EFI_SUCCESS Diskette is not changed.
+ @retval EFI_MEDIA_CHANGED Diskette is changed.
+ @retval EFI_NO_MEDIA No diskette.
+ @retval EFI_DEVICE_ERROR Fail to do the seek or recalibrate operation.
+
+**/
+EFI_STATUS
+DisketChanged (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Check change line
+ //
+ Data = IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DIR));
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+
+ if ((Data & DIR_DCL) == DIR_DCL) {
+ if (Info->Pcn != 0) {
+ Status = Recalibrate (FdcBlkIoDev, Info);
+ } else {
+ Status = Seek (FdcBlkIoDev, Info, 0x30);
+ }
+
+ if (Status != EFI_SUCCESS) {
+ //
+ // Fail to do the seek or recalibrate operation
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ Data = IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_DIR));
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+
+ if ((Data & DIR_DCL) == DIR_DCL) {
+ return EFI_NO_MEDIA;
+ }
+
+ return EFI_MEDIA_CHANGED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detects if FDC device exists.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV
+ @param Info Information of floppy device.
+ @param MediaInfo Information of floppy media.
+
+ @retval TRUE FDC device exists and is working properly.
+ @retval FALSE FDC device does not exist or cannot work properly.
+
+**/
+BOOLEAN
+DiscoverFdcDevice (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ EFI_STATUS Status;
+ DISKET_PARA_TABLE *Para;
+
+ Status = MotorOn (FdcBlkIoDev, Info);
+ if (Status != EFI_SUCCESS) {
+ return FALSE;
+ }
+
+ Status = Recalibrate (FdcBlkIoDev, Info);
+
+ if (Status != EFI_SUCCESS) {
+ MotorOff (FdcBlkIoDev, Info);
+ return FALSE;
+ }
+ //
+ // Set Media Parameter
+ //
+ MediaInfo->DeviceType = LegacyFloppy;
+ MediaInfo->MediaPresent = TRUE;
+
+ //
+ // Check Media
+ //
+ Status = DisketChanged (FdcBlkIoDev, Info);
+ if (Status == EFI_NO_MEDIA) {
+ //
+ // No diskette in floppy.
+ //
+ MediaInfo->MediaPresent = FALSE;
+ } else if (Status != EFI_MEDIA_CHANGED && Status != EFI_SUCCESS) {
+ //
+ // EFI_DEVICE_ERROR
+ //
+ MotorOff (FdcBlkIoDev, Info);
+ return FALSE;
+ }
+
+ MotorOff (FdcBlkIoDev, Info);
+
+ //
+ // Get the base of disk parameter information corresponding to its type.
+ //
+ Para = (DISKET_PARA_TABLE *) ((UINT8 *) DiskPara + sizeof (DISKET_PARA_TABLE) * Info->Type);
+
+ MediaInfo->BlockSize = BytePerSector[Para->Number];
+ MediaInfo->LastBlock = Para->EndOfTrack * 2 * (Para->MaxTrackNum + 1) - 1;
+
+ return TRUE;
+}
+
+/**
+ Enumerate floppy device
+
+ @param FdcBlkIoDev Instance of floppy device controller
+
+ @return Number of FDC devices.
+
+**/
+UINT8
+FdcEnumeration (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev
+ )
+{
+ UINT8 DevPos;
+ UINT8 DevNo;
+ EFI_PEI_BLOCK_IO_MEDIA MediaInfo;
+ EFI_STATUS Status;
+
+ DevNo = 0;
+
+ //
+ // DevPos=0 means Drive A, 1 means Drive B.
+ //
+ for (DevPos = 0; DevPos < 2; DevPos++) {
+ //
+ // Detecting device presence
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_PERIPHERAL_REMOVABLE_MEDIA + EFI_P_PC_PRESENCE_DETECT);
+
+ //
+ // Reset FDC
+ //
+ Status = FdcReset (FdcBlkIoDev, DevPos);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ FdcBlkIoDev->DeviceInfo[DevPos].DevPos = DevPos;
+ FdcBlkIoDev->DeviceInfo[DevPos].Pcn = 0;
+ FdcBlkIoDev->DeviceInfo[DevPos].MotorOn = FALSE;
+ FdcBlkIoDev->DeviceInfo[DevPos].NeedRecalibrate = TRUE;
+ FdcBlkIoDev->DeviceInfo[DevPos].Type = FdcType1440K1440K;
+
+ //
+ // Discover FDC device
+ //
+ if (DiscoverFdcDevice (FdcBlkIoDev, &(FdcBlkIoDev->DeviceInfo[DevPos]), &MediaInfo)) {
+ FdcBlkIoDev->DeviceInfo[DevNo].DevPos = DevPos;
+
+ FdcBlkIoDev->DeviceInfo[DevNo].Pcn = FdcBlkIoDev->DeviceInfo[DevPos].Pcn;
+ FdcBlkIoDev->DeviceInfo[DevNo].MotorOn = FdcBlkIoDev->DeviceInfo[DevPos].MotorOn;
+ FdcBlkIoDev->DeviceInfo[DevNo].NeedRecalibrate = FdcBlkIoDev->DeviceInfo[DevPos].NeedRecalibrate;
+ FdcBlkIoDev->DeviceInfo[DevNo].Type = FdcBlkIoDev->DeviceInfo[DevPos].Type;
+
+ CopyMem (
+ &(FdcBlkIoDev->DeviceInfo[DevNo].MediaInfo),
+ &MediaInfo,
+ sizeof (EFI_PEI_BLOCK_IO_MEDIA)
+ );
+
+ DevNo++;
+ } else {
+ //
+ // Assume controller error
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_REMOVABLE_MEDIA + EFI_P_EC_CONTROLLER_ERROR
+ );
+ }
+ }
+
+ FdcBlkIoDev->DeviceCount = DevNo;
+ return DevNo;
+}
+
+/**
+ Checks result reflected by FDC_RESULT_PACKET.
+
+ @param Result FDC_RESULT_PACKET read from FDC after certain operation.
+ @param Info Information of floppy device.
+
+ @retval EFI_SUCCESS Result is healthy.
+ @retval EFI_DEVICE_ERROR Result is not healthy.
+
+**/
+EFI_STATUS
+CheckResult (
+ IN FDC_RESULT_PACKET *Result,
+ OUT PEI_FLOPPY_DEVICE_INFO *Info
+ )
+{
+ if ((Result->Status0 & STS0_IC) != IC_NT) {
+ if ((Result->Status0 & STS0_SE) == BIT5) {
+ //
+ // Seek error
+ //
+ Info->NeedRecalibrate = TRUE;
+ }
+
+ Info->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check Status Register1
+ //
+ if ((Result->Status1 & (STS1_EN | STS1_DE | STS1_OR | STS1_ND | STS1_NW | STS1_MA)) != 0) {
+ Info->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check Status Register2
+ //
+ if ((Result->Status2 & (STS2_CM | STS2_DD | STS2_WC | STS2_BC | STS2_MD)) != 0) {
+ Info->NeedRecalibrate = TRUE;
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill parameters for command packet.
+
+ @param Info Information of floppy device.
+ @param Lba Logical block address.
+ @param Command Command for which for fill parameters.
+
+**/
+VOID
+FillPara (
+ IN PEI_FLOPPY_DEVICE_INFO *Info,
+ IN EFI_PEI_LBA Lba,
+ OUT FDC_COMMAND_PACKET1 *Command
+ )
+{
+ DISKET_PARA_TABLE *Para;
+ UINT8 EndOfTrack;
+ UINT8 DevPos;
+
+ DevPos = Info->DevPos;
+
+ //
+ // Get the base of disk parameter information corresponding to its type.
+ //
+ Para = (DISKET_PARA_TABLE *) ((UINT8 *) DiskPara + sizeof (DISKET_PARA_TABLE) * Info->Type);
+
+ EndOfTrack = Para->EndOfTrack;
+
+ if (DevPos == 0) {
+ Command->DiskHeadSel = 0;
+ } else {
+ Command->DiskHeadSel = 1;
+ }
+
+ Command->Cylinder = (UINT8) ((UINTN) Lba / EndOfTrack / 2);
+ Command->Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+ Command->Sector = (UINT8) ((UINT8) ((UINTN) Lba % EndOfTrack) + 1);
+ Command->DiskHeadSel = (UINT8) (Command->DiskHeadSel | (Command->Head << 2));
+ Command->Number = Para->Number;
+ Command->EndOfTrack = Para->EndOfTrack;
+ Command->GapLength = Para->GapLength;
+ Command->DataLength = Para->DataLength;
+}
+
+/**
+ Setup specifed FDC device.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param DevPos Index of FDC device.
+
+ @retval EFI_SUCCESS FDC device successfully set up.
+ @retval EFI_DEVICE_ERROR FDC device has errors.
+
+**/
+EFI_STATUS
+Setup (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN UINT8 DevPos
+ )
+{
+ EFI_STATUS Status;
+
+ IoWrite8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_CCR), 0x0);
+
+ MicroSecondDelay (FDC_MEDIUM_DELAY);
+
+ Status = Specify (FdcBlkIoDev);
+ return Status;
+}
+
+/**
+ Setup DMA channels to read data.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Buffer Memory buffer for DMA transfer.
+ @param BlockSize the number of the bytes in one block.
+ @param NumberOfBlocks Number of blocks to read.
+
+**/
+VOID
+SetDMA (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN VOID *Buffer,
+ IN UINTN BlockSize,
+ IN UINTN NumberOfBlocks
+ )
+{
+ UINT8 Data;
+ UINTN Count;
+
+ //
+ // Mask DMA channel 2;
+ //
+ IoWrite8 (R_8237_DMA_WRSMSK_CH0_3, B_8237_DMA_WRSMSK_CMS | 2);
+
+ //
+ // Clear first/last flip flop
+ //
+ IoWrite8 (R_8237_DMA_CBPR_CH0_3, B_8237_DMA_WRSMSK_CMS | 2);
+
+ //
+ // Set mode
+ //
+ IoWrite8 (R_8237_DMA_CHMODE_CH0_3, V_8237_DMA_CHMODE_SINGLE | V_8237_DMA_CHMODE_IO2MEM | 2);
+
+ //
+ // Set base address and page register
+ //
+ Data = (UINT8) (UINTN) Buffer;
+ IoWrite8 (R_8237_DMA_BASE_CA_CH2, Data);
+ Data = (UINT8) ((UINTN) Buffer >> 8);
+ IoWrite8 (R_8237_DMA_BASE_CA_CH2, Data);
+
+ Data = (UINT8) ((UINTN) Buffer >> 16);
+ IoWrite8 (R_8237_DMA_MEM_LP_CH2, Data);
+
+ //
+ // Set count register
+ //
+ Count = BlockSize * NumberOfBlocks - 1;
+ Data = (UINT8) (Count & 0xff);
+ IoWrite8 (R_8237_DMA_BASE_CC_CH2, Data);
+ Data = (UINT8) (Count >> 8);
+ IoWrite8 (R_8237_DMA_BASE_CC_CH2, Data);
+
+ //
+ // Clear channel 2 mask
+ //
+ IoWrite8 (R_8237_DMA_WRSMSK_CH0_3, 0x02);
+}
+
+
+/**
+ According to the block range specified by Lba and NumberOfBlocks, calculate
+ the number of blocks in the same sector, which can be transferred in a batch.
+
+ @param Info Information of floppy device.
+ @param Lba Start address of block range.
+ @param NumberOfBlocks Number of blocks of the range.
+
+ @return Number of blocks in the same sector.
+
+**/
+UINTN
+GetTransferBlockCount (
+ IN PEI_FLOPPY_DEVICE_INFO *Info,
+ IN EFI_PEI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ DISKET_PARA_TABLE *Para;
+ UINT8 EndOfTrack;
+ UINT8 Head;
+ UINT8 SectorsInTrack;
+
+ //
+ // Get the base of disk parameter information corresponding to its type.
+ //
+ Para = (DISKET_PARA_TABLE *) ((UINT8 *) DiskPara + sizeof (DISKET_PARA_TABLE) * Info->Type);
+
+ EndOfTrack = Para->EndOfTrack;
+ Head = (UINT8) ((UINTN) Lba / EndOfTrack % 2);
+
+ SectorsInTrack = (UINT8) (EndOfTrack * (2 - Head) - (UINT8) ((UINTN) Lba % EndOfTrack));
+ if (SectorsInTrack < NumberOfBlocks) {
+ //
+ // Not all the block range locates in the same sector
+ //
+ return SectorsInTrack;
+ } else {
+ //
+ // All the block range is in the same sector.
+ //
+ return NumberOfBlocks;
+ }
+}
+
+/**
+ Read data sector from FDC device.
+
+ @param FdcBlkIoDev Instance of FDC_BLK_IO_DEV.
+ @param Info Information of floppy device.
+ @param Buffer Buffer to setup for DMA.
+ @param Lba The start address to read.
+ @param NumberOfBlocks Number of blocks to read.
+
+ @retval EFI_SUCCESS Data successfully read out.
+ @retval EFI_DEVICE_ERROR FDC device has errors.
+ @retval EFI_TIMEOUT Command does not take effect in time.
+
+**/
+EFI_STATUS
+ReadDataSector (
+ IN FDC_BLK_IO_DEV *FdcBlkIoDev,
+ IN OUT PEI_FLOPPY_DEVICE_INFO *Info,
+ IN VOID *Buffer,
+ IN EFI_PEI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ FDC_COMMAND_PACKET1 Command;
+ FDC_RESULT_PACKET Result;
+ UINTN Index;
+ UINTN Times;
+ UINT8 *Pointer;
+
+ Status = Seek (FdcBlkIoDev, Info, Lba);
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set up DMA
+ //
+ SetDMA (FdcBlkIoDev, Buffer, Info->MediaInfo.BlockSize, NumberOfBlocks);
+
+ //
+ // Allocate Read command packet
+ //
+ ZeroMem (&Command, sizeof (FDC_COMMAND_PACKET1));
+ Command.CommandCode = READ_DATA_CMD | CMD_MT | CMD_MFM | CMD_SK;
+
+ //
+ // Fill parameters for command.
+ //
+ FillPara (Info, Lba, &Command);
+
+ //
+ // Write command bytes to FDC
+ //
+ Pointer = (UINT8 *) (&Command);
+ for (Index = 0; Index < sizeof (FDC_COMMAND_PACKET1); Index++) {
+ if (DataOutByte (FdcBlkIoDev, Pointer++) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Wait for some time until command takes effect.
+ //
+ Times = (STALL_1_SECOND / FDC_CHECK_INTERVAL) + 1;
+ do {
+ if ((IoRead8 ((UINT16) (PcdGet16 (PcdFdcBaseAddress) + FDC_REGISTER_MSR)) & 0xc0) == 0xc0) {
+ break;
+ }
+
+ MicroSecondDelay (FDC_SHORT_DELAY);
+ } while (--Times > 0);
+
+ if (Times == 0) {
+ //
+ // Command fails to take effect in time, return EFI_TIMEOUT.
+ //
+ return EFI_TIMEOUT;
+ }
+
+ //
+ // Read result bytes from FDC
+ //
+ Pointer = (UINT8 *) (&Result);
+ for (Index = 0; Index < sizeof (FDC_RESULT_PACKET); Index++) {
+ if (DataInByte (FdcBlkIoDev, Pointer++) != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ return CheckResult (&Result, Info);
+}
+
+/**
+ Gets the count of block I/O devices that one specific block driver detects.
+
+ This function is used for getting the count of block I/O devices that one
+ specific block driver detects. To the PEI ATAPI driver, it returns the number
+ of all the detected ATAPI devices it detects during the enumeration process.
+ To the PEI legacy floppy driver, it returns the number of all the legacy
+ devices it finds during its enumeration process. If no device is detected,
+ then the function will return zero.
+
+ @param[in] PeiServices General-purpose services that are available
+ to every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI
+ instance.
+ @param[out] NumberBlockDevices The number of block I/O devices discovered.
+
+ @retval EFI_SUCCESS Operation performed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ )
+{
+ FDC_BLK_IO_DEV *FdcBlkIoDev;
+
+ FdcBlkIoDev = NULL;
+
+ FdcBlkIoDev = PEI_RECOVERY_FDC_FROM_BLKIO_THIS (This);
+
+ *NumberBlockDevices = FdcBlkIoDev->DeviceCount;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Gets a block device's media information.
+
+ This function will provide the caller with the specified block device's media
+ information. If the media changes, calling this function will update the media
+ information accordingly.
+
+ @param[in] PeiServices General-purpose services that are available to every
+ PEIM
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the
+ device index that was assigned during the enumeration
+ process. This index is a number from one to
+ NumberBlockDevices.
+ @param[out] MediaInfo The media information of the specified block media.
+ The caller is responsible for the ownership of this
+ data structure.
+
+ @retval EFI_SUCCESS Media information about the specified block device
+ was obtained successfully.
+ @retval EFI_DEVICE_ERROR Cannot get the media information due to a hardware
+ error.
+ @retval Others Other failure occurs.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcGetBlockDeviceMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ )
+{
+ UINTN DeviceCount;
+ FDC_BLK_IO_DEV *FdcBlkIoDev;
+ BOOLEAN Healthy;
+ UINTN Index;
+
+ FdcBlkIoDev = NULL;
+
+ if (This == NULL || MediaInfo == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FdcBlkIoDev = PEI_RECOVERY_FDC_FROM_BLKIO_THIS (This);
+
+ DeviceCount = FdcBlkIoDev->DeviceCount;
+
+ //
+ // DeviceIndex is a value from 1 to NumberBlockDevices.
+ //
+ if ((DeviceIndex < 1) || (DeviceIndex > DeviceCount) || (DeviceIndex > 2)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Index = DeviceIndex - 1;
+ //
+ // Probe media and retrieve latest media information
+ //
+ Healthy = DiscoverFdcDevice (
+ FdcBlkIoDev,
+ &FdcBlkIoDev->DeviceInfo[Index],
+ MediaInfo
+ );
+
+ if (!Healthy) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (
+ &(FdcBlkIoDev->DeviceInfo[Index].MediaInfo),
+ MediaInfo,
+ sizeof (EFI_PEI_BLOCK_IO_MEDIA)
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads the requested number of blocks from the specified block device.
+
+ The function reads the requested number of blocks from the device. All the
+ blocks are read, or an error is returned. If there is no media in the device,
+ the function returns EFI_NO_MEDIA.
+
+ @param[in] PeiServices General-purpose services that are available to
+ every PEIM.
+ @param[in] This Indicates the EFI_PEI_RECOVERY_BLOCK_IO_PPI instance.
+ @param[in] DeviceIndex Specifies the block device to which the function wants
+ to talk. Because the driver that implements Block I/O
+ PPIs will manage multiple block devices, the PPIs that
+ want to talk to a single device must specify the device
+ index that was assigned during the enumeration process.
+ This index is a number from one to NumberBlockDevices.
+ @param[in] StartLBA The starting logical block address (LBA) to read from
+ on the device
+ @param[in] BufferSize The size of the Buffer in bytes. This number must be
+ a multiple of the intrinsic block size of the device.
+ @param[out] Buffer A pointer to the destination buffer for the data.
+ The caller is responsible for the ownership of the
+ buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting
+ to perform the read operation.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not
+ valid, or the buffer is not properly aligned.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of
+ the intrinsic block size of the device.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcReadBlocks (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLBA,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_PEI_BLOCK_IO_MEDIA MediaInfo;
+ EFI_STATUS Status;
+ UINTN Count;
+ UINTN NumberOfBlocks;
+ UINTN BlockSize;
+ FDC_BLK_IO_DEV *FdcBlkIoDev;
+ VOID *MemPage;
+
+ FdcBlkIoDev = NULL;
+ ZeroMem (&MediaInfo, sizeof (EFI_PEI_BLOCK_IO_MEDIA));
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FdcBlkIoDev = PEI_RECOVERY_FDC_FROM_BLKIO_THIS (This);
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = FdcGetBlockDeviceMediaInfo (PeiServices, This, DeviceIndex, &MediaInfo);
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!MediaInfo.MediaPresent) {
+ return EFI_NO_MEDIA;
+ }
+
+ BlockSize = MediaInfo.BlockSize;
+
+ //
+ // If BufferSize cannot be divided by block size of FDC device,
+ // return EFI_BAD_BUFFER_SIZE.
+ //
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if ((StartLBA + NumberOfBlocks - 1) > FdcBlkIoDev->DeviceInfo[DeviceIndex - 1].MediaInfo.LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ MemPage = AllocatePages (EFI_SIZE_TO_PAGES (BufferSize));
+ if ((MemPage == NULL) || ((UINTN) MemPage >= ISA_MAX_MEMORY_ADDRESS)) {
+ //
+ // If fail to allocate memory under ISA_MAX_MEMORY_ADDRESS, designate the address space for DMA
+ //
+ MemPage = (VOID *) ((UINTN) (UINT32) 0x0f00000);
+ }
+ Status = MotorOn (FdcBlkIoDev, &(FdcBlkIoDev->DeviceInfo[DeviceIndex - 1]));
+ if (Status != EFI_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Setup (FdcBlkIoDev, FdcBlkIoDev->DeviceInfo[DeviceIndex - 1].DevPos);
+ if (Status != EFI_SUCCESS) {
+ MotorOff (FdcBlkIoDev, &(FdcBlkIoDev->DeviceInfo[DeviceIndex - 1]));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Read data in batches.
+ // Blocks in the same cylinder are read out in a batch.
+ //
+ while ((Count = GetTransferBlockCount (
+ &(FdcBlkIoDev->DeviceInfo[DeviceIndex - 1]),
+ StartLBA,
+ NumberOfBlocks
+ )) != 0 && Status == EFI_SUCCESS) {
+ Status = ReadDataSector (
+ FdcBlkIoDev,
+ &(FdcBlkIoDev->DeviceInfo[DeviceIndex - 1]),
+ MemPage,
+ StartLBA,
+ Count
+ );
+ CopyMem (Buffer, MemPage, BlockSize * Count);
+ StartLBA += Count;
+ NumberOfBlocks -= Count;
+ Buffer = (VOID *) ((UINTN) Buffer + Count * BlockSize);
+ }
+
+ MotorOff (FdcBlkIoDev, &(FdcBlkIoDev->DeviceInfo[DeviceIndex - 1]));
+
+ switch (Status) {
+ case EFI_SUCCESS:
+ return EFI_SUCCESS;
+
+ default:
+ FdcReset (FdcBlkIoDev, FdcBlkIoDev->DeviceInfo[DeviceIndex - 1].DevPos);
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ Initializes the floppy disk controller and installs FDC Block I/O PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCCESS Successfully initialized FDC and installed PPI.
+ @retval EFI_NOT_FOUND Cannot find FDC device.
+ @retval EFI_OUT_OF_RESOURCES Have no enough memory to create instance or descriptors.
+ @retval Other Fail to install FDC Block I/O PPI.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcPeimEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+ FDC_BLK_IO_DEV *FdcBlkIoDev;
+ UINTN DeviceCount;
+ UINT32 Index;
+
+ Status = PeiServicesRegisterForShadow (FileHandle);
+ if (!EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate memory for instance of FDC_BLK_IO_DEV and copy initial value
+ // from template to it.
+ //
+ FdcBlkIoDev = AllocatePages (EFI_SIZE_TO_PAGES(sizeof (FDC_BLK_IO_DEV)));
+ if (FdcBlkIoDev == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (FdcBlkIoDev, &mBlockIoDevTemplate, sizeof (mBlockIoDevTemplate));
+
+ //
+ // Initialize DMA controller to enable all channels.
+ //
+ for (Index = 0; Index < sizeof (mRegisterTable) / sizeof (PEI_DMA_TABLE); Index++) {
+ IoWrite8 (mRegisterTable[Index].Register, mRegisterTable[Index].Value);
+ }
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, EFI_PERIPHERAL_REMOVABLE_MEDIA + EFI_P_PC_INIT);
+
+ //
+ // Enumerate FDC devices.
+ //
+ DeviceCount = FdcEnumeration (FdcBlkIoDev);
+ if (DeviceCount == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ FdcBlkIoDev->PpiDescriptor.Ppi = &FdcBlkIoDev->FdcBlkIo;
+
+ return PeiServicesInstallPpi (&FdcBlkIoDev->PpiDescriptor);
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.h
new file mode 100644
index 0000000000..6477394efc
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/FloppyPeim.h
@@ -0,0 +1,246 @@
+/** @file
+Private include file for IsaFloppyPei PEIM.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _RECOVERY_FLOPPY_H_
+#define _RECOVERY_FLOPPY_H_
+
+#include <Ppi/BlockIo.h>
+
+#include <Library/DebugLib.h>
+#include <Library/PeimEntryPoint.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/TimerLib.h>
+#include <Library/IoLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+
+#include "Fdc.h"
+
+
+//
+// Some PC AT Compatible Device definitions
+//
+//
+// 8237 DMA registers
+//
+#define R_8237_DMA_BASE_CA_CH0 0x00
+#define R_8237_DMA_BASE_CA_CH1 0x02
+#define R_8237_DMA_BASE_CA_CH2 0x04
+#define R_8237_DMA_BASE_CA_CH3 0xd6
+#define R_8237_DMA_BASE_CA_CH5 0xc4
+#define R_8237_DMA_BASE_CA_CH6 0xc8
+#define R_8237_DMA_BASE_CA_CH7 0xcc
+
+#define R_8237_DMA_BASE_CC_CH0 0x01
+#define R_8237_DMA_BASE_CC_CH1 0x03
+#define R_8237_DMA_BASE_CC_CH2 0x05
+#define R_8237_DMA_BASE_CC_CH3 0xd7
+#define R_8237_DMA_BASE_CC_CH5 0xc6
+#define R_8237_DMA_BASE_CC_CH6 0xca
+#define R_8237_DMA_BASE_CC_CH7 0xce
+
+#define R_8237_DMA_MEM_LP_CH0 0x87
+#define R_8237_DMA_MEM_LP_CH1 0x83
+#define R_8237_DMA_MEM_LP_CH2 0x81
+#define R_8237_DMA_MEM_LP_CH3 0x82
+#define R_8237_DMA_MEM_LP_CH5 0x8B
+#define R_8237_DMA_MEM_LP_CH6 0x89
+#define R_8237_DMA_MEM_LP_CH7 0x8A
+
+
+#define R_8237_DMA_COMMAND_CH0_3 0x08
+#define R_8237_DMA_COMMAND_CH4_7 0xd0
+#define B_8237_DMA_COMMAND_GAP 0x10
+#define B_8237_DMA_COMMAND_CGE 0x04
+
+
+#define R_8237_DMA_STA_CH0_3 0x09
+#define R_8237_DMA_STA_CH4_7 0xd2
+
+#define R_8237_DMA_WRSMSK_CH0_3 0x0a
+#define R_8237_DMA_WRSMSK_CH4_7 0xd4
+#define B_8237_DMA_WRSMSK_CMS 0x04
+
+
+#define R_8237_DMA_CHMODE_CH0_3 0x0b
+#define R_8237_DMA_CHMODE_CH4_7 0xd6
+#define V_8237_DMA_CHMODE_DEMAND 0x00
+#define V_8237_DMA_CHMODE_SINGLE 0x40
+#define V_8237_DMA_CHMODE_CASCADE 0xc0
+#define B_8237_DMA_CHMODE_DECREMENT 0x20
+#define B_8237_DMA_CHMODE_INCREMENT 0x00
+#define B_8237_DMA_CHMODE_AE 0x10
+#define V_8237_DMA_CHMODE_VERIFY 0
+#define V_8237_DMA_CHMODE_IO2MEM 0x04
+#define V_8237_DMA_CHMODE_MEM2IO 0x08
+
+#define R_8237_DMA_CBPR_CH0_3 0x0c
+#define R_8237_DMA_CBPR_CH4_7 0xd8
+
+#define R_8237_DMA_MCR_CH0_3 0x0d
+#define R_8237_DMA_MCR_CH4_7 0xda
+
+#define R_8237_DMA_CLMSK_CH0_3 0x0e
+#define R_8237_DMA_CLMSK_CH4_7 0xdc
+
+#define R_8237_DMA_WRMSK_CH0_3 0x0f
+#define R_8237_DMA_WRMSK_CH4_7 0xde
+
+///
+/// ISA memory range
+///
+#define ISA_MAX_MEMORY_ADDRESS 0x1000000
+
+//
+// Macro for time delay & interval
+//
+#define STALL_1_SECOND 1000000
+#define STALL_1_MSECOND 1000
+#define FDC_CHECK_INTERVAL 50
+
+#define FDC_SHORT_DELAY 50
+#define FDC_MEDIUM_DELAY 100
+#define FDC_LONG_DELAY 4000
+#define FDC_RESET_DELAY 2000
+#define FDC_RECALIBRATE_DELAY 250000
+
+typedef enum {
+ FdcType360K360K = 0,
+ FdcType360K1200K,
+ FdcType1200K1200K,
+ FdcType720K720K,
+ FdcType720K1440K,
+ FdcType1440K1440K,
+ FdcType720K2880K,
+ FdcType1440K2880K,
+ FdcType2880K2880K
+} FDC_DISKET_TYPE;
+
+typedef struct {
+ UINT8 Register;
+ UINT8 Value;
+} PEI_DMA_TABLE;
+
+typedef struct {
+ UINT8 DevPos;
+ UINT8 Pcn;
+ BOOLEAN MotorOn;
+ BOOLEAN NeedRecalibrate;
+ FDC_DISKET_TYPE Type;
+ EFI_PEI_BLOCK_IO_MEDIA MediaInfo;
+} PEI_FLOPPY_DEVICE_INFO;
+
+#define FDC_BLK_IO_DEV_SIGNATURE SIGNATURE_32 ('F', 'b', 'i', 'o')
+
+typedef struct {
+ UINTN Signature;
+ EFI_PEI_RECOVERY_BLOCK_IO_PPI FdcBlkIo;
+ EFI_PEI_PPI_DESCRIPTOR PpiDescriptor;
+ UINTN DeviceCount;
+ PEI_FLOPPY_DEVICE_INFO DeviceInfo[2];
+} FDC_BLK_IO_DEV;
+
+#define PEI_RECOVERY_FDC_FROM_BLKIO_THIS(a) CR (a, FDC_BLK_IO_DEV, FdcBlkIo, FDC_BLK_IO_DEV_SIGNATURE)
+
+//
+// PEI Recovery Block I/O PPI
+//
+
+/**
+ Get the number of FDC devices.
+
+ This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.GetNumberOfBlockDevices.
+ It get the number of FDC devices in the system.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to this PPI instance.
+ @param NumberBlockDevices Pointer to the the number of FDC devices for output.
+
+ @retval EFI_SUCCESS Number of FDC devices is retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Parameter This is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcGetNumberOfBlockDevices (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ OUT UINTN *NumberBlockDevices
+ );
+
+/**
+ Get the specified media information.
+
+ This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.GetBlockDeviceMediaInfo.
+ It gets the specified media information.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to this PPI instance.
+ @param DeviceIndex Index of FDC device to get information.
+ @param MediaInfo Pointer to the media info buffer for output.
+
+ @retval EFI_SUCCESS Number of FDC devices is retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Parameter This is NULL.
+ @retval EFI_INVALID_PARAMETER Parameter MediaInfo is NULL.
+ @retval EFI_INVALID_PARAMETER DeviceIndex is not valid.
+ @retval EFI_DEVICE_ERROR FDC device does not exist or has errors.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcGetBlockDeviceMediaInfo (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ OUT EFI_PEI_BLOCK_IO_MEDIA *MediaInfo
+ );
+
+/**
+ Get the requested number of blocks from the specified FDC device.
+
+ This function implements EFI_PEI_RECOVERY_BLOCK_IO_PPI.ReadBlocks.
+ It reads the requested number of blocks from the specified FDC device.
+
+ @param PeiServices An indirect pointer to the PEI Services Table published by the PEI Foundation.
+ @param This Pointer to this PPI instance.
+ @param DeviceIndex Index of FDC device to get information.
+ @param StartLba The start LBA to read from.
+ @param BufferSize The size of range to read.
+ @param Buffer Buffer to hold the data read from FDC.
+
+ @retval EFI_SUCCESS Number of FDC devices is retrieved successfully.
+ @retval EFI_INVALID_PARAMETER Parameter This is NULL.
+ @retval EFI_INVALID_PARAMETER Parameter Buffer is NULL.
+ @retval EFI_INVALID_PARAMETER Parameter BufferSize cannot be divided by block size of FDC device.
+ @retval EFI_NO_MEDIA No media present.
+ @retval EFI_DEVICE_ERROR FDC device has error.
+ @retval Others Fail to read blocks.
+
+**/
+EFI_STATUS
+EFIAPI
+FdcReadBlocks (
+ IN EFI_PEI_SERVICES **PeiServices,
+ IN EFI_PEI_RECOVERY_BLOCK_IO_PPI *This,
+ IN UINTN DeviceIndex,
+ IN EFI_PEI_LBA StartLba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.inf
new file mode 100644
index 0000000000..8d4db34fbe
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.inf
@@ -0,0 +1,73 @@
+## @file
+# ISA Floppy PEIM to support recovery boot via floppy disk.
+#
+# This module detects and supports ISA Floppy drives. If a drive is discovered
+# the PEIM will install the BlockIo PPI. This module is only dispatched if it
+# is in the Recovery Boot mode.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaFloppyPei
+ MODULE_UNI_FILE = IsaFloppyPei.uni
+ FILE_GUID = 7F6E0A24-DBFD-43df-9755-0292D7D3DD48
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = FdcPeimEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC (EBC is for build only)
+#
+
+[Sources]
+ FloppyPeim.c
+ FloppyPeim.h
+ Fdc.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ IoLib
+ TimerLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ PeiServicesLib
+ PeimEntryPoint
+ DebugLib
+ MemoryAllocationLib
+ PcdLib
+
+[Ppis]
+ gEfiPeiVirtualBlockIoPpiGuid ## PRODUCES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFdcBaseAddress ## CONSUMES
+
+[Depex]
+ gEfiPeiMemoryDiscoveredPpiGuid AND gEfiPeiBootInRecoveryModePpiGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaFloppyPeiExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.uni
new file mode 100644
index 0000000000..57f64d6e12
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPeiExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPeiExtra.uni
new file mode 100644
index 0000000000..cbef982a66
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPeiExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.c
new file mode 100644
index 0000000000..97c196037a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.c
@@ -0,0 +1,182 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Isa driver.
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaDriver.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIsaIoComponentName = {
+ IsaIoComponentNameGetDriverName,
+ IsaIoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIsaIoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IsaIoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IsaIoComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIsaIoDriverNameTable[] = {
+ {
+ "eng;en",
+ L"ISA IO Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIsaIoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gIsaIoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.h
new file mode 100644
index 0000000000..8e8178773b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/ComponentName.h
@@ -0,0 +1,148 @@
+/** @file
+ Header file for implementation of UEFI Component Name(2) protocol.
+
+Copyright (c) 2010 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _COMPONENT_NAME_H_
+#define _COMPONENT_NAME_H_
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIsaIoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gIsaIoComponentName2;
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.c
new file mode 100644
index 0000000000..8c58b318c6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.c
@@ -0,0 +1,326 @@
+/** @file
+ IsaIo UEFI driver.
+
+ Produce an instance of the ISA I/O Protocol for every SIO controller.
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaDriver.h"
+
+//
+// IsaIo Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gIsaIoDriver = {
+ IsaIoDriverSupported,
+ IsaIoDriverStart,
+ IsaIoDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ The main entry point for the IsaIo driver.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval EFI_OUT_OF_RESOURCES There was not enough memory in pool to install all the protocols.
+**/
+EFI_STATUS
+EFIAPI
+InitializeIsaIo (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gIsaIoDriver,
+ ImageHandle,
+ &gIsaIoComponentName,
+ &gIsaIoComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+ Tests to see if a controller can be managed by the IsaIo driver.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+ @retval EFI_UNSUPPORTED The device is is not supported by this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SIO_PROTOCOL *Sio;
+ EFI_HANDLE PciHandle;
+
+ //
+ // Try to open EFI DEVICE PATH protocol on the controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the PciIo protocol from its parent controller.
+ //
+ Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &DevicePath, &PciHandle);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Try to open the Super IO protocol on the controller
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_HANDLE PciHandle;
+ EFI_SIO_PROTOCOL *Sio;
+ ACPI_RESOURCE_HEADER_PTR Resources;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ PciIo = NULL;
+ Sio = NULL;
+
+ //
+ // Open Device Path Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the PciIo protocol from its parent controller.
+ //
+ TempDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiPciIoProtocolGuid, &TempDevicePath, &PciHandle);
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (PciHandle, &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Open Super IO Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ (VOID **) &Sio,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail due to LocateDevicePath(...) or OpenProtocol(Sio, BY_DRIVER)
+ //
+ return Status;
+ }
+
+ Status = Sio->GetResources (Sio, &Resources);
+ ASSERT_EFI_ERROR (Status);
+
+ IsaIoDevice = AllocatePool (sizeof (ISA_IO_DEVICE));
+ ASSERT (IsaIoDevice != NULL);
+
+ IsaIoDevice->Signature = ISA_IO_DEVICE_SIGNATURE;
+ IsaIoDevice->PciIo = PciIo;
+
+ //
+ // Initialize the ISA I/O instance structure
+ //
+ InitializeIsaIoInstance (IsaIoDevice, DevicePath, Resources);
+
+ //
+ // Install the ISA I/O protocol on the Controller handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Stop this driver on ControllerHandle.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (IsaIo);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ &IsaIoDevice->IsaIo,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiSioProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ FreePool (IsaIoDevice->IsaIo.ResourceList);
+ FreePool (IsaIoDevice);
+ }
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.h
new file mode 100644
index 0000000000..64f710bcec
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaDriver.h
@@ -0,0 +1,263 @@
+/** @file
+ The header file for ISA driver
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ISA_DRIVER_H_
+#define _ISA_DRIVER_H_
+
+
+#include <Uefi.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/SuperIo.h>
+#include <Protocol/ComponentName.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/DriverBinding.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Guid/StatusCodeDataTypeId.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+#include <IndustryStandard/Acpi.h>
+
+#include "ComponentName.h"
+
+//
+// 8237 DMA registers
+//
+#define R_8237_DMA_BASE_CA_CH0 0x00
+#define R_8237_DMA_BASE_CA_CH1 0x02
+#define R_8237_DMA_BASE_CA_CH2 0x04
+#define R_8237_DMA_BASE_CA_CH3 0xd6
+#define R_8237_DMA_BASE_CA_CH5 0xc4
+#define R_8237_DMA_BASE_CA_CH6 0xc8
+#define R_8237_DMA_BASE_CA_CH7 0xcc
+
+#define R_8237_DMA_BASE_CC_CH0 0x01
+#define R_8237_DMA_BASE_CC_CH1 0x03
+#define R_8237_DMA_BASE_CC_CH2 0x05
+#define R_8237_DMA_BASE_CC_CH3 0xd7
+#define R_8237_DMA_BASE_CC_CH5 0xc6
+#define R_8237_DMA_BASE_CC_CH6 0xca
+#define R_8237_DMA_BASE_CC_CH7 0xce
+
+#define R_8237_DMA_MEM_LP_CH0 0x87
+#define R_8237_DMA_MEM_LP_CH1 0x83
+#define R_8237_DMA_MEM_LP_CH2 0x81
+#define R_8237_DMA_MEM_LP_CH3 0x82
+#define R_8237_DMA_MEM_LP_CH5 0x8B
+#define R_8237_DMA_MEM_LP_CH6 0x89
+#define R_8237_DMA_MEM_LP_CH7 0x8A
+
+
+#define R_8237_DMA_COMMAND_CH0_3 0x08
+#define R_8237_DMA_COMMAND_CH4_7 0xd0
+#define B_8237_DMA_COMMAND_GAP 0x10
+#define B_8237_DMA_COMMAND_CGE 0x04
+
+
+#define R_8237_DMA_STA_CH0_3 0xd8
+#define R_8237_DMA_STA_CH4_7 0xd0
+
+#define R_8237_DMA_WRSMSK_CH0_3 0x0a
+#define R_8237_DMA_WRSMSK_CH4_7 0xd4
+#define B_8237_DMA_WRSMSK_CMS 0x04
+
+
+#define R_8237_DMA_CHMODE_CH0_3 0x0b
+#define R_8237_DMA_CHMODE_CH4_7 0xd6
+#define V_8237_DMA_CHMODE_DEMAND 0x00
+#define V_8237_DMA_CHMODE_SINGLE 0x40
+#define V_8237_DMA_CHMODE_CASCADE 0xc0
+#define B_8237_DMA_CHMODE_DECREMENT 0x20
+#define B_8237_DMA_CHMODE_INCREMENT 0x00
+#define B_8237_DMA_CHMODE_AE 0x10
+#define V_8237_DMA_CHMODE_VERIFY 0
+#define V_8237_DMA_CHMODE_IO2MEM 0x04
+#define V_8237_DMA_CHMODE_MEM2IO 0x08
+
+#define R_8237_DMA_CBPR_CH0_3 0x0c
+#define R_8237_DMA_CBPR_CH4_7 0xd8
+
+#define R_8237_DMA_MCR_CH0_3 0x0d
+#define R_8237_DMA_MCR_CH4_7 0xda
+
+#define R_8237_DMA_CLMSK_CH0_3 0x0e
+#define R_8237_DMA_CLMSK_CH4_7 0xdc
+
+#define R_8237_DMA_WRMSK_CH0_3 0x0f
+#define R_8237_DMA_WRMSK_CH4_7 0xde
+
+typedef enum {
+ IsaAccessTypeUnknown,
+ IsaAccessTypeIo,
+ IsaAccessTypeMem,
+ IsaAccessTypeMaxType
+} ISA_ACCESS_TYPE;
+
+typedef struct {
+ UINT8 Address;
+ UINT8 Page;
+ UINT8 Count;
+} EFI_ISA_DMA_REGISTERS;
+
+//
+// ISA I/O Device Structure
+//
+#define ISA_IO_DEVICE_SIGNATURE SIGNATURE_32 ('i', 's', 'a', 'i')
+
+typedef struct {
+ UINT32 Signature;
+ EFI_HANDLE Handle;
+ EFI_ISA_IO_PROTOCOL IsaIo;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+} ISA_IO_DEVICE;
+
+#define ISA_IO_DEVICE_FROM_ISA_IO_THIS(a) CR (a, ISA_IO_DEVICE, IsaIo, ISA_IO_DEVICE_SIGNATURE)
+
+//
+// Mapping structure for performing ISA DMA to a buffer above 16 MB
+//
+typedef struct {
+ EFI_ISA_IO_PROTOCOL_OPERATION Operation;
+ UINTN NumberOfBytes;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS HostAddress;
+ EFI_PHYSICAL_ADDRESS MappedHostAddress;
+} ISA_MAP_INFO;
+
+//
+// EFI Driver Binding Protocol Interface Functions
+//
+
+/**
+ Tests to see if a controller can be managed by the ISA Driver.
+
+ How the Start() function of a driver is implemented can affect how the Supported() function is implemented.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] Controller The handle of the controller to test.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The device is supported by this driver.
+ @retval EFI_ALREADY_STARTED The device is already being managed by this driver.
+ @retval EFI_ACCESS_DENIED The device is already being managed by a different driver
+ or an application that requires exclusive access.
+ @retval EFI_UNSUPPORTED The device is is not supported by this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Start this driver on ControllerHandle.
+
+ The Start() function is designed to be invoked from the EFI boot service ConnectController().
+ As a result, much of the error checking on the parameters to Start() has been moved into this
+ common boot service. It is legal to call Start() from other locations, but the following calling
+ restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE.
+ 2. If RemainingDevicePath is not NULL, then it must be a pointer to a naturally aligned
+ EFI_DEVICE_PATH_PROTOCOL.
+ 3. Prior to calling Start(), the Supported() function for the driver specified by This must
+ have been called with the same calling parameters, and Supported() must have returned EFI_SUCCESS.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle The handle of the controller to start. This handle
+ must support a protocol interface that supplies
+ an I/O abstraction to the driver.
+ @param[in] RemainingDevicePath A pointer to the remaining portion of a device path.
+ This parameter is ignored by device drivers, and is optional for bus drivers.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval EFI_DEVICE_ERROR The device could not be started due to a device error.
+ Currently not implemented.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+ @retval Others The driver failded to start the device.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Stop this driver on ControllerHandle.
+
+ The Stop() function is designed to be invoked from the EFI boot service DisconnectController().
+ As a result, much of the error checking on the parameters to Stop() has been moved
+ into this common boot service. It is legal to call Stop() from other locations,
+ but the following calling restrictions must be followed or the system behavior will not be deterministic.
+ 1. ControllerHandle must be a valid EFI_HANDLE that was used on a previous call to this
+ same driver's Start() function.
+ 2. The first NumberOfChildren handles of ChildHandleBuffer must all be a valid
+ EFI_HANDLE. In addition, all of these handles must have been created in this driver's
+ Start() function, and the Start() function must have called OpenProtocol() on
+ ControllerHandle with an Attribute of EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER.
+
+ @param[in] This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param[in] ControllerHandle A handle to the device being stopped. The handle must
+ support a bus specific I/O protocol for the driver
+ to use to stop the device.
+ @param[in] NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param[in] ChildHandleBuffer An array of child handles to be freed. May be NULL
+ if NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL * This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE * ChildHandleBuffer OPTIONAL
+ );
+
+//
+// Function Prototypes
+//
+
+/**
+ Initializes an ISA I/O Instance
+
+ @param[in] IsaIoDevice The isa device to be initialized.
+ @param[in] DevicePath The device path of the isa device.
+ @param[in] Resources The ACPI resource list.
+
+**/
+VOID
+InitializeIsaIoInstance (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN ACPI_RESOURCE_HEADER_PTR Resources
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c
new file mode 100644
index 0000000000..2e4361fc0d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.c
@@ -0,0 +1,1803 @@
+/** @file
+ The implementation for EFI_ISA_IO_PROTOCOL.
+
+Copyright (c) 2010 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IsaIo.h"
+
+//
+// Module Variables
+//
+EFI_ISA_IO_PROTOCOL mIsaIoInterface = {
+ {
+ IsaIoMemRead,
+ IsaIoMemWrite
+ },
+ {
+ IsaIoIoRead,
+ IsaIoIoWrite
+ },
+ IsaIoCopyMem,
+ IsaIoMap,
+ IsaIoUnmap,
+ IsaIoAllocateBuffer,
+ IsaIoFreeBuffer,
+ IsaIoFlush,
+ NULL,
+ 0,
+ NULL
+};
+
+EFI_ISA_DMA_REGISTERS mDmaRegisters[8] = {
+ {
+ 0x00,
+ 0x87,
+ 0x01
+ },
+ {
+ 0x02,
+ 0x83,
+ 0x03
+ },
+ {
+ 0x04,
+ 0x81,
+ 0x05
+ },
+ {
+ 0x06,
+ 0x82,
+ 0x07
+ },
+ {
+ 0x00,
+ 0x00,
+ 0x00
+ }, // Channel 4 is invalid
+ {
+ 0xC4,
+ 0x8B,
+ 0xC6
+ },
+ {
+ 0xC8,
+ 0x89,
+ 0xCA
+ },
+ {
+ 0xCC,
+ 0x8A,
+ 0xCE
+ },
+};
+
+/**
+ Verifies access to an ISA device
+
+ @param[in] IsaIoDevice The ISA device to be verified.
+ @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
+ @param[in] Width The width of the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+
+ @retval EFI_SUCCESS Verify success.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The device ont support the access type.
+**/
+EFI_STATUS
+IsaIoVerifyAccess (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN ISA_ACCESS_TYPE Type,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT32 Offset
+ )
+{
+ EFI_ISA_ACPI_RESOURCE *Item;
+ EFI_STATUS Status;
+
+ if ((UINT32)Width >= EfiIsaIoWidthMaximum ||
+ Width == EfiIsaIoWidthReserved ||
+ Width == EfiIsaIoWidthFifoReserved ||
+ Width == EfiIsaIoWidthFillReserved
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Width is EfiIsaIoWidthFifoUintX then convert to EfiIsaIoWidthUintX
+ // If Width is EfiIsaIoWidthFillUintX then convert to EfiIsaIoWidthUintX
+ //
+ if (Width >= EfiIsaIoWidthFifoUint8 && Width < EfiIsaIoWidthFifoReserved) {
+ Count = 1;
+ }
+
+ Width = (EFI_ISA_IO_PROTOCOL_WIDTH) (Width & 0x03);
+
+ Status = EFI_UNSUPPORTED;
+ Item = IsaIoDevice->IsaIo.ResourceList->ResourceItem;
+ while (Item->Type != EfiIsaAcpiResourceEndOfList) {
+ if ((Type == IsaAccessTypeMem && Item->Type == EfiIsaAcpiResourceMemory) ||
+ (Type == IsaAccessTypeIo && Item->Type == EfiIsaAcpiResourceIo)) {
+ if (Offset >= Item->StartRange && (Offset + Count * (UINT32)(1 << Width)) - 1 <= Item->EndRange) {
+ return EFI_SUCCESS;
+ }
+
+ if (Offset >= Item->StartRange && Offset <= Item->EndRange) {
+ Status = EFI_INVALID_PARAMETER;
+ }
+ }
+
+ Item++;
+ }
+
+ return Status;
+}
+
+/**
+ Convert the IO Information in ACPI descriptor to IO ISA Attribute.
+
+ @param[in] Information The IO Information in ACPI descriptor
+
+ @return UINT32 The IO ISA Attribute
+**/
+UINT32
+IsaIoAttribute (
+ IN UINT8 Information
+ )
+{
+ UINT32 Attribute;
+
+ Attribute = 0;
+
+ switch (Information & EFI_ACPI_IO_DECODE_MASK) {
+ case EFI_ACPI_IO_DECODE_16_BIT:
+ Attribute |= EFI_ISA_ACPI_IO_DECODE_16_BITS;
+ break;
+
+ case EFI_ACPI_IO_DECODE_10_BIT:
+ Attribute |= EFI_ISA_ACPI_IO_DECODE_10_BITS;
+ break;
+ }
+
+ return Attribute;
+}
+
+/**
+ Convert the IRQ Information in ACPI descriptor to IRQ ISA Attribute.
+
+ @param[in] Information The IRQ Information in ACPI descriptor
+
+ @return UINT32 The IRQ ISA Attribute
+**/
+UINT32
+IsaIrqAttribute (
+ IN UINT8 Information
+ )
+{
+ UINT32 Attribute;
+
+ Attribute = 0;
+
+ if ((Information & EFI_ACPI_IRQ_POLARITY_MASK) == EFI_ACPI_IRQ_HIGH_TRUE) {
+ if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE;
+ } else {
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
+ }
+ } else {
+ if ((Information & EFI_ACPI_IRQ_MODE) == EFI_ACPI_IRQ_LEVEL_TRIGGERED) {
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE;
+ } else {
+ Attribute = EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE;
+ }
+ }
+ return Attribute;
+}
+
+/**
+ Convert the Memory Information in ACPI descriptor to Memory ISA Attribute.
+
+ @param[in] Information The Memory Information in ACPI descriptor
+
+ @return UINT32 The Memory ISA Attribute
+**/
+UINT32
+IsaMemoryAttribute (
+ IN UINT8 Information
+ )
+{
+ UINT32 Attribute;
+
+ Attribute = 0;
+
+ switch (Information & EFI_ACPI_MEMORY_WRITE_STATUS_MASK) {
+ case EFI_ACPI_MEMORY_WRITABLE:
+ Attribute |= EFI_ISA_ACPI_MEMORY_WRITEABLE;
+ break;
+ }
+
+ return Attribute;
+}
+
+/**
+ Convert the DMA Information in ACPI descriptor to DMA ISA Attribute.
+
+ @param[in] Information The DMA Information in ACPI descriptor
+
+ @return UINT32 The DMA ISA Attribute
+**/
+UINT32
+IsaDmaAttribute (
+ IN UINT8 Information
+ )
+{
+ UINT32 Attribute;
+
+ Attribute = EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE;
+
+ switch (Information & EFI_ACPI_DMA_SPEED_TYPE_MASK) {
+ case EFI_ACPI_DMA_SPEED_TYPE_COMPATIBILITY:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE;
+ break;
+ case EFI_ACPI_DMA_SPEED_TYPE_A:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A;
+ break;
+ case EFI_ACPI_DMA_SPEED_TYPE_B:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B;
+ break;
+ case EFI_ACPI_DMA_SPEED_TYPE_F:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C;
+ break;
+ }
+
+ switch (Information & EFI_ACPI_DMA_TRANSFER_TYPE_MASK) {
+ case EFI_ACPI_DMA_TRANSFER_TYPE_8_BIT:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8;
+ break;
+ case EFI_ACPI_DMA_TRANSFER_TYPE_16_BIT:
+ Attribute |= EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16;
+ break;
+ }
+
+ return Attribute;
+}
+
+/**
+ Convert the ACPI resource descriptor to ISA resource descriptor.
+
+ @param[in] AcpiResource Pointer to the ACPI resource descriptor
+ @param[out] IsaResource The optional pointer to the buffer to
+ store the converted ISA resource descriptor
+
+ @return UINTN Number of ISA resource descriptor needed
+**/
+UINTN
+AcpiResourceToIsaResource (
+ IN ACPI_RESOURCE_HEADER_PTR AcpiResource,
+ OUT EFI_ISA_ACPI_RESOURCE *IsaResource OPTIONAL
+ )
+{
+ UINT32 Index;
+ UINTN Count;
+ UINT32 LastIndex;
+ EFI_ACPI_IO_PORT_DESCRIPTOR *Io;
+ EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *FixedIo;
+ EFI_ACPI_IRQ_DESCRIPTOR *Irq;
+ EFI_ACPI_DMA_DESCRIPTOR *Dma;
+ EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *Memory;
+ EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *FixedMemory;
+
+ Count = 0;
+ LastIndex = 0;
+
+ switch (AcpiResource.SmallHeader->Byte) {
+ case ACPI_DMA_DESCRIPTOR:
+ Dma = (EFI_ACPI_DMA_DESCRIPTOR *) AcpiResource.SmallHeader;
+ for (Index = 0; Index < sizeof (Dma->ChannelMask) * 8; Index++) {
+ if (Dma->ChannelMask & (1 << Index)) {
+ if ((Count > 0) && (LastIndex + 1 == Index)) {
+ if (IsaResource != NULL) {
+ IsaResource[Count - 1].EndRange ++;
+ }
+ } else {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceDma;
+ IsaResource[Count].Attribute = IsaDmaAttribute (Dma->Information);
+ IsaResource[Count].StartRange = Index;
+ IsaResource[Count].EndRange = Index;
+ }
+ Count ++;
+ }
+
+ LastIndex = Index;
+ }
+ }
+ break;
+
+ case ACPI_IO_PORT_DESCRIPTOR:
+ Io = (EFI_ACPI_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
+ if (Io->Length != 0) {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceIo;
+ IsaResource[Count].Attribute = IsaIoAttribute (Io->Information);
+ IsaResource[Count].StartRange = Io->BaseAddressMin;
+ IsaResource[Count].EndRange = Io->BaseAddressMin + Io->Length - 1;
+ }
+ Count ++;
+ }
+ break;
+
+ case ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR:
+ FixedIo = (EFI_ACPI_FIXED_LOCATION_IO_PORT_DESCRIPTOR *) AcpiResource.SmallHeader;
+ if (FixedIo->Length != 0) {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceIo;
+ IsaResource[Count].Attribute = EFI_ISA_ACPI_IO_DECODE_10_BITS;
+ IsaResource[Count].StartRange = FixedIo->BaseAddress;
+ IsaResource[Count].EndRange = FixedIo->BaseAddress + FixedIo->Length - 1;
+ }
+ Count ++;
+ }
+ break;
+
+ case ACPI_IRQ_DESCRIPTOR:
+ case ACPI_IRQ_NOFLAG_DESCRIPTOR:
+ Irq = (EFI_ACPI_IRQ_DESCRIPTOR *) AcpiResource.SmallHeader;
+ for (Index = 0; Index < sizeof (Irq->Mask) * 8; Index++) {
+ if (Irq->Mask & (1 << Index)) {
+ if ((Count > 0) && (LastIndex + 1 == Index)) {
+ if (IsaResource != NULL) {
+ IsaResource[Count - 1].EndRange ++;
+ }
+ } else {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceInterrupt;
+ if (AcpiResource.SmallHeader->Byte == ACPI_IRQ_DESCRIPTOR) {
+ IsaResource[Count].Attribute = IsaIrqAttribute (Irq->Information);
+ } else {
+ IsaResource[Count].Attribute = EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE;
+ }
+ IsaResource[Count].StartRange = Index;
+ IsaResource[Count].EndRange = Index;
+ }
+ Count++;
+ }
+
+ LastIndex = Index;
+ }
+ }
+ break;
+
+ case ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR:
+ Memory = (EFI_ACPI_32_BIT_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
+ if (Memory->Length != 0) {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
+ IsaResource[Count].Attribute = IsaMemoryAttribute (Memory->Information);
+ IsaResource[Count].StartRange = Memory->BaseAddressMin;
+ IsaResource[Count].EndRange = Memory->BaseAddressMin + Memory->Length - 1;
+ }
+ Count ++;
+ }
+ break;
+
+ case ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR:
+ FixedMemory = (EFI_ACPI_32_BIT_FIXED_MEMORY_RANGE_DESCRIPTOR *) AcpiResource.LargeHeader;
+ if (FixedMemory->Length != 0) {
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceMemory;
+ IsaResource[Count].Attribute = IsaMemoryAttribute (FixedMemory->Information);
+ IsaResource[Count].StartRange = FixedMemory->BaseAddress;
+ IsaResource[Count].EndRange = FixedMemory->BaseAddress + FixedMemory->Length - 1;
+ }
+ Count ++;
+ }
+ break;
+
+ case ACPI_END_TAG_DESCRIPTOR:
+ if (IsaResource != NULL) {
+ IsaResource[Count].Type = EfiIsaAcpiResourceEndOfList;
+ IsaResource[Count].Attribute = 0;
+ IsaResource[Count].StartRange = 0;
+ IsaResource[Count].EndRange = 0;
+ }
+ Count ++;
+ break;
+ }
+
+ return Count;
+}
+
+/**
+ Initializes an ISA I/O Instance
+
+ @param[in] IsaIoDevice The isa device to be initialized.
+ @param[in] DevicePath The device path of the isa device.
+ @param[in] Resources The ACPI resource list.
+
+**/
+VOID
+InitializeIsaIoInstance (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN ACPI_RESOURCE_HEADER_PTR Resources
+ )
+{
+ UINTN Index;
+ ACPI_HID_DEVICE_PATH *AcpiNode;
+ ACPI_RESOURCE_HEADER_PTR ResourcePtr;
+
+ //
+ // Use the ISA IO Protocol structure template to initialize the ISA IO instance
+ //
+ CopyMem (
+ &IsaIoDevice->IsaIo,
+ &mIsaIoInterface,
+ sizeof (EFI_ISA_IO_PROTOCOL)
+ );
+
+ //
+ // Count the resources including the ACPI End Tag
+ //
+ ResourcePtr = Resources;
+ Index = 0;
+ while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
+
+ Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
+
+ if (ResourcePtr.SmallHeader->Bits.Type == 0) {
+ ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
+ + ResourcePtr.SmallHeader->Bits.Length
+ + sizeof (*ResourcePtr.SmallHeader));
+ } else {
+ ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
+ + ResourcePtr.LargeHeader->Length
+ + sizeof (*ResourcePtr.LargeHeader));
+ }
+
+ }
+ //
+ // Get the Isa Resource count for ACPI End Tag
+ //
+ Index += AcpiResourceToIsaResource (ResourcePtr, NULL);
+
+ //
+ // Initialize the ResourceList
+ //
+ IsaIoDevice->IsaIo.ResourceList = AllocatePool (sizeof (EFI_ISA_ACPI_RESOURCE_LIST) + Index * sizeof (EFI_ISA_ACPI_RESOURCE));
+ ASSERT (IsaIoDevice->IsaIo.ResourceList != NULL);
+ IsaIoDevice->IsaIo.ResourceList->ResourceItem = (EFI_ISA_ACPI_RESOURCE *) (IsaIoDevice->IsaIo.ResourceList + 1);
+
+ AcpiNode = (ACPI_HID_DEVICE_PATH *) ((UINT8 *) DevicePath + GetDevicePathSize (DevicePath) - END_DEVICE_PATH_LENGTH - sizeof (ACPI_HID_DEVICE_PATH));
+ IsaIoDevice->IsaIo.ResourceList->Device.HID = AcpiNode->HID;
+ IsaIoDevice->IsaIo.ResourceList->Device.UID = AcpiNode->UID;
+
+ ResourcePtr = Resources;
+ Index = 0;
+ while (ResourcePtr.SmallHeader->Byte != ACPI_END_TAG_DESCRIPTOR) {
+
+ Index += AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
+
+ if (ResourcePtr.SmallHeader->Bits.Type == 0) {
+ ResourcePtr.SmallHeader = (ACPI_SMALL_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.SmallHeader
+ + ResourcePtr.SmallHeader->Bits.Length
+ + sizeof (*ResourcePtr.SmallHeader));
+ } else {
+ ResourcePtr.LargeHeader = (ACPI_LARGE_RESOURCE_HEADER *) ((UINT8 *) ResourcePtr.LargeHeader
+ + ResourcePtr.LargeHeader->Length
+ + sizeof (*ResourcePtr.LargeHeader));
+ }
+ }
+
+ //
+ // Convert the ACPI End Tag
+ //
+ AcpiResourceToIsaResource (ResourcePtr, &IsaIoDevice->IsaIo.ResourceList->ResourceItem[Index]);
+}
+
+/**
+ Performs an ISA I/O Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeIo,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Io.Read (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA I/O Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was writen to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeIo,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Io.Write (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Writes an 8-bit I/O Port
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Offset The offset in ISA IO space to start the IO operation.
+ @param[in] Value The data to write port.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WritePort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 Offset,
+ IN UINT8 Value
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ Status = IsaIoDevice->PciIo->Io.Write (
+ IsaIoDevice->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ 1,
+ &Value
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ return Status;
+ }
+
+ //
+ // Wait for 50 microseconds to take affect.
+ //
+ gBS->Stall (50);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes I/O operation base address and count number to a 8 bit I/O Port.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] AddrOffset The address' offset.
+ @param[in] PageOffset The page's offest.
+ @param[in] CountOffset The count's offset.
+ @param[in] BaseAddress The base address.
+ @param[in] Count The number of I/O operations to perform.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WriteDmaPort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 AddrOffset,
+ IN UINT32 PageOffset,
+ IN UINT32 CountOffset,
+ IN UINT32 BaseAddress,
+ IN UINT16 Count
+ )
+{
+ EFI_STATUS Status;
+
+ Status = WritePort (This, AddrOffset, (UINT8) (BaseAddress & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, AddrOffset, (UINT8) ((BaseAddress >> 8) & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, PageOffset, (UINT8) ((BaseAddress >> 16) & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, CountOffset, (UINT8) (Count & 0xff));
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, CountOffset, (UINT8) ((Count >> 8) & 0xff));
+ return Status;
+}
+
+/**
+ Unmaps a memory region for DMA
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoUnmap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ )
+{
+ ISA_MAP_INFO *IsaMapInfo;
+
+ //
+ // Check if DMA is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // See if the Map() operation associated with this Unmap() required a mapping
+ // buffer.If a mapping buffer was not required, then this function simply
+ // returns EFI_SUCCESS.
+ //
+ if (Mapping != NULL) {
+ //
+ // Get the MAP_INFO structure from Mapping
+ //
+ IsaMapInfo = (ISA_MAP_INFO *) Mapping;
+
+ //
+ // If this is a write operation from the Agent's point of view,
+ // then copy the contents of the mapped buffer into the real buffer
+ // so the processor can read the contents of the real buffer.
+ //
+ if (IsaMapInfo->Operation == EfiIsaIoOperationBusMasterWrite) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // Free the mapped buffer and the MAP_INFO structure.
+ //
+ gBS->FreePages (IsaMapInfo->MappedHostAddress, IsaMapInfo->NumberOfPages);
+ FreePool (IsaMapInfo);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Flushes any posted write data to the system memory.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The buffers were flushed.
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFlush (
+ IN EFI_ISA_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ Status = IsaIoDevice->PciIo->Flush (IsaIoDevice->PciIo);
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA Memory Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device successfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify the Isa Io Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Mem.Read (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Performs an ISA Memory Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was written to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ Offset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->Mem.Write (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ Offset,
+ Count,
+ Buffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory copy operation.
+ @param[in] DestOffset The offset of the destination
+ @param[in] SrcOffset The offset of the source
+ @param[in] Count The number of memory copy operations to perform
+
+ @retval EFI_SUCCESS The data was copied sucessfully.
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoCopyMem (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 DestOffset,
+ IN UINT32 SrcOffset,
+ IN UINTN Count
+ )
+{
+ EFI_STATUS Status;
+ ISA_IO_DEVICE *IsaIoDevice;
+
+ //
+ // Check if ISA memory is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_ISA_MEMORY) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IsaIoDevice = ISA_IO_DEVICE_FROM_ISA_IO_THIS (This);
+
+ //
+ // Verify Isa IO Access for destination and source
+ //
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ DestOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoVerifyAccess (
+ IsaIoDevice,
+ IsaAccessTypeMem,
+ Width,
+ Count,
+ SrcOffset
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IsaIoDevice->PciIo->CopyMem (
+ IsaIoDevice->PciIo,
+ (EFI_PCI_IO_PROTOCOL_WIDTH) Width,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ DestOffset,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ SrcOffset,
+ Count
+ );
+
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
+/**
+ Maps a memory region for DMA, note this implementation
+ only supports slave read/write operation to save code size.
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+IsaIoMapOnlySupportSlaveReadWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ ISA_MAP_INFO *IsaMapInfo;
+ UINT8 DmaMode;
+ UINTN MaxNumberOfBytes;
+ UINT32 BaseAddress;
+ UINT16 Count;
+ UINT8 DmaMask;
+ UINT8 DmaClear;
+ UINT8 DmaChannelMode;
+
+ if ((NULL == This) ||
+ (NULL == HostAddress) ||
+ (NULL == NumberOfBytes) ||
+ (NULL == DeviceAddress) ||
+ (NULL == Mapping)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the return values to their defaults
+ //
+ *Mapping = NULL;
+
+ //
+ // Make sure the Operation parameter is valid.
+ // Light IsaIo only supports two operations.
+ //
+ if (!(Operation == EfiIsaIoOperationSlaveRead ||
+ Operation == EfiIsaIoOperationSlaveWrite)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber >= 4) {
+ //
+ // The Light IsaIo doesn't support channelNumber larger than 4.
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Map the HostAddress to a DeviceAddress.
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((PhysicalAddress + *NumberOfBytes) > BASE_16MB) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // is above 16MB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
+ // is called later.
+ //
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
+ if (IsaMapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = IsaMapInfo;
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ IsaMapInfo->Operation = Operation;
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
+ IsaMapInfo->HostAddress = PhysicalAddress;
+ IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
+
+ //
+ // Allocate a buffer below 16MB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ IsaMapInfo->NumberOfPages,
+ &IsaMapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (IsaMapInfo);
+ *NumberOfBytes = 0;
+ *Mapping = NULL;
+ return Status;
+ }
+ //
+ // If this is a read operation from the DMA agents's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the DMA agent can read the contents of the real buffer.
+ //
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // The DeviceAddress is the address of the maped buffer below 16 MB
+ //
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;
+ } else {
+ //
+ // The transfer is below 16 MB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ }
+
+ //
+ // Figure out what to program into the DMA Channel Mode Register
+ //
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
+ } else {
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
+ }
+ //
+ // We only support EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE in simplified IsaIo
+ //
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;
+
+ //
+ // A Slave DMA transfer can not cross a 64K boundary.
+ // Compute *NumberOfBytes based on this restriction.
+ //
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
+ if (*NumberOfBytes > MaxNumberOfBytes) {
+ *NumberOfBytes = MaxNumberOfBytes;
+ }
+ //
+ // Compute the values to program into the BaseAddress and Count registers
+ // of the Slave DMA controller
+ //
+ BaseAddress = (UINT32) (*DeviceAddress);
+ Count = (UINT16) (*NumberOfBytes - 1);
+ //
+ // Program the DMA Write Single Mask Register for ChannelNumber
+ // Clear the DMA Byte Pointer Register
+ //
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;
+ DmaClear = R_8237_DMA_CBPR_CH0_3;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaClear,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, DmaChannelMode, DmaMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WriteDmaPort (
+ This,
+ mDmaRegisters[ChannelNumber].Address,
+ mDmaRegisters[ChannelNumber].Page,
+ mDmaRegisters[ChannelNumber].Count,
+ BaseAddress,
+ Count
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (ChannelNumber & 0x03)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Maps a memory region for DMA. This implementation implement the
+ the full mapping support.
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS - The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER - The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED - The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR - The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES - The memory pages could not be allocated.
+**/
+EFI_STATUS
+IsaIoMapFullSupport (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Master;
+ BOOLEAN Read;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ ISA_MAP_INFO *IsaMapInfo;
+ UINT8 DmaMode;
+ UINTN MaxNumberOfBytes;
+ UINT32 BaseAddress;
+ UINT16 Count;
+ UINT8 DmaMask;
+ UINT8 DmaClear;
+ UINT8 DmaChannelMode;
+
+ if ((NULL == This) ||
+ (NULL == HostAddress) ||
+ (NULL == NumberOfBytes) ||
+ (NULL == DeviceAddress) ||
+ (NULL == Mapping)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the return values to their defaults
+ //
+ *Mapping = NULL;
+
+ //
+ // Make sure the Operation parameter is valid
+ //
+ if ((UINT32)Operation >= EfiIsaIoOperationMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber >= 8) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // See if this is a Slave DMA Operation
+ //
+ Master = TRUE;
+ Read = FALSE;
+ if (Operation == EfiIsaIoOperationSlaveRead) {
+ Operation = EfiIsaIoOperationBusMasterRead;
+ Master = FALSE;
+ Read = TRUE;
+ }
+
+ if (Operation == EfiIsaIoOperationSlaveWrite) {
+ Operation = EfiIsaIoOperationBusMasterWrite;
+ Master = FALSE;
+ Read = FALSE;
+ }
+
+ if (!Master) {
+ //
+ // Make sure that ChannelNumber is a valid channel number
+ // Channel 4 is used to cascade, so it is illegal.
+ //
+ if (ChannelNumber == 4 || ChannelNumber > 7) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // This implementation only support COMPATIBLE DMA Transfers
+ //
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((ChannelAttributes &
+ (EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A |
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B |
+ EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C)) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ChannelNumber < 4) {
+ //
+ // If this is Channel 0..3, then the width must be 8 bit
+ //
+ if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) == 0) ||
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) != 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // If this is Channel 4..7, then the width must be 16 bit
+ //
+ if (((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8) != 0) ||
+ ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16) == 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Either Demand Mode or Single Mode must be selected, but not both
+ //
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+ //
+ // Map the HostAddress to a DeviceAddress.
+ //
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress;
+ if ((PhysicalAddress +*NumberOfBytes) > BASE_16MB) {
+ //
+ // Common Buffer operations can not be remapped. If the common buffer
+ // is above 16MB, then it is not possible to generate a mapping, so return
+ // an error.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterCommonBuffer) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Allocate an ISA_MAP_INFO structure to remember the mapping when Unmap()
+ // is called later.
+ //
+ IsaMapInfo = AllocatePool (sizeof (ISA_MAP_INFO));
+ if (IsaMapInfo == NULL) {
+ *NumberOfBytes = 0;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Return a pointer to the MAP_INFO structure in Mapping
+ //
+ *Mapping = IsaMapInfo;
+
+ //
+ // Initialize the MAP_INFO structure
+ //
+ IsaMapInfo->Operation = Operation;
+ IsaMapInfo->NumberOfBytes = *NumberOfBytes;
+ IsaMapInfo->NumberOfPages = EFI_SIZE_TO_PAGES (*NumberOfBytes);
+ IsaMapInfo->HostAddress = PhysicalAddress;
+ IsaMapInfo->MappedHostAddress = BASE_16MB - 1;
+
+ //
+ // Allocate a buffer below 16MB to map the transfer to.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ IsaMapInfo->NumberOfPages,
+ &IsaMapInfo->MappedHostAddress
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (IsaMapInfo);
+ *NumberOfBytes = 0;
+ *Mapping = NULL;
+ return Status;
+ }
+ //
+ // If this is a read operation from the DMA agents's point of view,
+ // then copy the contents of the real buffer into the mapped buffer
+ // so the DMA agent can read the contents of the real buffer.
+ //
+ if (Operation == EfiIsaIoOperationBusMasterRead) {
+ CopyMem (
+ (VOID *) (UINTN) IsaMapInfo->MappedHostAddress,
+ (VOID *) (UINTN) IsaMapInfo->HostAddress,
+ IsaMapInfo->NumberOfBytes
+ );
+ }
+ //
+ // The DeviceAddress is the address of the maped buffer below 16 MB
+ //
+ *DeviceAddress = IsaMapInfo->MappedHostAddress;
+ } else {
+ //
+ // The transfer is below 16 MB, so the DeviceAddress is simply the
+ // HostAddress
+ //
+ *DeviceAddress = PhysicalAddress;
+ }
+ //
+ // If this is a Bus Master operation then return
+ //
+ if (Master) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Figure out what to program into the DMA Channel Mode Register
+ //
+ DmaMode = (UINT8) (B_8237_DMA_CHMODE_INCREMENT | (ChannelNumber & 0x03));
+ if (Read) {
+ DmaMode |= V_8237_DMA_CHMODE_MEM2IO;
+ } else {
+ DmaMode |= V_8237_DMA_CHMODE_IO2MEM;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE) != 0) {
+ DmaMode |= B_8237_DMA_CHMODE_AE;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE) != 0) {
+ DmaMode |= V_8237_DMA_CHMODE_DEMAND;
+ }
+
+ if ((ChannelAttributes & EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE) != 0) {
+ DmaMode |= V_8237_DMA_CHMODE_SINGLE;
+ }
+ //
+ // A Slave DMA transfer can not cross a 64K boundary.
+ // Compute *NumberOfBytes based on this restriction.
+ //
+ MaxNumberOfBytes = 0x10000 - ((UINT32) (*DeviceAddress) & 0xffff);
+ if (*NumberOfBytes > MaxNumberOfBytes) {
+ *NumberOfBytes = MaxNumberOfBytes;
+ }
+ //
+ // Compute the values to program into the BaseAddress and Count registers
+ // of the Slave DMA controller
+ //
+ if (ChannelNumber < 4) {
+ BaseAddress = (UINT32) (*DeviceAddress);
+ Count = (UINT16) (*NumberOfBytes - 1);
+ } else {
+ BaseAddress = (UINT32) (((UINT32) (*DeviceAddress) & 0xff0000) | (((UINT32) (*DeviceAddress) & 0xffff) >> 1));
+ Count = (UINT16) ((*NumberOfBytes - 1) >> 1);
+ }
+ //
+ // Program the DMA Write Single Mask Register for ChannelNumber
+ // Clear the DMA Byte Pointer Register
+ //
+ if (ChannelNumber < 4) {
+ DmaMask = R_8237_DMA_WRSMSK_CH0_3;
+ DmaClear = R_8237_DMA_CBPR_CH0_3;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH0_3;
+ } else {
+ DmaMask = R_8237_DMA_WRSMSK_CH4_7;
+ DmaClear = R_8237_DMA_CBPR_CH4_7;
+ DmaChannelMode = R_8237_DMA_CHMODE_CH4_7;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaClear,
+ (UINT8) (B_8237_DMA_WRSMSK_CMS | (ChannelNumber & 0x03))
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (This, DmaChannelMode, DmaMode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WriteDmaPort (
+ This,
+ mDmaRegisters[ChannelNumber].Address,
+ mDmaRegisters[ChannelNumber].Page,
+ mDmaRegisters[ChannelNumber].Count,
+ BaseAddress,
+ Count
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = WritePort (
+ This,
+ DmaMask,
+ (UINT8) (ChannelNumber & 0x03)
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Maps a memory region for DMA
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ )
+{
+ //
+ // Check if DMA is supported.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Set Feature Flag PcdIsaBusSupportBusMaster to FALSE to disable support for
+ // ISA Bus Master.
+ //
+ // So we just return EFI_UNSUPPORTED for these functions.
+ //
+ if ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0) {
+ return IsaIoMapOnlySupportSlaveReadWrite (
+ This,
+ Operation,
+ ChannelNumber,
+ ChannelAttributes,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+
+ } else {
+ return IsaIoMapFullSupport (
+ This,
+ Operation,
+ ChannelNumber,
+ ChannelAttributes,
+ HostAddress,
+ NumberOfBytes,
+ DeviceAddress,
+ Mapping
+ );
+ }
+}
+
+/**
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Type The type allocation to perform.
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of pages to allocate.
+ @param[out] HostAddress A pointer to store the base address of the allocated range.
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
+ @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
+ by HostAddress, Pages, and Type is not available for common buffer use.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoAllocateBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+
+ //
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
+ // ISA Bus Master.
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
+ //
+ if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (HostAddress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((UINT32)Type >= MaxAllocateType) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // The only valid memory types are EfiBootServicesData and EfiRuntimeServicesData
+ //
+ if (MemoryType != EfiBootServicesData && MemoryType != EfiRuntimeServicesData) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Attributes & ~(EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE | EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ PhysicalAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) (BASE_16MB - 1);
+ if (Type == AllocateAddress) {
+ if ((UINTN) (*HostAddress) >= BASE_16MB) {
+ return EFI_UNSUPPORTED;
+ } else {
+ PhysicalAddress = (UINTN) (*HostAddress);
+ }
+ }
+
+ if (Type == AllocateAnyPages) {
+ Type = AllocateMaxAddress;
+ }
+
+ Status = gBS->AllocatePages (Type, MemoryType, Pages, &PhysicalAddress);
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ return Status;
+ }
+
+ *HostAddress = (VOID *) (UINTN) PhysicalAddress;
+ return Status;
+}
+
+/**
+ Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Pages The number of pages to free.
+ @param[in] HostAddress The base address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFreeBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Set Feature Flag PcdIsaBusOnlySupportSlaveDma to FALSE to disable support for
+ // ISA Bus Master.
+ // Or unset Feature Flag PcdIsaBusSupportDma to disable support for ISA DMA.
+ //
+ if (((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_SUPPORT_DMA) == 0) ||
+ ((PcdGet8 (PcdIsaBusSupportedFeatures) & PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA) != 0)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) HostAddress,
+ Pages
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_IO_BUS_LPC | EFI_IOB_EC_CONTROLLER_ERROR
+ );
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.h
new file mode 100644
index 0000000000..cc4a1f8b80
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIo.h
@@ -0,0 +1,331 @@
+/** @file
+ The header file for EFI_ISA_IO protocol implementation.
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ISA_IO_H_
+#define _ISA_IO_H_
+
+#include "IsaDriver.h"
+
+//
+// Bits definition of PcdIsaBusSupportedFeatures
+//
+#define PCD_ISA_BUS_SUPPORT_DMA BIT0
+#define PCD_ISA_BUS_ONLY_SUPPORT_SLAVE_DMA BIT1
+#define PCD_ISA_BUS_SUPPORT_ISA_MEMORY BIT2
+
+//
+// ISA I/O Support Function Prototypes
+//
+
+/**
+ Verifies access to an ISA device
+
+ @param[in] IsaIoDevice The ISA device to be verified.
+ @param[in] Type The Access type. The input must be either IsaAccessTypeMem or IsaAccessTypeIo.
+ @param[in] Width The width of the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+
+ @retval EFI_SUCCESS Verify success.
+ @retval EFI_INVALID_PARAMETER One of the parameters has an invalid value.
+ @retval EFI_UNSUPPORTED The device ont support the access type.
+**/
+EFI_STATUS
+IsaIoVerifyAccess (
+ IN ISA_IO_DEVICE *IsaIoDevice,
+ IN ISA_ACCESS_TYPE Type,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINTN Count,
+ IN UINT32 Offset
+ );
+
+/**
+ Performs an ISA I/O Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Performs an ISA I/O Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O operation.
+ @param[in] Offset The offset in ISA I/O space to start the I/O operation.
+ @param[in] Count The number of I/O operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was writen to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoIoWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Maps a memory region for DMA
+
+ @param This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param Operation Indicates the type of DMA (slave or bus master), and if
+ the DMA operation is going to read or write to system memory.
+ @param ChannelNumber The slave channel number to use for this DMA operation.
+ If Operation and ChannelAttributes shows that this device
+ performs bus mastering DMA, then this field is ignored.
+ The legal range for this field is 0..7.
+ @param ChannelAttributes The attributes of the DMA channel to use for this DMA operation
+ @param HostAddress The system memory address to map to the device.
+ @param NumberOfBytes On input the number of bytes to map. On output the number
+ of bytes that were mapped.
+ @param DeviceAddress The resulting map address for the bus master device to use
+ to access the hosts HostAddress.
+ @param Mapping A resulting value to pass to EFI_ISA_IO.Unmap().
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation or HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Unmaps a memory region for DMA
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO.Map().
+
+ @retval EFI_SUCCESS The range was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoUnmap (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Flushes any posted write data to the system memory.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The buffers were flushed.
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFlush (
+ IN EFI_ISA_IO_PROTOCOL *This
+ );
+
+/**
+ Writes I/O operation base address and count number to a 8 bit I/O Port.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] AddrOffset The address' offset.
+ @param[in] PageOffset The page's offest.
+ @param[in] CountOffset The count's offset.
+ @param[in] BaseAddress The base address.
+ @param[in] Count The number of I/O operations to perform.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by these Offsets and Count is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WriteDmaPort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 AddrOffset,
+ IN UINT32 PageOffset,
+ IN UINT32 CountOffset,
+ IN UINT32 BaseAddress,
+ IN UINT16 Count
+ );
+
+/**
+ Writes an 8-bit I/O Port
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Offset The offset in ISA IO space to start the IO operation.
+ @param[in] Value The data to write port.
+
+ @retval EFI_SUCCESS Success.
+ @retval EFI_INVALID_PARAMETER Parameter is invalid.
+ @retval EFI_UNSUPPORTED The address range specified by Offset is not valid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+WritePort (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINT32 Offset,
+ IN UINT8 Value
+ );
+
+/**
+ Performs an ISA Memory Read Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[out] Buffer The destination buffer to store the results
+
+ @retval EFI_SUCCESS The data was read from the device successfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemRead (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+
+/**
+ Performs an ISA Memory Write Cycle
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory operation.
+ @param[in] Offset The offset in ISA memory space to start the memory operation.
+ @param[in] Count The number of memory operations to perform.
+ @param[in] Buffer The source buffer to write data from
+
+ @retval EFI_SUCCESS The data was written to the device sucessfully.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoMemWrite (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Copy one region of ISA memory space to another region of ISA memory space on the ISA controller.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the memory copy operation.
+ @param[in] DestOffset The offset of the destination
+ @param[in] SrcOffset The offset of the source
+ @param[in] Count The number of memory copy operations to perform
+
+ @retval EFI_SUCCESS The data was copied sucessfully.
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoCopyMem (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 DestOffset,
+ IN UINT32 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer mapping.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Type The type allocation to perform.
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of pages to allocate.
+ @param[out] HostAddress A pointer to store the base address of the allocated range.
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER Type is invalid or MemoryType is invalid or HostAddress is NULL
+ @retval EFI_UNSUPPORTED Attributes is unsupported or the memory range specified
+ by HostAddress, Pages, and Type is not available for common buffer use.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+**/
+EFI_STATUS
+EFIAPI
+IsaIoAllocateBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees memory that was allocated with EFI_ISA_IO.AllocateBuffer().
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Pages The number of pages to free.
+ @param[in] HostAddress The base address of the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
+**/
+EFI_STATUS
+EFIAPI
+IsaIoFreeBuffer (
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.inf
new file mode 100644
index 0000000000..499cf434f5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.inf
@@ -0,0 +1,71 @@
+## @file
+# Produces an instance of the ISA I/O Protocol for every SIO controller.
+#
+# Produces an instance of the ISA I/O Protocol for every SIO controller. The ISA
+# I/O protocols are installed based off of the information provided by each
+# instance of the SIO Protocol found.
+#
+# Copyright (c) 2010 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaIoDxe
+ MODULE_UNI_FILE = IsaIoDxe.uni
+ FILE_GUID = 61AD3083-DCAD-4850-A50C-73B23B3B14F9
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIsaIo
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gIsaIoDriver
+# COMPONENT_NAME = gIsaIoComponentName;
+# COMPONENT_NAME2 = gIsaIoComponentName2;
+#
+
+[Sources]
+ ComponentName.h
+ ComponentName.c
+ IsaIo.h
+ IsaIo.c
+ IsaDriver.h
+ IsaDriver.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## BY_START
+ gEfiSioProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiGenericMemTestProtocolGuid ## TO_START
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSupportedFeatures ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaIoDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.uni
new file mode 100644
index 0000000000..9cfecb2395
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxeExtra.uni
new file mode 100644
index 0000000000..6b6dc83e89
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/ComponentName.c
new file mode 100644
index 0000000000..ef24008f6b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/ComponentName.c
@@ -0,0 +1,272 @@
+/** @file
+ UEFI Component Name and Name2 protocol for Isa serial driver.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Serial.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIsaSerialComponentName = {
+ IsaSerialComponentNameGetDriverName,
+ IsaSerialComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIsaSerialComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IsaSerialComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IsaSerialComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIsaSerialDriverNameTable[] = {
+ {
+ "eng;en",
+ L"ISA Serial Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED CHAR16 mSerialPortName[] = L"ISA Serial Port # ";
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIsaSerialDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gIsaSerialComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ SERIAL_DEV *SerialDevice;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ //
+ // Make sure this driver is currently managing ControllerHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gSerialControllerDriver.DriverBindingHandle,
+ &gEfiIsaIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ControllerNameTable = NULL;
+ if (ChildHandle != NULL) {
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiIsaIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the Serial I/O Protocol from the child handle
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ gSerialControllerDriver.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the Serial Controller's Device structure
+ //
+ SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
+ ControllerNameTable = SerialDevice->ControllerNameTable;
+ }
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gIsaSerialComponentName)
+ );
+}
+
+/**
+ Add the ISO639-2 and RFC4646 component name both for the Serial IO device
+
+ @param SerialDevice A pointer to the SERIAL_DEV instance.
+
+ @param IsaIo A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+**/
+VOID
+AddName (
+ IN SERIAL_DEV *SerialDevice,
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ mSerialPortName[(sizeof (mSerialPortName) / 2) - 2] = (CHAR16) (L'0' + (UINT8) IsaIo->ResourceList->Device.UID);
+ AddUnicodeString2 (
+ "eng",
+ gIsaSerialComponentName.SupportedLanguages,
+ &SerialDevice->ControllerNameTable,
+ mSerialPortName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gIsaSerialComponentName2.SupportedLanguages,
+ &SerialDevice->ControllerNameTable,
+ mSerialPortName,
+ FALSE
+ );
+
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
new file mode 100644
index 0000000000..4abaac9ff8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
@@ -0,0 +1,80 @@
+## @file
+# Serial driver for standard UARTS on an ISA bus.
+#
+# Produces the Serial I/O protocol for standard UARTS using ISA I/O. This driver
+# supports the 8250, 16450, 16550 and 16550A UART types.
+#
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IsaSerialDxe
+ MODULE_UNI_FILE = IsaSerialDxe.uni
+ FILE_GUID = 93B80003-9FB3-11d4-9A3A-0090273FC14D
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIsaSerial
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gSerialControllerDriver
+# COMPONENT_NAME = gIsaSerialComponentName
+# COMPONENT_NAME2 = gIsaSerialComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ Serial.h
+ Serial.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ DevicePathLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Guids]
+ gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiSerialIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultBaudRate|115200 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultDataBits|8 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultParity|1 ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUartDefaultStopBits|1 ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSerialClockRate|1843200 ## CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IsaSerialDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.uni
new file mode 100644
index 0000000000..6b99f490e5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxeExtra.uni
new file mode 100644
index 0000000000..47bc80b42b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
new file mode 100644
index 0000000000..57ee669d14
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.c
@@ -0,0 +1,2038 @@
+/** @file
+ Serial driver for standard UARTS on an ISA bus.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Serial.h"
+
+//
+// ISA Serial Driver Global Variables
+//
+EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver = {
+ SerialControllerDriverSupported,
+ SerialControllerDriverStart,
+ SerialControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+
+SERIAL_DEV gSerialDevTempate = {
+ SERIAL_DEV_SIGNATURE,
+ NULL,
+ { // SerialIo
+ SERIAL_IO_INTERFACE_REVISION,
+ IsaSerialReset,
+ IsaSerialSetAttributes,
+ IsaSerialSetControl,
+ IsaSerialGetControl,
+ IsaSerialWrite,
+ IsaSerialRead,
+ NULL
+ },
+ { // SerialMode
+ SERIAL_PORT_SUPPORT_CONTROL_MASK,
+ SERIAL_PORT_DEFAULT_TIMEOUT,
+ 0,
+ SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH,
+ 0,
+ 0,
+ 0
+ },
+ NULL,
+ NULL,
+ { // UartDevicePath
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_UART_DP,
+ {
+ (UINT8) (sizeof (UART_DEVICE_PATH)),
+ (UINT8) ((sizeof (UART_DEVICE_PATH)) >> 8)
+ }
+ },
+ 0,
+ 0,
+ 0,
+ 0,
+ 0
+ },
+ NULL,
+ 0, //BaseAddress
+ {
+ 0,
+ 0,
+ SERIAL_MAX_BUFFER_SIZE,
+ { 0 }
+ },
+ {
+ 0,
+ 0,
+ SERIAL_MAX_BUFFER_SIZE,
+ { 0 }
+ },
+ FALSE,
+ FALSE,
+ Uart16550A,
+ NULL
+};
+
+/**
+ Check the device path node whether it's the Flow Control node or not.
+
+ @param[in] FlowControl The device path node to be checked.
+
+ @retval TRUE It's the Flow Control node.
+ @retval FALSE It's not.
+
+**/
+BOOLEAN
+IsUartFlowControlNode (
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
+ )
+{
+ return (BOOLEAN) (
+ (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
+ (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
+ );
+}
+
+/**
+ Check the device path node whether it contains Flow Control node or not.
+
+ @param[in] DevicePath The device path to be checked.
+
+ @retval TRUE It contains the Flow Control node.
+ @retval FALSE It doesn't.
+
+**/
+BOOLEAN
+ContainsFlowControl (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ while (!IsDevicePathEnd (DevicePath)) {
+ if (IsUartFlowControlNode ((UART_FLOW_CONTROL_DEVICE_PATH *) DevicePath)) {
+ return TRUE;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ return FALSE;
+}
+
+/**
+ The user Entry Point for module IsaSerial. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeIsaSerial (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gSerialControllerDriver,
+ ImageHandle,
+ &gIsaSerialComponentName,
+ &gIsaSerialComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Initialize UART default setting in gSerialDevTempate
+ //
+ gSerialDevTempate.SerialMode.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ gSerialDevTempate.SerialMode.DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ gSerialDevTempate.SerialMode.Parity = PcdGet8 (PcdUartDefaultParity);
+ gSerialDevTempate.SerialMode.StopBits = PcdGet8 (PcdUartDefaultStopBits);
+ gSerialDevTempate.UartDevicePath.BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ gSerialDevTempate.UartDevicePath.DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ gSerialDevTempate.UartDevicePath.Parity = PcdGet8 (PcdUartDefaultParity);
+ gSerialDevTempate.UartDevicePath.StopBits = PcdGet8 (PcdUartDefaultStopBits);
+
+ return Status;
+}
+
+/**
+ Check to see if this driver supports the given controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @return EFI_SUCCESS This driver can support the given controller
+
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UART_DEVICE_PATH *UartNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ BOOLEAN HasFlowControl;
+
+ //
+ // Check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ Status = EFI_UNSUPPORTED;
+
+ UartNode = (UART_DEVICE_PATH *) RemainingDevicePath;
+ if (UartNode->Header.Type != MESSAGING_DEVICE_PATH ||
+ UartNode->Header.SubType != MSG_UART_DP ||
+ sizeof (UART_DEVICE_PATH) != DevicePathNodeLength ((EFI_DEVICE_PATH_PROTOCOL *) UartNode)
+ ) {
+ goto Error;
+ }
+
+ if (UartNode->BaudRate > SERIAL_PORT_MAX_BAUD_RATE) {
+ goto Error;
+ }
+
+ if (UartNode->Parity < NoParity || UartNode->Parity > SpaceParity) {
+ goto Error;
+ }
+
+ if (UartNode->DataBits < 5 || UartNode->DataBits > 8) {
+ goto Error;
+ }
+
+ if (UartNode->StopBits < OneStopBit || UartNode->StopBits > TwoStopBits) {
+ goto Error;
+ }
+
+ if ((UartNode->DataBits == 5) && (UartNode->StopBits == TwoStopBits)) {
+ goto Error;
+ }
+
+ if ((UartNode->DataBits >= 6) && (UartNode->DataBits <= 8) && (UartNode->StopBits == OneFiveStopBits)) {
+ goto Error;
+ }
+
+ FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (UartNode);
+ if (IsUartFlowControlNode (FlowControlNode)) {
+ //
+ // If the second node is Flow Control Node,
+ // return error when it request other than hardware flow control.
+ //
+ if ((ReadUnaligned32 (&FlowControlNode->FlowControlMap) & ~UART_FLOW_CONTROL_HARDWARE) != 0) {
+ goto Error;
+ }
+ }
+ }
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath is NULL or is the End of Device Path Node
+ //
+ return EFI_SUCCESS;
+ }
+ //
+ // When the driver has produced device path with flow control node but RemainingDevicePath only contains UART node,
+ // return unsupported, and vice versa.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ HasFlowControl = ContainsFlowControl (RemainingDevicePath);
+ if (HasFlowControl ^ ContainsFlowControl (DevicePath)) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ break;
+ }
+ }
+ FreePool (OpenInfoBuffer);
+ return Status;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is standard ISA UART that
+ // can be managed by this driver.
+ //
+ Status = EFI_SUCCESS;
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x501)) {
+ Status = EFI_UNSUPPORTED;
+ goto Error;
+ }
+
+Error:
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start to management the controller passed in
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @return EFI_SUCCESS Driver is started successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ SERIAL_DEV *SerialDevice;
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ UART_DEVICE_PATH *Uart;
+ UINT32 FlowControlMap;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINT32 Control;
+
+ SerialDevice = NULL;
+ //
+ // Get the Parent Device Path
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ return Status;
+ }
+ //
+ // Report status code enable the serial
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_ENABLE | EFI_PERIPHERAL_SERIAL_PORT,
+ ParentDevicePath
+ );
+
+ //
+ // Grab the IO abstraction we need to get any work done
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && Status != EFI_ALREADY_STARTED) {
+ goto Error;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+
+ if (RemainingDevicePath == NULL || IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath is NULL or is the End of Device Path Node
+ //
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Make sure a child handle does not already exist. This driver can only
+ // produce one child per serial port.
+ //
+ Status = gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = EFI_ALREADY_STARTED;
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Uart = (UART_DEVICE_PATH *) RemainingDevicePath;
+ Status = SerialIo->SetAttributes (
+ SerialIo,
+ Uart->BaudRate,
+ SerialIo->Mode->ReceiveFifoDepth,
+ SerialIo->Mode->Timeout,
+ (EFI_PARITY_TYPE) Uart->Parity,
+ Uart->DataBits,
+ (EFI_STOP_BITS_TYPE) Uart->StopBits
+ );
+
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Uart);
+ if (!EFI_ERROR (Status) && IsUartFlowControlNode (FlowControl)) {
+ Status = SerialIo->GetControl (SerialIo, &Control);
+ if (!EFI_ERROR (Status)) {
+ if (ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) {
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ } else {
+ Control &= ~EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+ //
+ // Clear the bits that are not allowed to pass to SetControl
+ //
+ Control &= (EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE);
+ Status = SerialIo->SetControl (SerialIo, Control);
+ }
+ }
+ }
+ break;
+ }
+ }
+
+ FreePool (OpenInfoBuffer);
+ return Status;
+ }
+
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCESSS
+ //
+ return EFI_SUCCESS;
+ }
+ }
+
+ //
+ // Initialize the serial device instance
+ //
+ SerialDevice = AllocateCopyPool (sizeof (SERIAL_DEV), &gSerialDevTempate);
+ if (SerialDevice == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ SerialDevice->SerialIo.Mode = &(SerialDevice->SerialMode);
+ SerialDevice->IsaIo = IsaIo;
+ SerialDevice->ParentDevicePath = ParentDevicePath;
+ FlowControl = NULL;
+ FlowControlMap = 0;
+
+ //
+ // Check if RemainingDevicePath is NULL,
+ // if yes, use the values from the gSerialDevTempate as no remaining device path was
+ // passed in.
+ //
+ if (RemainingDevicePath != NULL) {
+ //
+ // If RemainingDevicePath isn't NULL,
+ // match the configuration of the RemainingDevicePath. IsHandleSupported()
+ // already checked to make sure the RemainingDevicePath contains settings
+ // that we can support.
+ //
+ CopyMem (&SerialDevice->UartDevicePath, RemainingDevicePath, sizeof (UART_DEVICE_PATH));
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (RemainingDevicePath);
+ if (IsUartFlowControlNode (FlowControl)) {
+ FlowControlMap = ReadUnaligned32 (&FlowControl->FlowControlMap);
+ } else {
+ FlowControl = NULL;
+ }
+ }
+
+ AddName (SerialDevice, IsaIo);
+
+ for (Index = 0; SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type != EfiIsaAcpiResourceEndOfList; Index++) {
+ if (SerialDevice->IsaIo->ResourceList->ResourceItem[Index].Type == EfiIsaAcpiResourceIo) {
+ SerialDevice->BaseAddress = (UINT16) SerialDevice->IsaIo->ResourceList->ResourceItem[Index].StartRange;
+ }
+ }
+
+ SerialDevice->HardwareFlowControl = (BOOLEAN) (FlowControlMap == UART_FLOW_CONTROL_HARDWARE);
+
+ //
+ // Report status code the serial present
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_PRESENCE_DETECT | EFI_PERIPHERAL_SERIAL_PORT,
+ ParentDevicePath
+ );
+
+ if (!IsaSerialPortPresent (SerialDevice)) {
+ Status = EFI_DEVICE_ERROR;
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_NOT_DETECTED | EFI_PERIPHERAL_SERIAL_PORT,
+ ParentDevicePath
+ );
+ goto Error;
+ }
+
+ //
+ // Build the device path by appending the UART node to the ParentDevicePath.
+ // The Uart setings are zero here, since SetAttribute() will update them to match
+ // the default setings.
+ //
+ SerialDevice->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &SerialDevice->UartDevicePath
+ );
+ //
+ // Only produce the Flow Control node when remaining device path has it
+ //
+ if (FlowControl != NULL) {
+ TempDevicePath = SerialDevice->DevicePath;
+ if (TempDevicePath != NULL) {
+ SerialDevice->DevicePath = AppendDevicePathNode (
+ TempDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) FlowControl
+ );
+ FreePool (TempDevicePath);
+ }
+ }
+ if (SerialDevice->DevicePath == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Error;
+ }
+
+ //
+ // Fill in Serial I/O Mode structure based on either the RemainingDevicePath or defaults.
+ //
+ SerialDevice->SerialMode.BaudRate = SerialDevice->UartDevicePath.BaudRate;
+ SerialDevice->SerialMode.DataBits = SerialDevice->UartDevicePath.DataBits;
+ SerialDevice->SerialMode.Parity = SerialDevice->UartDevicePath.Parity;
+ SerialDevice->SerialMode.StopBits = SerialDevice->UartDevicePath.StopBits;
+
+ //
+ // Issue a reset to initialize the COM port
+ //
+ Status = SerialDevice->SerialIo.Reset (&SerialDevice->SerialIo);
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_CONTROLLER_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
+ ParentDevicePath
+ );
+ goto Error;
+ }
+ //
+ // Install protocol interfaces for the serial device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &SerialDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ SerialDevice->DevicePath,
+ &gEfiSerialIoProtocolGuid,
+ &SerialDevice->SerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ SerialDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+Error:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (SerialDevice != NULL) {
+ if (SerialDevice->DevicePath != NULL) {
+ gBS->FreePool (SerialDevice->DevicePath);
+ }
+
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
+ gBS->FreePool (SerialDevice);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Disconnect this driver with the controller, uninstall related protocol instance
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren Number of child device.
+ @param ChildHandleBuffer A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Operation successfully
+ @retval EFI_DEVICE_ERROR Cannot stop the driver successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ SERIAL_DEV *SerialDevice;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+
+ //
+ // Report the status code disable the serial
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_DISABLE | EFI_PERIPHERAL_SERIAL_PORT,
+ DevicePath
+ );
+
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (SerialIo);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ SerialDevice->DevicePath,
+ &gEfiSerialIoProtocolGuid,
+ &SerialDevice->SerialIo,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+ if (SerialDevice->DevicePath != NULL) {
+ gBS->FreePool (SerialDevice->DevicePath);
+ }
+
+ FreeUnicodeStringTable (SerialDevice->ControllerNameTable);
+ gBS->FreePool (SerialDevice);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Detect whether specific FIFO is full or not.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+
+ @return whether specific FIFO is full or not
+
+**/
+BOOLEAN
+IsaSerialFifoFull (
+ IN SERIAL_DEV_FIFO *Fifo
+ )
+
+{
+ if (Fifo->Surplus == 0) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Detect whether specific FIFO is empty or not.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+
+ @return whether specific FIFO is empty or not
+
+**/
+BOOLEAN
+IsaSerialFifoEmpty (
+ IN SERIAL_DEV_FIFO *Fifo
+ )
+
+{
+ if (Fifo->Surplus == SERIAL_MAX_BUFFER_SIZE) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Add data to specific FIFO.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+ @param Data the data added to FIFO
+
+ @retval EFI_SUCCESS Add data to specific FIFO successfully
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
+
+**/
+EFI_STATUS
+IsaSerialFifoAdd (
+ IN SERIAL_DEV_FIFO *Fifo,
+ IN UINT8 Data
+ )
+
+{
+ //
+ // if FIFO full can not add data
+ //
+ if (IsaSerialFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not full can add data
+ //
+ Fifo->Data[Fifo->Last] = Data;
+ Fifo->Surplus--;
+ Fifo->Last++;
+ if (Fifo->Last == SERIAL_MAX_BUFFER_SIZE) {
+ Fifo->Last = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove data from specific FIFO.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+ @param Data the data removed from FIFO
+
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
+
+**/
+EFI_STATUS
+IsaSerialFifoRemove (
+ IN SERIAL_DEV_FIFO *Fifo,
+ OUT UINT8 *Data
+ )
+
+{
+ //
+ // if FIFO is empty, no data can remove
+ //
+ if (IsaSerialFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // FIFO is not empty, can remove data
+ //
+ *Data = Fifo->Data[Fifo->First];
+ Fifo->Surplus++;
+ Fifo->First++;
+ if (Fifo->First == SERIAL_MAX_BUFFER_SIZE) {
+ Fifo->First = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads and writes all avaliable data.
+
+ @param SerialDevice The device to flush
+
+ @retval EFI_SUCCESS Data was read/written successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
+ this happens, pending writes are not done.
+
+**/
+EFI_STATUS
+IsaSerialReceiveTransmit (
+ IN SERIAL_DEV *SerialDevice
+ )
+
+{
+ SERIAL_PORT_LSR Lsr;
+ UINT8 Data;
+ BOOLEAN ReceiveFifoFull;
+ SERIAL_PORT_MSR Msr;
+ SERIAL_PORT_MCR Mcr;
+ UINTN TimeOut;
+
+ Data = 0;
+
+ //
+ // Begin the read or write
+ //
+ if (SerialDevice->SoftwareLoopbackEnable) {
+ do {
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
+ if (!IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
+ if (ReceiveFifoFull) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ IsaSerialFifoAdd (&SerialDevice->Receive, Data);
+ }
+ } while (!IsaSerialFifoEmpty (&SerialDevice->Transmit));
+ } else {
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
+ //
+ // For full handshake flow control, tell the peer to send data
+ // if receive buffer is available.
+ //
+ if (SerialDevice->HardwareFlowControl &&
+ !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)&&
+ !ReceiveFifoFull
+ ) {
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.Rts = 1;
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+ }
+ do {
+ Lsr.Data = READ_LSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+
+ //
+ // Flush incomming data to prevent a an overrun during a long write
+ //
+ if ((Lsr.Bits.Dr == 1) && !ReceiveFifoFull) {
+ ReceiveFifoFull = IsaSerialFifoFull (&SerialDevice->Receive);
+ if (!ReceiveFifoFull) {
+ if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Oe == 1 || Lsr.Bits.Pe == 1 || Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->DevicePath
+ );
+ if (Lsr.Bits.FIFOe == 1 || Lsr.Bits.Pe == 1|| Lsr.Bits.Fe == 1 || Lsr.Bits.Bi == 1) {
+ Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ continue;
+ }
+ }
+
+ Data = READ_RBR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+
+ IsaSerialFifoAdd (&SerialDevice->Receive, Data);
+
+ //
+ // For full handshake flow control, if receive buffer full
+ // tell the peer to stop sending data.
+ //
+ if (SerialDevice->HardwareFlowControl &&
+ !FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake) &&
+ IsaSerialFifoFull (&SerialDevice->Receive)
+ ) {
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.Rts = 0;
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+ }
+
+
+ continue;
+ } else {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_SERIAL_PORT_PC_CLEAR_BUFFER | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->DevicePath
+ );
+ }
+ }
+ //
+ // Do the write
+ //
+ if (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
+ //
+ // Make sure the transmit data will not be missed
+ //
+ if (SerialDevice->HardwareFlowControl) {
+ //
+ // For half handshake flow control assert RTS before sending.
+ //
+ if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.Rts= 0;
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+ }
+ //
+ // Wait for CTS
+ //
+ TimeOut = 0;
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ while ((Msr.Bits.Dcd == 1) && ((Msr.Bits.Cts == 0) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);
+ TimeOut++;
+ if (TimeOut > 5) {
+ break;
+ }
+
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ }
+
+ if ((Msr.Bits.Dcd == 0) || ((Msr.Bits.Cts == 1) ^ FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake))) {
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
+ WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
+ }
+
+ //
+ // For half handshake flow control, tell DCE we are done.
+ //
+ if (FeaturePcdGet(PcdIsaBusSerialUseHalfHandshake)) {
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.Rts = 1;
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+ }
+ } else {
+ IsaSerialFifoRemove (&SerialDevice->Transmit, &Data);
+ WRITE_THR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Data);
+ }
+ }
+ } while (Lsr.Bits.Thre == 1 && !IsaSerialFifoEmpty (&SerialDevice->Transmit));
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// Interface Functions
+//
+/**
+ Reset serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Reset successfully
+ @retval EFI_DEVICE_ERROR Failed to reset
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ SERIAL_DEV *SerialDevice;
+ SERIAL_PORT_LCR Lcr;
+ SERIAL_PORT_IER Ier;
+ SERIAL_PORT_MCR Mcr;
+ SERIAL_PORT_FCR Fcr;
+ EFI_TPL Tpl;
+ UINT32 Control;
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+
+ //
+ // Report the status code reset the serial
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_RESET | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->DevicePath
+ );
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Make sure DLAB is 0.
+ //
+ Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Lcr.Bits.DLab = 0;
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
+
+ //
+ // Turn off all interrupts
+ //
+ Ier.Data = READ_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Ier.Bits.Ravie = 0;
+ Ier.Bits.Theie = 0;
+ Ier.Bits.Rie = 0;
+ Ier.Bits.Mie = 0;
+ WRITE_IER (SerialDevice->IsaIo, SerialDevice->BaseAddress, Ier.Data);
+
+ //
+ // Disable the FIFO.
+ //
+ Fcr.Bits.TrFIFOE = 0;
+ WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
+
+ //
+ // Turn off loopback and disable device interrupt.
+ //
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.Out1 = 0;
+ Mcr.Bits.Out2 = 0;
+ Mcr.Bits.Lme = 0;
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+
+ //
+ // Clear the scratch pad register
+ //
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0);
+
+ //
+ // Go set the current attributes
+ //
+ Status = This->SetAttributes (
+ This,
+ This->Mode->BaudRate,
+ This->Mode->ReceiveFifoDepth,
+ This->Mode->Timeout,
+ (EFI_PARITY_TYPE) This->Mode->Parity,
+ (UINT8) This->Mode->DataBits,
+ (EFI_STOP_BITS_TYPE) This->Mode->StopBits
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (Tpl);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Go set the current control bits
+ //
+ Control = 0;
+ if (SerialDevice->HardwareFlowControl) {
+ Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+ if (SerialDevice->SoftwareLoopbackEnable) {
+ Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
+ }
+ Status = This->SetControl (
+ This,
+ Control
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (Tpl);
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // for 16550A enable FIFO, 16550 disable FIFO
+ //
+ Fcr.Bits.TrFIFOE = 1;
+ Fcr.Bits.ResetRF = 1;
+ Fcr.Bits.ResetTF = 1;
+ WRITE_FCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Fcr.Data);
+
+ //
+ // Reset the software FIFO
+ //
+ SerialDevice->Receive.First = 0;
+ SerialDevice->Receive.Last = 0;
+ SerialDevice->Receive.Surplus = SERIAL_MAX_BUFFER_SIZE;
+ SerialDevice->Transmit.First = 0;
+ SerialDevice->Transmit.Last = 0;
+ SerialDevice->Transmit.Surplus = SERIAL_MAX_BUFFER_SIZE;
+
+ gBS->RestoreTPL (Tpl);
+
+ //
+ // Device reset is complete
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Set new attributes to a serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BaudRate The baudrate of the serial device
+ @param ReceiveFifoDepth The depth of receive FIFO buffer
+ @param Timeout The request timeout for a single char
+ @param Parity The type of parity used in serial device
+ @param DataBits Number of databits used in serial device
+ @param StopBits Number of stopbits used in serial device
+
+ @retval EFI_SUCCESS The new attributes were set
+ @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
+ @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ )
+{
+ EFI_STATUS Status;
+ SERIAL_DEV *SerialDevice;
+ UINT32 Divisor;
+ UINT32 Remained;
+ SERIAL_PORT_LCR Lcr;
+ UART_DEVICE_PATH *Uart;
+ EFI_TPL Tpl;
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+
+ //
+ // Check for default settings and fill in actual values.
+ //
+ if (BaudRate == 0) {
+ BaudRate = PcdGet64 (PcdUartDefaultBaudRate);
+ }
+
+ if (ReceiveFifoDepth == 0) {
+ ReceiveFifoDepth = SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH;
+ }
+
+ if (Timeout == 0) {
+ Timeout = SERIAL_PORT_DEFAULT_TIMEOUT;
+ }
+
+ if (Parity == DefaultParity) {
+ Parity = (EFI_PARITY_TYPE)PcdGet8 (PcdUartDefaultParity);
+ }
+
+ if (DataBits == 0) {
+ DataBits = PcdGet8 (PcdUartDefaultDataBits);
+ }
+
+ if (StopBits == DefaultStopBits) {
+ StopBits = (EFI_STOP_BITS_TYPE) PcdGet8 (PcdUartDefaultStopBits);
+ }
+ //
+ // 5 and 6 data bits can not be verified on a 16550A UART
+ // Return EFI_INVALID_PARAMETER if an attempt is made to use these settings.
+ //
+ if ((DataBits == 5) || (DataBits == 6)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Make sure all parameters are valid
+ //
+ if ((BaudRate > SERIAL_PORT_MAX_BAUD_RATE) || (BaudRate < SERIAL_PORT_MIN_BAUD_RATE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // 50,75,110,134,150,300,600,1200,1800,2000,2400,3600,4800,7200,9600,19200,
+ // 38400,57600,115200
+ //
+ if (BaudRate < 75) {
+ BaudRate = 50;
+ } else if (BaudRate < 110) {
+ BaudRate = 75;
+ } else if (BaudRate < 134) {
+ BaudRate = 110;
+ } else if (BaudRate < 150) {
+ BaudRate = 134;
+ } else if (BaudRate < 300) {
+ BaudRate = 150;
+ } else if (BaudRate < 600) {
+ BaudRate = 300;
+ } else if (BaudRate < 1200) {
+ BaudRate = 600;
+ } else if (BaudRate < 1800) {
+ BaudRate = 1200;
+ } else if (BaudRate < 2000) {
+ BaudRate = 1800;
+ } else if (BaudRate < 2400) {
+ BaudRate = 2000;
+ } else if (BaudRate < 3600) {
+ BaudRate = 2400;
+ } else if (BaudRate < 4800) {
+ BaudRate = 3600;
+ } else if (BaudRate < 7200) {
+ BaudRate = 4800;
+ } else if (BaudRate < 9600) {
+ BaudRate = 7200;
+ } else if (BaudRate < 19200) {
+ BaudRate = 9600;
+ } else if (BaudRate < 38400) {
+ BaudRate = 19200;
+ } else if (BaudRate < 57600) {
+ BaudRate = 38400;
+ } else if (BaudRate < 115200) {
+ BaudRate = 57600;
+ } else if (BaudRate <= SERIAL_PORT_MAX_BAUD_RATE) {
+ BaudRate = 115200;
+ }
+
+ if ((ReceiveFifoDepth < 1) || (ReceiveFifoDepth > SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Timeout < SERIAL_PORT_MIN_TIMEOUT) || (Timeout > SERIAL_PORT_MAX_TIMEOUT)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Parity < NoParity) || (Parity > SpaceParity)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DataBits < 5) || (DataBits > 8)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((StopBits < OneStopBit) || (StopBits > TwoStopBits)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // for DataBits = 6,7,8, StopBits can not set OneFiveStopBits
+ //
+ if ((DataBits >= 6) && (DataBits <= 8) && (StopBits == OneFiveStopBits)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Compute divisor use to program the baud rate using a round determination
+ //
+ Divisor = (UINT32) DivU64x32Remainder (
+ PcdGet32 (PcdSerialClockRate),
+ ((UINT32) BaudRate * 16),
+ &Remained
+ );
+ if (Remained != 0) {
+ Divisor += 1;
+ }
+
+ if ((Divisor == 0) || ((Divisor & 0xffff0000) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Compute the actual baud rate that the serial port will be programmed for.
+ //
+ BaudRate = PcdGet32 (PcdSerialClockRate) / Divisor / 16;
+
+ //
+ // Put serial port on Divisor Latch Mode
+ //
+ Lcr.Data = READ_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Lcr.Bits.DLab = 1;
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
+
+ //
+ // Write the divisor to the serial port
+ //
+ WRITE_DLL (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) (Divisor & 0xff));
+ WRITE_DLM (SerialDevice->IsaIo, SerialDevice->BaseAddress, (UINT8) ((Divisor >> 8) & 0xff));
+
+ //
+ // Put serial port back in normal mode and set remaining attributes.
+ //
+ Lcr.Bits.DLab = 0;
+
+ switch (Parity) {
+ case NoParity:
+ Lcr.Bits.ParEn = 0;
+ Lcr.Bits.EvenPar = 0;
+ Lcr.Bits.SticPar = 0;
+ break;
+
+ case EvenParity:
+ Lcr.Bits.ParEn = 1;
+ Lcr.Bits.EvenPar = 1;
+ Lcr.Bits.SticPar = 0;
+ break;
+
+ case OddParity:
+ Lcr.Bits.ParEn = 1;
+ Lcr.Bits.EvenPar = 0;
+ Lcr.Bits.SticPar = 0;
+ break;
+
+ case SpaceParity:
+ Lcr.Bits.ParEn = 1;
+ Lcr.Bits.EvenPar = 1;
+ Lcr.Bits.SticPar = 1;
+ break;
+
+ case MarkParity:
+ Lcr.Bits.ParEn = 1;
+ Lcr.Bits.EvenPar = 0;
+ Lcr.Bits.SticPar = 1;
+ break;
+
+ default:
+ break;
+ }
+
+ switch (StopBits) {
+ case OneStopBit:
+ Lcr.Bits.StopB = 0;
+ break;
+
+ case OneFiveStopBits:
+ case TwoStopBits:
+ Lcr.Bits.StopB = 1;
+ break;
+
+ default:
+ break;
+ }
+ //
+ // DataBits
+ //
+ Lcr.Bits.SerialDB = (UINT8) ((DataBits - 5) & 0x03);
+ WRITE_LCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Lcr.Data);
+
+ //
+ // Set the Serial I/O mode
+ //
+ This->Mode->BaudRate = BaudRate;
+ This->Mode->ReceiveFifoDepth = ReceiveFifoDepth;
+ This->Mode->Timeout = Timeout;
+ This->Mode->Parity = Parity;
+ This->Mode->DataBits = DataBits;
+ This->Mode->StopBits = StopBits;
+
+ //
+ // See if Device Path Node has actually changed
+ //
+ if (SerialDevice->UartDevicePath.BaudRate == BaudRate &&
+ SerialDevice->UartDevicePath.DataBits == DataBits &&
+ SerialDevice->UartDevicePath.Parity == Parity &&
+ SerialDevice->UartDevicePath.StopBits == StopBits
+ ) {
+ gBS->RestoreTPL (Tpl);
+ return EFI_SUCCESS;
+ }
+ //
+ // Update the device path
+ //
+ SerialDevice->UartDevicePath.BaudRate = BaudRate;
+ SerialDevice->UartDevicePath.DataBits = DataBits;
+ SerialDevice->UartDevicePath.Parity = (UINT8) Parity;
+ SerialDevice->UartDevicePath.StopBits = (UINT8) StopBits;
+
+ Status = EFI_SUCCESS;
+ if (SerialDevice->Handle != NULL) {
+ Uart = (UART_DEVICE_PATH *) (
+ (UINTN) SerialDevice->DevicePath
+ + GetDevicePathSize (SerialDevice->ParentDevicePath)
+ - END_DEVICE_PATH_LENGTH
+ );
+ CopyMem (Uart, &SerialDevice->UartDevicePath, sizeof (UART_DEVICE_PATH));
+ Status = gBS->ReinstallProtocolInterface (
+ SerialDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ SerialDevice->DevicePath,
+ SerialDevice->DevicePath
+ );
+ }
+
+ gBS->RestoreTPL (Tpl);
+
+ return Status;
+}
+
+/**
+ Set Control Bits.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param Control Control bits that can be settable
+
+ @retval EFI_SUCCESS New Control bits were set successfully
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ )
+{
+ SERIAL_DEV *SerialDevice;
+ SERIAL_PORT_MCR Mcr;
+ EFI_TPL Tpl;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControl;
+ EFI_STATUS Status;
+
+ //
+ // The control bits that can be set are :
+ // EFI_SERIAL_DATA_TERMINAL_READY: 0x0001 // WO
+ // EFI_SERIAL_REQUEST_TO_SEND: 0x0002 // WO
+ // EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE: 0x1000 // RW
+ // EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE: 0x2000 // RW
+ // EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE: 0x4000 // RW
+ //
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+
+ //
+ // first determine the parameter is invalid
+ //
+ if ((Control & (~(EFI_SERIAL_REQUEST_TO_SEND | EFI_SERIAL_DATA_TERMINAL_READY |
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE |
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE))) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ Mcr.Bits.DtrC = 0;
+ Mcr.Bits.Rts = 0;
+ Mcr.Bits.Lme = 0;
+ SerialDevice->SoftwareLoopbackEnable = FALSE;
+ SerialDevice->HardwareFlowControl = FALSE;
+
+ if ((Control & EFI_SERIAL_DATA_TERMINAL_READY) == EFI_SERIAL_DATA_TERMINAL_READY) {
+ Mcr.Bits.DtrC = 1;
+ }
+
+ if ((Control & EFI_SERIAL_REQUEST_TO_SEND) == EFI_SERIAL_REQUEST_TO_SEND) {
+ Mcr.Bits.Rts = 1;
+ }
+
+ if ((Control & EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) == EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE) {
+ Mcr.Bits.Lme = 1;
+ }
+
+ if ((Control & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) == EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) {
+ SerialDevice->HardwareFlowControl = TRUE;
+ }
+
+ WRITE_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Mcr.Data);
+
+ if ((Control & EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) == EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE) {
+ SerialDevice->SoftwareLoopbackEnable = TRUE;
+ }
+
+ Status = EFI_SUCCESS;
+ if (SerialDevice->Handle != NULL) {
+ FlowControl = (UART_FLOW_CONTROL_DEVICE_PATH *) (
+ (UINTN) SerialDevice->DevicePath
+ + GetDevicePathSize (SerialDevice->ParentDevicePath)
+ - END_DEVICE_PATH_LENGTH
+ + sizeof (UART_DEVICE_PATH)
+ );
+ if (IsUartFlowControlNode (FlowControl) &&
+ ((ReadUnaligned32 (&FlowControl->FlowControlMap) == UART_FLOW_CONTROL_HARDWARE) ^ SerialDevice->HardwareFlowControl)) {
+ //
+ // Flow Control setting is changed, need to reinstall device path protocol
+ //
+ WriteUnaligned32 (&FlowControl->FlowControlMap, SerialDevice->HardwareFlowControl ? UART_FLOW_CONTROL_HARDWARE : 0);
+ Status = gBS->ReinstallProtocolInterface (
+ SerialDevice->Handle,
+ &gEfiDevicePathProtocolGuid,
+ SerialDevice->DevicePath,
+ SerialDevice->DevicePath
+ );
+ }
+ }
+
+ gBS->RestoreTPL (Tpl);
+
+ return Status;
+}
+
+/**
+ Get ControlBits.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param Control Control signals of the serial device
+
+ @retval EFI_SUCCESS Get Control signals successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ )
+{
+ SERIAL_DEV *SerialDevice;
+ SERIAL_PORT_MSR Msr;
+ SERIAL_PORT_MCR Mcr;
+ EFI_TPL Tpl;
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+
+ *Control = 0;
+
+ //
+ // Read the Modem Status Register
+ //
+ Msr.Data = READ_MSR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+
+ if (Msr.Bits.Cts == 1) {
+ *Control |= EFI_SERIAL_CLEAR_TO_SEND;
+ }
+
+ if (Msr.Bits.Dsr == 1) {
+ *Control |= EFI_SERIAL_DATA_SET_READY;
+ }
+
+ if (Msr.Bits.Ri == 1) {
+ *Control |= EFI_SERIAL_RING_INDICATE;
+ }
+
+ if (Msr.Bits.Dcd == 1) {
+ *Control |= EFI_SERIAL_CARRIER_DETECT;
+ }
+ //
+ // Read the Modem Control Register
+ //
+ Mcr.Data = READ_MCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+
+ if (Mcr.Bits.DtrC == 1) {
+ *Control |= EFI_SERIAL_DATA_TERMINAL_READY;
+ }
+
+ if (Mcr.Bits.Rts == 1) {
+ *Control |= EFI_SERIAL_REQUEST_TO_SEND;
+ }
+
+ if (Mcr.Bits.Lme == 1) {
+ *Control |= EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE;
+ }
+
+ if (SerialDevice->HardwareFlowControl) {
+ *Control |= EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE;
+ }
+ //
+ // See if the Transmit FIFO is empty
+ //
+ IsaSerialReceiveTransmit (SerialDevice);
+
+ if (IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
+ *Control |= EFI_SERIAL_OUTPUT_BUFFER_EMPTY;
+ }
+ //
+ // See if the Receive FIFO is empty.
+ //
+ IsaSerialReceiveTransmit (SerialDevice);
+
+ if (IsaSerialFifoEmpty (&SerialDevice->Receive)) {
+ *Control |= EFI_SERIAL_INPUT_BUFFER_EMPTY;
+ }
+
+ if (SerialDevice->SoftwareLoopbackEnable) {
+ *Control |= EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE;
+ }
+
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BufferSize On input the size of Buffer, on output the amount of
+ data actually written
+ @param Buffer The buffer of data to write
+
+ @retval EFI_SUCCESS The data were written successfully
+ @retval EFI_DEVICE_ERROR The device reported an error
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ )
+{
+ SERIAL_DEV *SerialDevice;
+ UINT8 *CharBuffer;
+ UINT32 Index;
+ UINTN Elapsed;
+ UINTN ActualWrite;
+ EFI_TPL Tpl;
+ UINTN Timeout;
+ UINTN BitsPerCharacter;
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+ Elapsed = 0;
+ ActualWrite = 0;
+
+ if (*BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (Buffer == NULL) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_OUTPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->DevicePath
+ );
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ CharBuffer = (UINT8 *) Buffer;
+
+ //
+ // Compute the number of bits in a single character. This is a start bit,
+ // followed by the number of data bits, followed by the number of stop bits.
+ // The number of stop bits is specified by an enumeration that includes
+ // support for 1.5 stop bits. Treat 1.5 stop bits as 2 stop bits.
+ //
+ BitsPerCharacter =
+ 1 +
+ This->Mode->DataBits +
+ ((This->Mode->StopBits == TwoStopBits) ? 2 : This->Mode->StopBits);
+
+ //
+ // Compute the timeout in microseconds to wait for a single byte to be
+ // transmitted. The Mode structure contans a Timeout field that is the
+ // maximum time to transmit or receive a character. However, many UARTs
+ // have a FIFO for transmits, so the time required to add one new character
+ // to the transmit FIFO may be the time required to flush a full FIFO. If
+ // the Timeout in the Mode structure is smaller than the time required to
+ // flush a full FIFO at the current baud rate, then use a timeout value that
+ // is required to flush a full transmit FIFO.
+ //
+ Timeout = MAX (
+ This->Mode->Timeout,
+ (UINTN)DivU64x64Remainder (
+ BitsPerCharacter * (SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH + 1) * 1000000,
+ This->Mode->BaudRate,
+ NULL
+ )
+ );
+
+ for (Index = 0; Index < *BufferSize; Index++) {
+ IsaSerialFifoAdd (&SerialDevice->Transmit, CharBuffer[Index]);
+
+ while (IsaSerialReceiveTransmit (SerialDevice) != EFI_SUCCESS || !IsaSerialFifoEmpty (&SerialDevice->Transmit)) {
+ //
+ // Unsuccessful write so check if timeout has expired, if not,
+ // stall for a bit, increment time elapsed, and try again
+ //
+ if (Elapsed >= Timeout) {
+ *BufferSize = ActualWrite;
+ gBS->RestoreTPL (Tpl);
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);
+
+ Elapsed += TIMEOUT_STALL_INTERVAL;
+ }
+
+ ActualWrite++;
+ //
+ // Successful write so reset timeout
+ //
+ Elapsed = 0;
+ }
+
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer
+ @param Buffer The buffer to return the data into
+
+ @retval EFI_SUCCESS The data were read successfully
+ @retval EFI_DEVICE_ERROR The device reported an error
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ SERIAL_DEV *SerialDevice;
+ UINT32 Index;
+ UINT8 *CharBuffer;
+ UINTN Elapsed;
+ EFI_STATUS Status;
+ EFI_TPL Tpl;
+
+ SerialDevice = SERIAL_DEV_FROM_THIS (This);
+ Elapsed = 0;
+
+ if (*BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Tpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Status = IsaSerialReceiveTransmit (SerialDevice);
+
+ if (EFI_ERROR (Status)) {
+ *BufferSize = 0;
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE,
+ EFI_P_EC_INPUT_ERROR | EFI_PERIPHERAL_SERIAL_PORT,
+ SerialDevice->DevicePath
+ );
+
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ CharBuffer = (UINT8 *) Buffer;
+ for (Index = 0; Index < *BufferSize; Index++) {
+ while (IsaSerialFifoRemove (&SerialDevice->Receive, &(CharBuffer[Index])) != EFI_SUCCESS) {
+ //
+ // Unsuccessful read so check if timeout has expired, if not,
+ // stall for a bit, increment time elapsed, and try again
+ // Need this time out to get conspliter to work.
+ //
+ if (Elapsed >= This->Mode->Timeout) {
+ *BufferSize = Index;
+ gBS->RestoreTPL (Tpl);
+ return EFI_TIMEOUT;
+ }
+
+ gBS->Stall (TIMEOUT_STALL_INTERVAL);
+ Elapsed += TIMEOUT_STALL_INTERVAL;
+
+ Status = IsaSerialReceiveTransmit (SerialDevice);
+ if (Status == EFI_DEVICE_ERROR) {
+ *BufferSize = Index;
+ gBS->RestoreTPL (Tpl);
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Successful read so reset timeout
+ //
+ Elapsed = 0;
+ }
+
+ IsaSerialReceiveTransmit (SerialDevice);
+
+ gBS->RestoreTPL (Tpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Use scratchpad register to test if this serial port is present.
+
+ @param SerialDevice Pointer to serial device structure
+
+ @return if this serial port is present
+**/
+BOOLEAN
+IsaSerialPortPresent (
+ IN SERIAL_DEV *SerialDevice
+ )
+
+{
+ UINT8 Temp;
+ BOOLEAN Status;
+
+ Status = TRUE;
+
+ //
+ // Save SCR reg
+ //
+ Temp = READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress);
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0xAA);
+
+ if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0xAA) {
+ Status = FALSE;
+ }
+
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, 0x55);
+
+ if (READ_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress) != 0x55) {
+ Status = FALSE;
+ }
+ //
+ // Restore SCR
+ //
+ WRITE_SCR (SerialDevice->IsaIo, SerialDevice->BaseAddress, Temp);
+ return Status;
+}
+
+/**
+ Use IsaIo protocol to read serial port.
+
+ @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
+ @param BaseAddress Serial port register group base address
+ @param Offset Offset in register group
+
+ @return Data read from serial port
+
+**/
+UINT8
+IsaSerialReadPort (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT16 BaseAddress,
+ IN UINT32 Offset
+ )
+{
+ UINT8 Data;
+
+ //
+ // Use IsaIo to access IO
+ //
+ IsaIo->Io.Read (
+ IsaIo,
+ EfiIsaIoWidthUint8,
+ BaseAddress + Offset,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+/**
+ Use IsaIo protocol to write serial port.
+
+ @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
+ @param BaseAddress Serial port register group base address
+ @param Offset Offset in register group
+ @param Data data which is to be written to some serial port register
+
+**/
+VOID
+IsaSerialWritePort (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT16 BaseAddress,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ )
+{
+ //
+ // Use IsaIo to access IO
+ //
+ IsaIo->Io.Write (
+ IsaIo,
+ EfiIsaIoWidthUint8,
+ BaseAddress + Offset,
+ 1,
+ &Data
+ );
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.h b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.h
new file mode 100644
index 0000000000..9d50ca9e27
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/Serial.h
@@ -0,0 +1,842 @@
+/** @file
+ Include for Serial Driver
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _SERIAL_H_
+#define _SERIAL_H_
+
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/IsaIo.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gSerialControllerDriver;
+extern EFI_COMPONENT_NAME_PROTOCOL gIsaSerialComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gIsaSerialComponentName2;
+
+//
+// Internal Data Structures
+//
+#define SERIAL_DEV_SIGNATURE SIGNATURE_32 ('s', 'e', 'r', 'd')
+#define SERIAL_MAX_BUFFER_SIZE 16
+#define TIMEOUT_STALL_INTERVAL 10
+
+//
+// Name: SERIAL_DEV_FIFO
+// Purpose: To define Receive FIFO and Transmit FIFO
+// Context: Used by serial data transmit and receive
+// Fields:
+// First UINT32: The index of the first data in array Data[]
+// Last UINT32: The index, which you can put a new data into array Data[]
+// Surplus UINT32: Identify how many data you can put into array Data[]
+// Data[] UINT8 : An array, which used to store data
+//
+typedef struct {
+ UINT32 First;
+ UINT32 Last;
+ UINT32 Surplus;
+ UINT8 Data[SERIAL_MAX_BUFFER_SIZE];
+} SERIAL_DEV_FIFO;
+
+typedef enum {
+ Uart8250 = 0,
+ Uart16450 = 1,
+ Uart16550 = 2,
+ Uart16550A= 3
+} EFI_UART_TYPE;
+
+//
+// Name: SERIAL_DEV
+// Purpose: To provide device specific information
+// Context:
+// Fields:
+// Signature UINTN: The identity of the serial device
+// SerialIo SERIAL_IO_PROTOCOL: Serial I/O protocol interface
+// SerialMode SERIAL_IO_MODE:
+// DevicePath EFI_DEVICE_PATH_PROTOCOL *: Device path of the serial device
+// Handle EFI_HANDLE: The handle instance attached to serial device
+// BaseAddress UINT16: The base address of specific serial device
+// Receive SERIAL_DEV_FIFO: The FIFO used to store data,
+// which is received by UART
+// Transmit SERIAL_DEV_FIFO: The FIFO used to store data,
+// which you want to transmit by UART
+// SoftwareLoopbackEnable BOOLEAN:
+// Type EFI_UART_TYPE: Specify the UART type of certain serial device
+//
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_SERIAL_IO_PROTOCOL SerialIo;
+ EFI_SERIAL_IO_MODE SerialMode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ UART_DEVICE_PATH UartDevicePath;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ UINT16 BaseAddress;
+ SERIAL_DEV_FIFO Receive;
+ SERIAL_DEV_FIFO Transmit;
+ BOOLEAN SoftwareLoopbackEnable;
+ BOOLEAN HardwareFlowControl;
+ EFI_UART_TYPE Type;
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+} SERIAL_DEV;
+
+#define SERIAL_DEV_FROM_THIS(a) CR (a, SERIAL_DEV, SerialIo, SERIAL_DEV_SIGNATURE)
+
+//
+// Serial Driver Defaults
+//
+#define SERIAL_PORT_DEFAULT_RECEIVE_FIFO_DEPTH 1
+#define SERIAL_PORT_DEFAULT_TIMEOUT 1000000
+#define SERIAL_PORT_SUPPORT_CONTROL_MASK (EFI_SERIAL_CLEAR_TO_SEND | \
+ EFI_SERIAL_DATA_SET_READY | \
+ EFI_SERIAL_RING_INDICATE | \
+ EFI_SERIAL_CARRIER_DETECT | \
+ EFI_SERIAL_REQUEST_TO_SEND | \
+ EFI_SERIAL_DATA_TERMINAL_READY | \
+ EFI_SERIAL_HARDWARE_LOOPBACK_ENABLE | \
+ EFI_SERIAL_SOFTWARE_LOOPBACK_ENABLE | \
+ EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE | \
+ EFI_SERIAL_OUTPUT_BUFFER_EMPTY | \
+ EFI_SERIAL_INPUT_BUFFER_EMPTY)
+
+//
+// 115200 baud with rounding errors
+//
+#define SERIAL_PORT_MAX_BAUD_RATE 115400
+#define SERIAL_PORT_MIN_BAUD_RATE 50
+
+#define SERIAL_PORT_MAX_RECEIVE_FIFO_DEPTH 16
+#define SERIAL_PORT_MIN_TIMEOUT 1 // 1 uS
+#define SERIAL_PORT_MAX_TIMEOUT 100000000 // 100 seconds
+//
+// UART Registers
+//
+#define SERIAL_REGISTER_THR 0 // WO Transmit Holding Register
+#define SERIAL_REGISTER_RBR 0 // RO Receive Buffer Register
+#define SERIAL_REGISTER_DLL 0 // R/W Divisor Latch LSB
+#define SERIAL_REGISTER_DLM 1 // R/W Divisor Latch MSB
+#define SERIAL_REGISTER_IER 1 // R/W Interrupt Enable Register
+#define SERIAL_REGISTER_IIR 2 // RO Interrupt Identification Register
+#define SERIAL_REGISTER_FCR 2 // WO FIFO Cotrol Register
+#define SERIAL_REGISTER_LCR 3 // R/W Line Control Register
+#define SERIAL_REGISTER_MCR 4 // R/W Modem Control Register
+#define SERIAL_REGISTER_LSR 5 // R/W Line Status Register
+#define SERIAL_REGISTER_MSR 6 // R/W Modem Status Register
+#define SERIAL_REGISTER_SCR 7 // R/W Scratch Pad Register
+#pragma pack(1)
+//
+// Name: SERIAL_PORT_IER_BITS
+// Purpose: Define each bit in Interrupt Enable Register
+// Context:
+// Fields:
+// Ravie Bit0: Receiver Data Available Interrupt Enable
+// Theie Bit1: Transmistter Holding Register Empty Interrupt Enable
+// Rie Bit2: Receiver Interrupt Enable
+// Mie Bit3: Modem Interrupt Enable
+// Reserved Bit4-Bit7: Reserved
+//
+typedef struct {
+ UINT8 Ravie : 1;
+ UINT8 Theie : 1;
+ UINT8 Rie : 1;
+ UINT8 Mie : 1;
+ UINT8 Reserved : 4;
+} SERIAL_PORT_IER_BITS;
+
+//
+// Name: SERIAL_PORT_IER
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_IER_BITS: Bits of the IER
+// Data UINT8: the value of the IER
+//
+typedef union {
+ SERIAL_PORT_IER_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_IER;
+
+//
+// Name: SERIAL_PORT_FCR_BITS
+// Purpose: Define each bit in FIFO Control Register
+// Context:
+// Fields:
+// TrFIFOE Bit0: Transmit and Receive FIFO Enable
+// ResetRF Bit1: Reset Reciever FIFO
+// ResetTF Bit2: Reset Transmistter FIFO
+// Dms Bit3: DMA Mode Select
+// Reserved Bit4-Bit5: Reserved
+// Rtb Bit6-Bit7: Receive Trigger Bits
+//
+typedef struct {
+ UINT8 TrFIFOE : 1;
+ UINT8 ResetRF : 1;
+ UINT8 ResetTF : 1;
+ UINT8 Dms : 1;
+ UINT8 Reserved : 2;
+ UINT8 Rtb : 2;
+} SERIAL_PORT_FCR_BITS;
+
+//
+// Name: SERIAL_PORT_FCR
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_FCR_BITS: Bits of the FCR
+// Data UINT8: the value of the FCR
+//
+typedef union {
+ SERIAL_PORT_FCR_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_FCR;
+
+//
+// Name: SERIAL_PORT_LCR_BITS
+// Purpose: Define each bit in Line Control Register
+// Context:
+// Fields:
+// SerialDB Bit0-Bit1: Number of Serial Data Bits
+// StopB Bit2: Number of Stop Bits
+// ParEn Bit3: Parity Enable
+// EvenPar Bit4: Even Parity Select
+// SticPar Bit5: Sticky Parity
+// BrCon Bit6: Break Control
+// DLab Bit7: Divisor Latch Access Bit
+//
+typedef struct {
+ UINT8 SerialDB : 2;
+ UINT8 StopB : 1;
+ UINT8 ParEn : 1;
+ UINT8 EvenPar : 1;
+ UINT8 SticPar : 1;
+ UINT8 BrCon : 1;
+ UINT8 DLab : 1;
+} SERIAL_PORT_LCR_BITS;
+
+//
+// Name: SERIAL_PORT_LCR
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_LCR_BITS: Bits of the LCR
+// Data UINT8: the value of the LCR
+//
+typedef union {
+ SERIAL_PORT_LCR_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_LCR;
+
+//
+// Name: SERIAL_PORT_MCR_BITS
+// Purpose: Define each bit in Modem Control Register
+// Context:
+// Fields:
+// DtrC Bit0: Data Terminal Ready Control
+// Rts Bit1: Request To Send Control
+// Out1 Bit2: Output1
+// Out2 Bit3: Output2, used to disable interrupt
+// Lme; Bit4: Loopback Mode Enable
+// Reserved Bit5-Bit7: Reserved
+//
+typedef struct {
+ UINT8 DtrC : 1;
+ UINT8 Rts : 1;
+ UINT8 Out1 : 1;
+ UINT8 Out2 : 1;
+ UINT8 Lme : 1;
+ UINT8 Reserved : 3;
+} SERIAL_PORT_MCR_BITS;
+
+//
+// Name: SERIAL_PORT_MCR
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_MCR_BITS: Bits of the MCR
+// Data UINT8: the value of the MCR
+//
+typedef union {
+ SERIAL_PORT_MCR_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_MCR;
+
+//
+// Name: SERIAL_PORT_LSR_BITS
+// Purpose: Define each bit in Line Status Register
+// Context:
+// Fields:
+// Dr Bit0: Receiver Data Ready Status
+// Oe Bit1: Overrun Error Status
+// Pe Bit2: Parity Error Status
+// Fe Bit3: Framing Error Status
+// Bi Bit4: Break Interrupt Status
+// Thre Bit5: Transmistter Holding Register Status
+// Temt Bit6: Transmitter Empty Status
+// FIFOe Bit7: FIFO Error Status
+//
+typedef struct {
+ UINT8 Dr : 1;
+ UINT8 Oe : 1;
+ UINT8 Pe : 1;
+ UINT8 Fe : 1;
+ UINT8 Bi : 1;
+ UINT8 Thre : 1;
+ UINT8 Temt : 1;
+ UINT8 FIFOe : 1;
+} SERIAL_PORT_LSR_BITS;
+
+//
+// Name: SERIAL_PORT_LSR
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_LSR_BITS: Bits of the LSR
+// Data UINT8: the value of the LSR
+//
+typedef union {
+ SERIAL_PORT_LSR_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_LSR;
+
+//
+// Name: SERIAL_PORT_MSR_BITS
+// Purpose: Define each bit in Modem Status Register
+// Context:
+// Fields:
+// DeltaCTS Bit0: Delta Clear To Send Status
+// DeltaDSR Bit1: Delta Data Set Ready Status
+// TrailingEdgeRI Bit2: Trailing Edge of Ring Indicator Status
+// DeltaDCD Bit3: Delta Data Carrier Detect Status
+// Cts Bit4: Clear To Send Status
+// Dsr Bit5: Data Set Ready Status
+// Ri Bit6: Ring Indicator Status
+// Dcd Bit7: Data Carrier Detect Status
+//
+typedef struct {
+ UINT8 DeltaCTS : 1;
+ UINT8 DeltaDSR : 1;
+ UINT8 TrailingEdgeRI : 1;
+ UINT8 DeltaDCD : 1;
+ UINT8 Cts : 1;
+ UINT8 Dsr : 1;
+ UINT8 Ri : 1;
+ UINT8 Dcd : 1;
+} SERIAL_PORT_MSR_BITS;
+
+//
+// Name: SERIAL_PORT_MSR
+// Purpose:
+// Context:
+// Fields:
+// Bits SERIAL_PORT_MSR_BITS: Bits of the MSR
+// Data UINT8: the value of the MSR
+//
+typedef union {
+ SERIAL_PORT_MSR_BITS Bits;
+ UINT8 Data;
+} SERIAL_PORT_MSR;
+
+#pragma pack()
+//
+// Define serial register I/O macros
+//
+#define READ_RBR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_RBR)
+#define READ_DLL(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_DLL)
+#define READ_DLM(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_DLM)
+#define READ_IER(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_IER)
+#define READ_IIR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_IIR)
+#define READ_LCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_LCR)
+#define READ_MCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_MCR)
+#define READ_LSR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_LSR)
+#define READ_MSR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_MSR)
+#define READ_SCR(IO, B) IsaSerialReadPort (IO, B, SERIAL_REGISTER_SCR)
+
+#define WRITE_THR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_THR, D)
+#define WRITE_DLL(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_DLL, D)
+#define WRITE_DLM(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_DLM, D)
+#define WRITE_IER(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_IER, D)
+#define WRITE_FCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_FCR, D)
+#define WRITE_LCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_LCR, D)
+#define WRITE_MCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_MCR, D)
+#define WRITE_LSR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_LSR, D)
+#define WRITE_MSR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_MSR, D)
+#define WRITE_SCR(IO, B, D) IsaSerialWritePort (IO, B, SERIAL_REGISTER_SCR, D)
+
+//
+// Prototypes
+// Driver model protocol interface
+//
+/**
+ Check to see if this driver supports the given controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @return EFI_SUCCESS This driver can support the given controller
+
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start to management the controller passed in
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @return EFI_SUCCESS Driver is started successfully
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Disconnect this driver with the controller, uninstall related protocol instance
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren Number of child device.
+ @param ChildHandleBuffer A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Operation successfully
+ @retval EFI_DEVICE_ERROR Cannot stop the driver successfully
+
+**/
+EFI_STATUS
+EFIAPI
+SerialControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Serial I/O Protocol Interface
+//
+/**
+ Reset serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Reset successfully
+ @retval EFI_DEVICE_ERROR Failed to reset
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialReset (
+ IN EFI_SERIAL_IO_PROTOCOL *This
+ );
+
+/**
+ Set new attributes to a serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BaudRate The baudrate of the serial device
+ @param ReceiveFifoDepth The depth of receive FIFO buffer
+ @param Timeout The request timeout for a single char
+ @param Parity The type of parity used in serial device
+ @param DataBits Number of databits used in serial device
+ @param StopBits Number of stopbits used in serial device
+
+ @retval EFI_SUCCESS The new attributes were set
+ @retval EFI_INVALID_PARAMETERS One or more attributes have an unsupported value
+ @retval EFI_UNSUPPORTED Data Bits can not set to 5 or 6
+ @retval EFI_DEVICE_ERROR The serial device is not functioning correctly (no return)
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialSetAttributes (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT64 BaudRate,
+ IN UINT32 ReceiveFifoDepth,
+ IN UINT32 Timeout,
+ IN EFI_PARITY_TYPE Parity,
+ IN UINT8 DataBits,
+ IN EFI_STOP_BITS_TYPE StopBits
+ );
+
+/**
+ Set Control Bits.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param Control Control bits that can be settable
+
+ @retval EFI_SUCCESS New Control bits were set successfully
+ @retval EFI_UNSUPPORTED The Control bits wanted to set are not supported
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialSetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN UINT32 Control
+ );
+
+/**
+ Get ControlBits.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param Control Control signals of the serial device
+
+ @retval EFI_SUCCESS Get Control signals successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialGetControl (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ OUT UINT32 *Control
+ );
+
+/**
+ Write the specified number of bytes to serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BufferSize On input the size of Buffer, on output the amount of
+ data actually written
+ @param Buffer The buffer of data to write
+
+ @retval EFI_SUCCESS The data were written successfully
+ @retval EFI_DEVICE_ERROR The device reported an error
+ @retval EFI_TIMEOUT The write operation was stopped due to timeout
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialWrite (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Read the specified number of bytes from serial device.
+
+ @param This Pointer to EFI_SERIAL_IO_PROTOCOL
+ @param BufferSize On input the size of Buffer, on output the amount of
+ data returned in buffer
+ @param Buffer The buffer to return the data into
+
+ @retval EFI_SUCCESS The data were read successfully
+ @retval EFI_DEVICE_ERROR The device reported an error
+ @retval EFI_TIMEOUT The read operation was stopped due to timeout
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialRead (
+ IN EFI_SERIAL_IO_PROTOCOL *This,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+//
+// Internal Functions
+//
+/**
+ Use scratchpad register to test if this serial port is present.
+
+ @param SerialDevice Pointer to serial device structure
+
+ @return if this serial port is present
+**/
+BOOLEAN
+IsaSerialPortPresent (
+ IN SERIAL_DEV *SerialDevice
+ );
+
+/**
+ Detect whether specific FIFO is full or not.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+
+ @return whether specific FIFO is full or not
+
+**/
+BOOLEAN
+IsaSerialFifoFull (
+ IN SERIAL_DEV_FIFO *Fifo
+ );
+
+/**
+ Detect whether specific FIFO is empty or not.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+
+ @return whether specific FIFO is empty or not
+
+**/
+BOOLEAN
+IsaSerialFifoEmpty (
+ IN SERIAL_DEV_FIFO *Fifo
+ );
+
+/**
+ Add data to specific FIFO.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+ @param Data the data added to FIFO
+
+ @retval EFI_SUCCESS Add data to specific FIFO successfully
+ @retval EFI_OUT_OF_RESOURCE Failed to add data because FIFO is already full
+
+**/
+EFI_STATUS
+IsaSerialFifoAdd (
+ IN SERIAL_DEV_FIFO *Fifo,
+ IN UINT8 Data
+ );
+
+/**
+ Remove data from specific FIFO.
+
+ @param Fifo A pointer to the Data Structure SERIAL_DEV_FIFO
+ @param Data the data removed from FIFO
+
+ @retval EFI_SUCCESS Remove data from specific FIFO successfully
+ @retval EFI_OUT_OF_RESOURCE Failed to remove data because FIFO is empty
+
+**/
+EFI_STATUS
+IsaSerialFifoRemove (
+ IN SERIAL_DEV_FIFO *Fifo,
+ OUT UINT8 *Data
+ );
+
+/**
+ Reads and writes all avaliable data.
+
+ @param SerialDevice The device to flush
+
+ @retval EFI_SUCCESS Data was read/written successfully.
+ @retval EFI_OUT_OF_RESOURCE Failed because software receive FIFO is full. Note, when
+ this happens, pending writes are not done.
+
+**/
+EFI_STATUS
+IsaSerialReceiveTransmit (
+ IN SERIAL_DEV *SerialDevice
+ );
+
+/**
+ Use IsaIo protocol to read serial port.
+
+ @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
+ @param BaseAddress Serial port register group base address
+ @param Offset Offset in register group
+
+ @return Data read from serial port
+
+**/
+UINT8
+IsaSerialReadPort (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT16 BaseAddress,
+ IN UINT32 Offset
+ );
+
+/**
+ Use IsaIo protocol to write serial port.
+
+ @param IsaIo Pointer to EFI_ISA_IO_PROTOCOL instance
+ @param BaseAddress Serial port register group base address
+ @param Offset Offset in register group
+ @param Data data which is to be written to some serial port register
+
+**/
+VOID
+IsaSerialWritePort (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT16 BaseAddress,
+ IN UINT32 Offset,
+ IN UINT8 Data
+ );
+
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IsaSerialComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Add the component name for the serial io device
+
+ @param SerialDevice A pointer to the SERIAL_DEV instance.
+
+ @param IsaIo A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+**/
+VOID
+AddName (
+ IN SERIAL_DEV *SerialDevice,
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c
new file mode 100644
index 0000000000..e6c739e2ba
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/ComponentName.c
@@ -0,0 +1,372 @@
+/** @file
+ Routines related Component Name protocol.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Keyboard.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2KeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2KeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPs2KeyboardComponentName = {
+ Ps2KeyboardComponentNameGetDriverName,
+ Ps2KeyboardComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPs2KeyboardComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Ps2KeyboardComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Ps2KeyboardComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPs2KeyboardDriverNameTable[] = {
+ {
+ "eng;en",
+ L"PS/2 Keyboard Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2KeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPs2KeyboardDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPs2KeyboardComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2KeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ EFI_ISA_IO_PROTOCOL *IsaIoProtocol;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIoProtocol,
+ gKeyboardControllerDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ gKeyboardControllerDriver.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &ConIn,
+ gKeyboardControllerDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ ConsoleIn->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gPs2KeyboardComponentName)
+ );
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
new file mode 100644
index 0000000000..2a20b789a7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdCtrller.c
@@ -0,0 +1,1908 @@
+/** @file
+ Routines that access 8042 keyboard controller
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Keyboard.h"
+
+struct {
+ UINT8 ScanCode; ///< follows value defined in Scan Code Set1
+ UINT16 EfiScanCode;
+ CHAR16 UnicodeChar;
+ CHAR16 ShiftUnicodeChar;
+}
+ConvertKeyboardScanCodeToEfiKey[] = {
+
+ {
+ 0x01, // Escape
+ SCAN_ESC,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x02,
+ SCAN_NULL,
+ L'1',
+ L'!'
+ },
+ {
+ 0x03,
+ SCAN_NULL,
+ L'2',
+ L'@'
+ },
+ {
+ 0x04,
+ SCAN_NULL,
+ L'3',
+ L'#'
+ },
+ {
+ 0x05,
+ SCAN_NULL,
+ L'4',
+ L'$'
+ },
+ {
+ 0x06,
+ SCAN_NULL,
+ L'5',
+ L'%'
+ },
+ {
+ 0x07,
+ SCAN_NULL,
+ L'6',
+ L'^'
+ },
+ {
+ 0x08,
+ SCAN_NULL,
+ L'7',
+ L'&'
+ },
+ {
+ 0x09,
+ SCAN_NULL,
+ L'8',
+ L'*'
+ },
+ {
+ 0x0A,
+ SCAN_NULL,
+ L'9',
+ L'('
+ },
+ {
+ 0x0B,
+ SCAN_NULL,
+ L'0',
+ L')'
+ },
+ {
+ 0x0C,
+ SCAN_NULL,
+ L'-',
+ L'_'
+ },
+ {
+ 0x0D,
+ SCAN_NULL,
+ L'=',
+ L'+'
+ },
+ {
+ 0x0E, // BackSpace
+ SCAN_NULL,
+ 0x0008,
+ 0x0008
+ },
+ {
+ 0x0F, // Tab
+ SCAN_NULL,
+ 0x0009,
+ 0x0009
+ },
+ {
+ 0x10,
+ SCAN_NULL,
+ L'q',
+ L'Q'
+ },
+ {
+ 0x11,
+ SCAN_NULL,
+ L'w',
+ L'W'
+ },
+ {
+ 0x12,
+ SCAN_NULL,
+ L'e',
+ L'E'
+ },
+ {
+ 0x13,
+ SCAN_NULL,
+ L'r',
+ L'R'
+ },
+ {
+ 0x14,
+ SCAN_NULL,
+ L't',
+ L'T'
+ },
+ {
+ 0x15,
+ SCAN_NULL,
+ L'y',
+ L'Y'
+ },
+ {
+ 0x16,
+ SCAN_NULL,
+ L'u',
+ L'U'
+ },
+ {
+ 0x17,
+ SCAN_NULL,
+ L'i',
+ L'I'
+ },
+ {
+ 0x18,
+ SCAN_NULL,
+ L'o',
+ L'O'
+ },
+ {
+ 0x19,
+ SCAN_NULL,
+ L'p',
+ L'P'
+ },
+ {
+ 0x1a,
+ SCAN_NULL,
+ L'[',
+ L'{'
+ },
+ {
+ 0x1b,
+ SCAN_NULL,
+ L']',
+ L'}'
+ },
+ {
+ 0x1c, // Enter
+ SCAN_NULL,
+ 0x000d,
+ 0x000d
+ },
+ {
+ 0x1d,
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x1e,
+ SCAN_NULL,
+ L'a',
+ L'A'
+ },
+ {
+ 0x1f,
+ SCAN_NULL,
+ L's',
+ L'S'
+ },
+ {
+ 0x20,
+ SCAN_NULL,
+ L'd',
+ L'D'
+ },
+ {
+ 0x21,
+ SCAN_NULL,
+ L'f',
+ L'F'
+ },
+ {
+ 0x22,
+ SCAN_NULL,
+ L'g',
+ L'G'
+ },
+ {
+ 0x23,
+ SCAN_NULL,
+ L'h',
+ L'H'
+ },
+ {
+ 0x24,
+ SCAN_NULL,
+ L'j',
+ L'J'
+ },
+ {
+ 0x25,
+ SCAN_NULL,
+ L'k',
+ L'K'
+ },
+ {
+ 0x26,
+ SCAN_NULL,
+ L'l',
+ L'L'
+ },
+ {
+ 0x27,
+ SCAN_NULL,
+ L';',
+ L':'
+ },
+ {
+ 0x28,
+ SCAN_NULL,
+ L'\'',
+ L'"'
+ },
+ {
+ 0x29,
+ SCAN_NULL,
+ L'`',
+ L'~'
+ },
+ {
+ 0x2a, // Left Shift
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x2b,
+ SCAN_NULL,
+ L'\\',
+ L'|'
+ },
+ {
+ 0x2c,
+ SCAN_NULL,
+ L'z',
+ L'Z'
+ },
+ {
+ 0x2d,
+ SCAN_NULL,
+ L'x',
+ L'X'
+ },
+ {
+ 0x2e,
+ SCAN_NULL,
+ L'c',
+ L'C'
+ },
+ {
+ 0x2f,
+ SCAN_NULL,
+ L'v',
+ L'V'
+ },
+ {
+ 0x30,
+ SCAN_NULL,
+ L'b',
+ L'B'
+ },
+ {
+ 0x31,
+ SCAN_NULL,
+ L'n',
+ L'N'
+ },
+ {
+ 0x32,
+ SCAN_NULL,
+ L'm',
+ L'M'
+ },
+ {
+ 0x33,
+ SCAN_NULL,
+ L',',
+ L'<'
+ },
+ {
+ 0x34,
+ SCAN_NULL,
+ L'.',
+ L'>'
+ },
+ {
+ 0x35,
+ SCAN_NULL,
+ L'/',
+ L'?'
+ },
+ {
+ 0x36, //Right Shift
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x37, // Numeric Keypad *
+ SCAN_NULL,
+ L'*',
+ L'*'
+ },
+ {
+ 0x38, //Left Alt/Extended Right Alt
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x39,
+ SCAN_NULL,
+ L' ',
+ L' '
+ },
+ {
+ 0x3A, //CapsLock
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x3B,
+ SCAN_F1,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x3C,
+ SCAN_F2,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x3D,
+ SCAN_F3,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x3E,
+ SCAN_F4,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x3F,
+ SCAN_F5,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x40,
+ SCAN_F6,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x41,
+ SCAN_F7,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x42,
+ SCAN_F8,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x43,
+ SCAN_F9,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x44,
+ SCAN_F10,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x45, // NumLock
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x46, // ScrollLock
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x47,
+ SCAN_HOME,
+ L'7',
+ L'7'
+ },
+ {
+ 0x48,
+ SCAN_UP,
+ L'8',
+ L'8'
+ },
+ {
+ 0x49,
+ SCAN_PAGE_UP,
+ L'9',
+ L'9'
+ },
+ {
+ 0x4a,
+ SCAN_NULL,
+ L'-',
+ L'-'
+ },
+ {
+ 0x4b,
+ SCAN_LEFT,
+ L'4',
+ L'4'
+ },
+ {
+ 0x4c, // Numeric Keypad 5
+ SCAN_NULL,
+ L'5',
+ L'5'
+ },
+ {
+ 0x4d,
+ SCAN_RIGHT,
+ L'6',
+ L'6'
+ },
+ {
+ 0x4e,
+ SCAN_NULL,
+ L'+',
+ L'+'
+ },
+ {
+ 0x4f,
+ SCAN_END,
+ L'1',
+ L'1'
+ },
+ {
+ 0x50,
+ SCAN_DOWN,
+ L'2',
+ L'2'
+ },
+ {
+ 0x51,
+ SCAN_PAGE_DOWN,
+ L'3',
+ L'3'
+ },
+ {
+ 0x52,
+ SCAN_INSERT,
+ L'0',
+ L'0'
+ },
+ {
+ 0x53,
+ SCAN_DELETE,
+ L'.',
+ L'.'
+ },
+ {
+ 0x57,
+ SCAN_F11,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x58,
+ SCAN_F12,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x5B, //Left LOGO
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x5C, //Right LOGO
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ 0x5D, //Menu key
+ SCAN_NULL,
+ 0x0000,
+ 0x0000
+ },
+ {
+ TABLE_END,
+ TABLE_END,
+ SCAN_NULL,
+ SCAN_NULL
+ },
+};
+
+//
+// The WaitForValue time out
+//
+UINTN mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
+
+BOOLEAN mEnableMouseInterface;
+
+
+
+/**
+ Return the count of scancode in the queue.
+
+ @param Queue Pointer to instance of SCAN_CODE_QUEUE.
+
+ @return Count of the scancode.
+**/
+UINTN
+GetScancodeBufCount (
+ IN SCAN_CODE_QUEUE *Queue
+ )
+{
+ if (Queue->Head <= Queue->Tail) {
+ return Queue->Tail - Queue->Head;
+ } else {
+ return Queue->Tail + KEYBOARD_SCAN_CODE_MAX_COUNT - Queue->Head;
+ }
+}
+
+/**
+ Read several bytes from the scancode buffer without removing them.
+ This function is called to see if there are enough bytes of scancode
+ representing a single key.
+
+ @param Queue Pointer to instance of SCAN_CODE_QUEUE.
+ @param Count Number of bytes to be read
+ @param Buf Store the results
+
+ @retval EFI_SUCCESS success to scan the keyboard code
+ @retval EFI_NOT_READY invalid parameter
+**/
+EFI_STATUS
+GetScancodeBufHead (
+ IN SCAN_CODE_QUEUE *Queue,
+ IN UINTN Count,
+ OUT UINT8 *Buf
+ )
+{
+ UINTN Index;
+ UINTN Pos;
+
+ //
+ // check the valid range of parameter 'Count'
+ //
+ if (GetScancodeBufCount (Queue) < Count) {
+ return EFI_NOT_READY;
+ }
+ //
+ // retrieve the values
+ //
+ for (Index = 0, Pos = Queue->Head; Index < Count; Index++, Pos = (Pos + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT) {
+ Buf[Index] = Queue->Buffer[Pos];
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Read & remove several bytes from the scancode buffer.
+ This function is usually called after GetScancodeBufHead()
+
+ @param Queue Pointer to instance of SCAN_CODE_QUEUE.
+ @param Count Number of bytes to be read
+ @param Buf Store the results
+
+ @retval EFI_SUCCESS success to scan the keyboard code
+ @retval EFI_NOT_READY invalid parameter
+**/
+EFI_STATUS
+PopScancodeBufHead (
+ IN SCAN_CODE_QUEUE *Queue,
+ IN UINTN Count,
+ OUT UINT8 *Buf OPTIONAL
+ )
+{
+ UINTN Index;
+
+ //
+ // Check the valid range of parameter 'Count'
+ //
+ if (GetScancodeBufCount (Queue) < Count) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Retrieve and remove the values
+ //
+ for (Index = 0; Index < Count; Index++, Queue->Head = (Queue->Head + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT) {
+ if (Buf != NULL) {
+ Buf[Index] = Queue->Buffer[Queue->Head];
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Push one byte to the scancode buffer.
+
+ @param Queue Pointer to instance of SCAN_CODE_QUEUE.
+ @param Scancode The byte to push.
+**/
+VOID
+PushScancodeBufTail (
+ IN SCAN_CODE_QUEUE *Queue,
+ IN UINT8 Scancode
+ )
+{
+ if (GetScancodeBufCount (Queue) == KEYBOARD_SCAN_CODE_MAX_COUNT - 1) {
+ PopScancodeBufHead (Queue, 1, NULL);
+ }
+
+ Queue->Buffer[Queue->Tail] = Scancode;
+ Queue->Tail = (Queue->Tail + 1) % KEYBOARD_SCAN_CODE_MAX_COUNT;
+}
+
+/**
+ Read data register .
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @return return the value
+
+**/
+UINT8
+KeyReadDataRegister (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+
+{
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINT8 Data;
+
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ IsaIo = ConsoleIn->IsaIo;
+
+ IsaIo->Io.Read (
+ IsaIo,
+ EfiIsaIoWidthUint8,
+ ConsoleIn->DataRegisterAddress,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Write data register.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data value wanted to be written
+
+**/
+VOID
+KeyWriteDataRegister (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN UINT8 Data
+ )
+{
+ ConsoleIn->IsaIo->Io.Write (
+ ConsoleIn->IsaIo,
+ EfiIsaIoWidthUint8,
+ ConsoleIn->DataRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Read status register.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @return value in status register
+
+**/
+UINT8
+KeyReadStatusRegister (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+{
+ UINT8 Data;
+ ConsoleIn->IsaIo->Io.Read (
+ ConsoleIn->IsaIo,
+ EfiIsaIoWidthUint8,
+ ConsoleIn->StatusRegisterAddress,
+ 1,
+ &Data
+ );
+ return Data;
+}
+
+/**
+ Write command register .
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data The value wanted to be written
+
+**/
+VOID
+KeyWriteCommandRegister (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN UINT8 Data
+ )
+{
+ ConsoleIn->IsaIo->Io.Write (
+ ConsoleIn->IsaIo,
+ EfiIsaIoWidthUint8,
+ ConsoleIn->CommandRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Display error message.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param ErrMsg Unicode string of error message
+
+**/
+VOID
+KeyboardError (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN CHAR16 *ErrMsg
+ )
+{
+ ConsoleIn->KeyboardErr = TRUE;
+}
+
+/**
+ Timer event handler: read a series of scancodes from 8042
+ and put them into memory scancode buffer.
+ it read as much scancodes to either fill
+ the memory buffer or empty the keyboard buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A KEYBOARD_CONSOLE_IN_DEV pointer
+
+**/
+VOID
+EFIAPI
+KeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+
+{
+ UINT8 Data;
+ EFI_TPL OldTpl;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+
+ ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (((KEYBOARD_CONSOLE_IN_DEV *) Context)->KeyboardErr) {
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return ;
+ }
+
+ //
+ // To let KB driver support Hot plug, here should skip the 'resend' command for the case that
+ // KB is not connected to system. If KB is not connected to system, driver will find there's something
+ // error in the following code and wait for the input buffer empty, this waiting time shoulb be short enough since
+ // this is a NOTIFY TPL period function, or the system performance will degrade hardly when KB is not connected.
+ // Just skip the 'resend' process simply.
+ //
+
+ while ((KeyReadStatusRegister (ConsoleIn) & (KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT|KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA)) ==
+ KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA
+ ) {
+ //
+ // Read one byte of the scan code and store it into the memory buffer
+ //
+ Data = KeyReadDataRegister (ConsoleIn);
+ PushScancodeBufTail (&ConsoleIn->ScancodeQueue, Data);
+ }
+ KeyGetchar (ConsoleIn);
+
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Read key value .
+
+ @param ConsoleIn - Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data - Pointer to outof buffer for keeping key value
+
+ @retval EFI_TIMEOUT Status resigter time out
+ @retval EFI_SUCCESS Success to read keyboard
+
+**/
+EFI_STATUS
+KeyboardRead (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ OUT UINT8 *Data
+ )
+
+{
+ UINT32 TimeOut;
+ UINT32 RegFilled;
+
+ TimeOut = 0;
+ RegFilled = 0;
+
+ //
+ // wait till output buffer full then perform the read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if (KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) {
+ RegFilled = 1;
+ *Data = KeyReadDataRegister (ConsoleIn);
+ break;
+ }
+
+ MicroSecondDelay (30);
+ }
+
+ if (RegFilled == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ write key to keyboard
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data value wanted to be written
+
+ @retval EFI_TIMEOUT The input buffer register is full for putting new value util timeout
+ @retval EFI_SUCCESS The new value is sucess put into input buffer register.
+
+**/
+EFI_STATUS
+KeyboardWrite (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // wait for input buffer empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ MicroSecondDelay (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Write it
+ //
+ KeyWriteDataRegister (ConsoleIn, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue keyboard command.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data The buff holding the command
+
+ @retval EFI_TIMEOUT Keyboard is not ready to issuing
+ @retval EFI_SUCCESS Success to issue keyboard command
+
+**/
+EFI_STATUS
+KeyboardCommand (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // Wait For Input Buffer Empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ MicroSecondDelay (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // issue the command
+ //
+ KeyWriteCommandRegister (ConsoleIn, Data);
+
+ //
+ // Wait For Input Buffer Empty again
+ //
+ RegEmptied = 0;
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (ConsoleIn) & 0x02) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ MicroSecondDelay (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ wait for a specific value to be presented on
+ 8042 Data register by keyboard and then read it,
+ used in keyboard commands ack
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Value the value wanted to be waited.
+
+ @retval EFI_TIMEOUT Fail to get specific value in given time
+ @retval EFI_SUCCESS Success to get specific value in given time.
+
+**/
+EFI_STATUS
+KeyboardWaitForValue (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN UINT8 Value
+ )
+{
+ UINT8 Data;
+ UINT32 TimeOut;
+ UINT32 SumTimeOut;
+ UINT32 GotIt;
+
+ GotIt = 0;
+ TimeOut = 0;
+ SumTimeOut = 0;
+
+ //
+ // Make sure the initial value of 'Data' is different from 'Value'
+ //
+ Data = 0;
+ if (Data == Value) {
+ Data = 1;
+ }
+ //
+ // Read from 8042 (multiple times if needed)
+ // until the expected value appears
+ // use SumTimeOut to control the iteration
+ //
+ while (1) {
+ //
+ // Perform a read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if (KeyReadStatusRegister (ConsoleIn) & 0x01) {
+ Data = KeyReadDataRegister (ConsoleIn);
+ break;
+ }
+
+ MicroSecondDelay (30);
+ }
+
+ SumTimeOut += TimeOut;
+
+ if (Data == Value) {
+ GotIt = 1;
+ break;
+ }
+
+ if (SumTimeOut >= mWaitForValueTimeOut) {
+ break;
+ }
+ }
+ //
+ // Check results
+ //
+ if (GotIt == 1) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_TIMEOUT;
+ }
+
+}
+
+/**
+ Show keyboard status lights according to
+ indicators in ConsoleIn.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @return status of updating keyboard register
+
+**/
+EFI_STATUS
+UpdateStatusLights (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Command;
+
+ //
+ // Send keyboard command
+ //
+ Status = KeyboardWrite (ConsoleIn, 0xed);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyboardWaitForValue (ConsoleIn, 0xfa);
+
+ //
+ // Light configuration
+ //
+ Command = 0;
+ if (ConsoleIn->CapsLock) {
+ Command |= 4;
+ }
+
+ if (ConsoleIn->NumLock) {
+ Command |= 2;
+ }
+
+ if (ConsoleIn->ScrollLock) {
+ Command |= 1;
+ }
+
+ Status = KeyboardWrite (ConsoleIn, Command);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyboardWaitForValue (ConsoleIn, 0xfa);
+ return Status;
+}
+
+/**
+ Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
+
+ The function is always called in TPL_NOTIFY.
+
+ @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
+
+**/
+VOID
+KeyGetchar (
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+{
+ EFI_STATUS Status;
+ UINT16 ScanCode;
+ BOOLEAN Extend0;
+ BOOLEAN Extend1;
+ UINTN Index;
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ //
+ // 3 bytes most
+ //
+ UINT8 ScancodeArr[3];
+ UINT32 ScancodeArrPos;
+
+ //
+ // Check if there are enough bytes of scancode representing a single key
+ // available in the buffer
+ //
+ while (TRUE) {
+ Extend0 = FALSE;
+ Extend1 = FALSE;
+ ScancodeArrPos = 0;
+ Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED0) {
+ //
+ // E0 to look ahead 2 bytes
+ //
+ Extend0 = TRUE;
+ ScancodeArrPos = 1;
+ Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ } else if (ScancodeArr[ScancodeArrPos] == SCANCODE_EXTENDED1) {
+ //
+ // E1 to look ahead 3 bytes
+ //
+ Extend1 = TRUE;
+ ScancodeArrPos = 2;
+ Status = GetScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ }
+ //
+ // if we reach this position, scancodes for a key is in buffer now,pop them
+ //
+ Status = PopScancodeBufHead (&ConsoleIn->ScancodeQueue, ScancodeArrPos + 1, ScancodeArr);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // store the last available byte, this byte of scancode will be checked
+ //
+ ScanCode = ScancodeArr[ScancodeArrPos];
+
+ if (!Extend1) {
+ //
+ // Check for special keys and update the driver state.
+ //
+ switch (ScanCode) {
+
+ case SCANCODE_CTRL_MAKE:
+ if (Extend0) {
+ ConsoleIn->RightCtrl = TRUE;
+ } else {
+ ConsoleIn->LeftCtrl = TRUE;
+ }
+ break;
+ case SCANCODE_CTRL_BREAK:
+ if (Extend0) {
+ ConsoleIn->RightCtrl = FALSE;
+ } else {
+ ConsoleIn->LeftCtrl = FALSE;
+ }
+ break;
+
+ case SCANCODE_ALT_MAKE:
+ if (Extend0) {
+ ConsoleIn->RightAlt = TRUE;
+ } else {
+ ConsoleIn->LeftAlt = TRUE;
+ }
+ break;
+ case SCANCODE_ALT_BREAK:
+ if (Extend0) {
+ ConsoleIn->RightAlt = FALSE;
+ } else {
+ ConsoleIn->LeftAlt = FALSE;
+ }
+ break;
+
+ case SCANCODE_LEFT_SHIFT_MAKE:
+ //
+ // To avoid recognize PRNT_SCRN key as a L_SHIFT key
+ // because PRNT_SCRN key generates E0 followed by L_SHIFT scan code.
+ // If it the second byte of the PRNT_ScRN skip it.
+ //
+ if (!Extend0) {
+ ConsoleIn->LeftShift = TRUE;
+ break;
+ }
+ continue;
+
+ case SCANCODE_LEFT_SHIFT_BREAK:
+ if (!Extend0) {
+ ConsoleIn->LeftShift = FALSE;
+ }
+ break;
+
+ case SCANCODE_RIGHT_SHIFT_MAKE:
+ ConsoleIn->RightShift = TRUE;
+ break;
+ case SCANCODE_RIGHT_SHIFT_BREAK:
+ ConsoleIn->RightShift = FALSE;
+ break;
+
+ case SCANCODE_LEFT_LOGO_MAKE:
+ ConsoleIn->LeftLogo = TRUE;
+ break;
+ case SCANCODE_LEFT_LOGO_BREAK:
+ ConsoleIn->LeftLogo = FALSE;
+ break;
+
+ case SCANCODE_RIGHT_LOGO_MAKE:
+ ConsoleIn->RightLogo = TRUE;
+ break;
+ case SCANCODE_RIGHT_LOGO_BREAK:
+ ConsoleIn->RightLogo = FALSE;
+ break;
+
+ case SCANCODE_MENU_MAKE:
+ ConsoleIn->Menu = TRUE;
+ break;
+ case SCANCODE_MENU_BREAK:
+ ConsoleIn->Menu = FALSE;
+ break;
+
+ case SCANCODE_SYS_REQ_MAKE:
+ if (Extend0) {
+ ConsoleIn->SysReq = TRUE;
+ }
+ break;
+ case SCANCODE_SYS_REQ_BREAK:
+ if (Extend0) {
+ ConsoleIn->SysReq = FALSE;
+ }
+ break;
+
+ case SCANCODE_SYS_REQ_MAKE_WITH_ALT:
+ ConsoleIn->SysReq = TRUE;
+ break;
+ case SCANCODE_SYS_REQ_BREAK_WITH_ALT:
+ ConsoleIn->SysReq = FALSE;
+ break;
+
+ case SCANCODE_CAPS_LOCK_MAKE:
+ ConsoleIn->CapsLock = (BOOLEAN)!ConsoleIn->CapsLock;
+ UpdateStatusLights (ConsoleIn);
+ break;
+ case SCANCODE_NUM_LOCK_MAKE:
+ ConsoleIn->NumLock = (BOOLEAN)!ConsoleIn->NumLock;
+ UpdateStatusLights (ConsoleIn);
+ break;
+ case SCANCODE_SCROLL_LOCK_MAKE:
+ if (!Extend0) {
+ ConsoleIn->ScrollLock = (BOOLEAN)!ConsoleIn->ScrollLock;
+ UpdateStatusLights (ConsoleIn);
+ }
+ break;
+ }
+ }
+
+ //
+ // If this is above the valid range, ignore it
+ //
+ if (ScanCode >= SCANCODE_MAX_MAKE) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ //
+ // Handle Ctrl+Alt+Del hotkey
+ //
+ if ((ConsoleIn->LeftCtrl || ConsoleIn->RightCtrl) &&
+ (ConsoleIn->LeftAlt || ConsoleIn->RightAlt ) &&
+ ScanCode == SCANCODE_DELETE_MAKE
+ ) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+
+ //
+ // Save the Shift/Toggle state
+ //
+ KeyData.KeyState.KeyShiftState = (UINT32) (EFI_SHIFT_STATE_VALID
+ | (ConsoleIn->LeftCtrl ? EFI_LEFT_CONTROL_PRESSED : 0)
+ | (ConsoleIn->RightCtrl ? EFI_RIGHT_CONTROL_PRESSED : 0)
+ | (ConsoleIn->LeftAlt ? EFI_LEFT_ALT_PRESSED : 0)
+ | (ConsoleIn->RightAlt ? EFI_RIGHT_ALT_PRESSED : 0)
+ | (ConsoleIn->LeftShift ? EFI_LEFT_SHIFT_PRESSED : 0)
+ | (ConsoleIn->RightShift ? EFI_RIGHT_SHIFT_PRESSED : 0)
+ | (ConsoleIn->LeftLogo ? EFI_LEFT_LOGO_PRESSED : 0)
+ | (ConsoleIn->RightLogo ? EFI_RIGHT_LOGO_PRESSED : 0)
+ | (ConsoleIn->Menu ? EFI_MENU_KEY_PRESSED : 0)
+ | (ConsoleIn->SysReq ? EFI_SYS_REQ_PRESSED : 0)
+ );
+ KeyData.KeyState.KeyToggleState = (EFI_KEY_TOGGLE_STATE) (EFI_TOGGLE_STATE_VALID
+ | (ConsoleIn->CapsLock ? EFI_CAPS_LOCK_ACTIVE : 0)
+ | (ConsoleIn->NumLock ? EFI_NUM_LOCK_ACTIVE : 0)
+ | (ConsoleIn->ScrollLock ? EFI_SCROLL_LOCK_ACTIVE : 0)
+ | (ConsoleIn->IsSupportPartialKey ? EFI_KEY_STATE_EXPOSED : 0)
+ );
+
+ KeyData.Key.ScanCode = SCAN_NULL;
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+
+ //
+ // Key Pad "/" shares the same scancode as that of "/" except Key Pad "/" has E0 prefix
+ //
+ if (Extend0 && ScanCode == 0x35) {
+ KeyData.Key.UnicodeChar = L'/';
+ KeyData.Key.ScanCode = SCAN_NULL;
+
+ //
+ // PAUSE shares the same scancode as that of NUM except PAUSE has E1 prefix
+ //
+ } else if (Extend1 && ScanCode == SCANCODE_NUM_LOCK_MAKE) {
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ KeyData.Key.ScanCode = SCAN_PAUSE;
+
+ //
+ // PAUSE shares the same scancode as that of SCROLL except PAUSE (CTRL pressed) has E0 prefix
+ //
+ } else if (Extend0 && ScanCode == SCANCODE_SCROLL_LOCK_MAKE) {
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ KeyData.Key.ScanCode = SCAN_PAUSE;
+
+ //
+ // PRNT_SCRN shares the same scancode as that of Key Pad "*" except PRNT_SCRN has E0 prefix
+ //
+ } else if (Extend0 && ScanCode == SCANCODE_SYS_REQ_MAKE) {
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ KeyData.Key.ScanCode = SCAN_NULL;
+
+ //
+ // Except the above special case, all others can be handled by convert table
+ //
+ } else {
+ for (Index = 0; ConvertKeyboardScanCodeToEfiKey[Index].ScanCode != TABLE_END; Index++) {
+ if (ScanCode == ConvertKeyboardScanCodeToEfiKey[Index].ScanCode) {
+ KeyData.Key.ScanCode = ConvertKeyboardScanCodeToEfiKey[Index].EfiScanCode;
+ KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar;
+
+ if ((ConsoleIn->LeftShift || ConsoleIn->RightShift) &&
+ (ConvertKeyboardScanCodeToEfiKey[Index].UnicodeChar != ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar)) {
+ KeyData.Key.UnicodeChar = ConvertKeyboardScanCodeToEfiKey[Index].ShiftUnicodeChar;
+ //
+ // Need not return associated shift state if a class of printable characters that
+ // are normally adjusted by shift modifiers. e.g. Shift Key + 'f' key = 'F'
+ //
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
+ }
+ //
+ // alphabetic key is affected by CapsLock State
+ //
+ if (ConsoleIn->CapsLock) {
+ if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'a' + L'A');
+ } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar - L'A' + L'a');
+ }
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // distinguish numeric key pad keys' 'up symbol' and 'down symbol'
+ //
+ if (ScanCode >= 0x47 && ScanCode <= 0x53) {
+ if (ConsoleIn->NumLock && !(ConsoleIn->LeftShift || ConsoleIn->RightShift) && !Extend0) {
+ KeyData.Key.ScanCode = SCAN_NULL;
+ } else if (ScanCode != 0x4a && ScanCode != 0x4e) {
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ }
+ }
+
+ //
+ // If the key can not be converted then just return.
+ //
+ if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
+ if (!ConsoleIn->IsSupportPartialKey) {
+ return ;
+ }
+ }
+
+ //
+ // Invoke notification functions if exist
+ //
+ for (Link = GetFirstNode (&ConsoleIn->NotifyList); !IsNull (&ConsoleIn->NotifyList, Link); Link = GetNextNode (&ConsoleIn->NotifyList, Link)) {
+ CurrentNotify = CR (
+ Link,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+
+ PushEfikeyBufTail (&ConsoleIn->EfiKeyQueue, &KeyData);
+}
+
+/**
+ Perform 8042 controller and keyboard Initialization.
+ If ExtendedVerification is TRUE, do additional test for
+ the keyboard interface
+
+ @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
+ @param ExtendedVerification - indicates a thorough initialization
+
+ @retval EFI_DEVICE_ERROR Fail to init keyboard
+ @retval EFI_SUCCESS Success to init keyboard
+**/
+EFI_STATUS
+InitKeyboard (
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ UINT8 CommandByte;
+ EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
+ UINT32 TryTime;
+
+ Status = EFI_SUCCESS;
+ mEnableMouseInterface = TRUE;
+ TryTime = 0;
+
+ //
+ // Get Ps2 policy to set this
+ //
+ gBS->LocateProtocol (
+ &gEfiPs2PolicyProtocolGuid,
+ NULL,
+ (VOID **) &Ps2Policy
+ );
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER,
+ ConsoleIn->DevicePath
+ );
+
+ //
+ // Perform a read to cleanup the Status Register's
+ // output buffer full bits within MAX TRY times
+ //
+ if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA) != 0) {
+ while (!EFI_ERROR (Status) && TryTime < KEYBOARD_MAX_TRY) {
+ Status = KeyboardRead (ConsoleIn, &CommandByte);
+ TryTime ++;
+ }
+ //
+ // Exceed the max try times. The device may be error.
+ //
+ if (TryTime == KEYBOARD_MAX_TRY) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+ }
+ //
+ // We should disable mouse interface during the initialization process
+ // since mouse device output could block keyboard device output in the
+ // 60H port of 8042 controller.
+ //
+ // So if we are not initializing 8042 controller for the
+ // first time, we have to remember the previous mouse interface
+ // enabling state
+ //
+ // Test the system flag in to determine whether this is the first
+ // time initialization
+ //
+ if ((KeyReadStatusRegister (ConsoleIn) & KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG) != 0) {
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ //
+ // 8042 controller is already setup (by myself or by mouse driver):
+ // See whether mouse interface is already enabled
+ // which determines whether we should enable it later
+ //
+ //
+ // Read the command byte of 8042 controller
+ //
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_READ);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardRead (ConsoleIn, &CommandByte);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"\n\r");
+ goto Done;
+ }
+ //
+ // Test the mouse enabling bit
+ //
+ if ((CommandByte & 0x20) != 0) {
+ mEnableMouseInterface = FALSE;
+ } else {
+ mEnableMouseInterface = TRUE;
+ }
+ } else {
+ mEnableMouseInterface = FALSE;
+ }
+ } else {
+ //
+ // 8042 controller is not setup yet:
+ // 8042 controller selftest;
+ // Don't enable mouse interface later.
+ //
+ //
+ // Disable keyboard and mouse interfaces
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"\n\r");
+ goto Done;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST,
+ ConsoleIn->DevicePath
+ );
+ //
+ // 8042 Controller Self Test
+ //
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, 0x55);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller self test failed!\n\r");
+ goto Done;
+ }
+ }
+ //
+ // Don't enable mouse interface later
+ //
+ mEnableMouseInterface = FALSE;
+
+ }
+
+ if (Ps2Policy != NULL) {
+ Ps2Policy->Ps2InitHardware (ConsoleIn->Handle);
+ }
+ //
+ // Write 8042 Command Byte, set System Flag
+ // While at the same time:
+ // 1. disable mouse interface,
+ // 2. enable kbd interface,
+ // 3. enable PC/XT kbd translation mode
+ // 4. enable mouse and kbd interrupts
+ //
+ // ( Command Byte bits:
+ // 7: Reserved
+ // 6: PC/XT translation mode
+ // 5: Disable Auxiliary device interface
+ // 4: Disable keyboard interface
+ // 3: Reserved
+ // 2: System Flag
+ // 1: Enable Auxiliary device interrupt
+ // 0: Enable Keyboard interrupt )
+ //
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_WRITE);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWrite (ConsoleIn, 0x67);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
+ goto Done;
+ }
+
+ //
+ // Clear Memory Scancode Buffer
+ //
+ ConsoleIn->ScancodeQueue.Head = 0;
+ ConsoleIn->ScancodeQueue.Tail = 0;
+ ConsoleIn->EfiKeyQueue.Head = 0;
+ ConsoleIn->EfiKeyQueue.Tail = 0;
+
+ //
+ // Reset the status indicators
+ //
+ ConsoleIn->CapsLock = FALSE;
+ ConsoleIn->NumLock = FALSE;
+ ConsoleIn->ScrollLock = FALSE;
+ ConsoleIn->LeftCtrl = FALSE;
+ ConsoleIn->RightCtrl = FALSE;
+ ConsoleIn->LeftAlt = FALSE;
+ ConsoleIn->RightAlt = FALSE;
+ ConsoleIn->LeftShift = FALSE;
+ ConsoleIn->RightShift = FALSE;
+ ConsoleIn->LeftLogo = FALSE;
+ ConsoleIn->RightLogo = FALSE;
+ ConsoleIn->Menu = FALSE;
+ ConsoleIn->SysReq = FALSE;
+
+ ConsoleIn->IsSupportPartialKey = FALSE;
+ //
+ // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
+ // and to support KB hot plug, we need to let the InitKB succeed no matter whether there is a KB device connected
+ // to system. So we only do the real reseting for keyboard when user asks and there is a real KB connected t system,
+ // and normally during booting an OS, it's skipped.
+ //
+ if (ExtendedVerification && CheckKeyboardConnect (ConsoleIn)) {
+ //
+ // Additional verifications for keyboard interface
+ //
+ //
+ // Keyboard Interface Test
+ //
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, 0x00);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (
+ ConsoleIn,
+ L"Some specific value not aquired from 8042 controller!\n\r"
+ );
+ goto Done;
+ }
+ //
+ // Keyboard reset with a BAT(Basic Assurance Test)
+ //
+ Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_RESET);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");
+ goto Done;
+ }
+ //
+ // wait for BAT completion code
+ //
+ mWaitForValueTimeOut = KEYBOARD_BAT_TIMEOUT;
+
+ Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_BAT_SUCCESS);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Keyboard self test failed!\n\r");
+ goto Done;
+ }
+
+ mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
+
+ //
+ // Set Keyboard to use Scan Code Set 2
+ //
+ Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWrite (ConsoleIn, 0x02);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller data write error!!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");
+ goto Done;
+ }
+
+ //
+ // Clear Keyboard Scancode Buffer
+ //
+ Status = KeyboardWrite (ConsoleIn, KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"8042 controller data write error!\n\r");
+ goto Done;
+ }
+
+ Status = KeyboardWaitForValue (ConsoleIn, KEYBOARD_8048_RETURN_8042_ACK);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Some specific value not aquired from 8042 controller!\n\r");
+ goto Done;
+ }
+ //
+ if (Ps2Policy != NULL) {
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
+ ConsoleIn->CapsLock = TRUE;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
+ ConsoleIn->NumLock = TRUE;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
+ ConsoleIn->ScrollLock = TRUE;
+ }
+ }
+ //
+ // Update Keyboard Lights
+ //
+ Status = UpdateStatusLights (ConsoleIn);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"Update keyboard status lights error!\n\r");
+ goto Done;
+ }
+ }
+ //
+ // At last, we can now enable the mouse interface if appropriate
+ //
+Done:
+
+ if (mEnableMouseInterface) {
+ //
+ // Enable mouse interface
+ //
+ Status1 = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE);
+ if (EFI_ERROR (Status1)) {
+ KeyboardError (ConsoleIn, L"8042 controller command write error!\n\r");
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+
+}
+
+/**
+ Disable the keyboard interface of the 8042 controller.
+
+ @param ConsoleIn The device instance
+
+ @return status of issuing disable command
+
+**/
+EFI_STATUS
+DisableKeyboard (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Disable keyboard interface
+ //
+ Status = KeyboardCommand (ConsoleIn, KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE);
+ if (EFI_ERROR (Status)) {
+ KeyboardError (ConsoleIn, L"\n\r");
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param[in] ConsoleIn Keyboard Private Data Structure
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+**/
+BOOLEAN
+EFIAPI
+CheckKeyboardConnect (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ )
+{
+ EFI_STATUS Status;
+ UINTN WaitForValueTimeOutBcakup;
+
+ //
+ // enable keyboard itself and wait for its ack
+ // If can't receive ack, Keyboard should not be connected.
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ Status = KeyboardWrite (
+ ConsoleIn,
+ KEYBOARD_KBEN
+ );
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // wait for 1s
+ //
+ WaitForValueTimeOutBcakup = mWaitForValueTimeOut;
+ mWaitForValueTimeOut = KEYBOARD_WAITFORVALUE_TIMEOUT;
+ Status = KeyboardWaitForValue (
+ ConsoleIn,
+ KEYBOARD_CMDECHO_ACK
+ );
+ mWaitForValueTimeOut = WaitForValueTimeOutBcakup;
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ return TRUE;
+ } else {
+ return TRUE;
+ }
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
new file mode 100644
index 0000000000..0efeb39e0d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KbdTextIn.c
@@ -0,0 +1,683 @@
+/** @file
+ Routines implements SIMPLE_TEXT_IN protocol's interfaces based on 8042 interfaces
+ provided by Ps2KbdCtrller.c.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "Ps2Keyboard.h"
+
+/**
+ Check whether the EFI key buffer is empty.
+
+ @param Queue Pointer to instance of EFI_KEY_QUEUE.
+
+ @retval TRUE The EFI key buffer is empty.
+ @retval FALSE The EFI key buffer isn't empty.
+**/
+BOOLEAN
+IsEfikeyBufEmpty (
+ IN EFI_KEY_QUEUE *Queue
+ )
+{
+ return (BOOLEAN) (Queue->Head == Queue->Tail);
+}
+
+/**
+ Read & remove one key data from the EFI key buffer.
+
+ @param Queue Pointer to instance of EFI_KEY_QUEUE.
+ @param KeyData Receive the key data.
+
+ @retval EFI_SUCCESS The key data is popped successfully.
+ @retval EFI_NOT_READY There is no key data available.
+**/
+EFI_STATUS
+PopEfikeyBufHead (
+ IN EFI_KEY_QUEUE *Queue,
+ OUT EFI_KEY_DATA *KeyData OPTIONAL
+ )
+{
+ if (IsEfikeyBufEmpty (Queue)) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Retrieve and remove the values
+ //
+ if (KeyData != NULL) {
+ CopyMem (KeyData, &Queue->Buffer[Queue->Head], sizeof (EFI_KEY_DATA));
+ }
+ Queue->Head = (Queue->Head + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
+ return EFI_SUCCESS;
+}
+
+/**
+ Push one key data to the EFI key buffer.
+
+ @param Queue Pointer to instance of EFI_KEY_QUEUE.
+ @param KeyData The key data to push.
+**/
+VOID
+PushEfikeyBufTail (
+ IN EFI_KEY_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if ((Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT == Queue->Head) {
+ //
+ // If Queue is full, pop the one from head.
+ //
+ PopEfikeyBufHead (Queue, NULL);
+ }
+ CopyMem (&Queue->Buffer[Queue->Tail], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Tail = (Queue->Tail + 1) % KEYBOARD_EFI_KEY_MAX_COUNT;
+}
+
+/**
+ Judge whether is a registed key
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+ return FALSE;
+ }
+
+ //
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
+ //
+ if (RegsiteredData->KeyState.KeyShiftState != 0 &&
+ RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
+ return FALSE;
+ }
+ if (RegsiteredData->KeyState.KeyToggleState != 0 &&
+ RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param ConsoleInDev Ps2 Keyboard private structure
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+KeyboardReadKeyStrokeWorker (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev,
+ OUT EFI_KEY_DATA *KeyData
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ KeyboardTimerHandler (NULL, ConsoleInDev);
+
+ if (ConsoleInDev->KeyboardErr) {
+ Status = EFI_DEVICE_ERROR;
+ } else {
+ Status = PopEfikeyBufHead (&ConsoleInDev->EfiKeyQueue, KeyData);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Perform 8042 controller and keyboard initialization which implement SIMPLE_TEXT_IN.Reset()
+
+ @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ @param ExtendedVerification Indicate that the driver may perform a more
+ exhaustive verification operation of the device during
+ reset, now this par is ignored in this driver
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardEfiReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ EFI_TPL OldTpl;
+
+ ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+ if (ConsoleIn->KeyboardErr) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET,
+ ConsoleIn->DevicePath
+ );
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Call InitKeyboard to initialize the keyboard
+ //
+ Status = InitKeyboard (ConsoleIn, ExtendedVerification);
+ if (EFI_ERROR (Status)) {
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ //
+ // Report the status If a stuck key was detected
+ //
+ if (KeyReadStatusRegister (ConsoleIn) & 0x01) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_STUCK_KEY,
+ ConsoleIn->DevicePath
+ );
+ }
+ //
+ // Report the status If keyboard is locked
+ //
+ if ((KeyReadStatusRegister (ConsoleIn) & 0x10) == 0) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_EC_LOCKED,
+ ConsoleIn->DevicePath
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Retrieve key values for driver user which implement SIMPLE_TEXT_IN.ReadKeyStroke().
+
+ @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ @param Key The output buffer for key value
+
+ @retval EFI_SUCCESS success to read key stroke
+**/
+EFI_STATUS
+EFIAPI
+KeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ EFI_KEY_DATA KeyData;
+
+ ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+
+ //
+ // Considering if the partial keystroke is enabled, there maybe a partial
+ // keystroke in the queue, so here skip the partial keystroke and get the
+ // next key from the queue
+ //
+ while (1) {
+ //
+ // If there is no pending key, then return.
+ //
+ Status = KeyboardReadKeyStrokeWorker (ConsoleIn, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // If it is partial keystroke, skip it.
+ //
+ if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
+ continue;
+ }
+ //
+ // Translate the CTRL-Alpha characters to their corresponding control value
+ // (ctrl-a = 0x0001 through ctrl-Z = 0x001A)
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
+ } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
+ }
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+ return EFI_SUCCESS;
+ }
+}
+
+/**
+ Event notification function for SIMPLE_TEXT_IN.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event the event object
+ @param Context waitting context
+
+**/
+VOID
+EFIAPI
+KeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_TPL OldTpl;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ EFI_KEY_DATA KeyData;
+
+ ConsoleIn = (KEYBOARD_CONSOLE_IN_DEV *) Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ KeyboardTimerHandler (NULL, ConsoleIn);
+
+ if (!ConsoleIn->KeyboardErr) {
+ //
+ // WaitforKey doesn't suppor the partial key.
+ // Considering if the partial keystroke is enabled, there maybe a partial
+ // keystroke in the queue, so here skip the partial keystroke and get the
+ // next key from the queue
+ //
+ while (!IsEfikeyBufEmpty (&ConsoleIn->EfiKeyQueue)) {
+ CopyMem (
+ &KeyData,
+ &(ConsoleIn->EfiKeyQueue.Buffer[ConsoleIn->EfiKeyQueue.Head]),
+ sizeof (EFI_KEY_DATA)
+ );
+ if (KeyData.Key.ScanCode == SCAN_NULL && KeyData.Key.UnicodeChar == CHAR_NULL) {
+ PopEfikeyBufHead (&ConsoleIn->EfiKeyQueue, &KeyData);
+ continue;
+ }
+ //
+ // if there is pending value key, signal the event.
+ //
+ gBS->SignalEvent (Event);
+ break;
+ }
+ }
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+}
+
+/**
+ Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event event object
+ @param Context waiting context
+
+**/
+VOID
+EFIAPI
+KeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+
+{
+ KeyboardWaitForKey (Event, Context);
+}
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardEfiResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+
+{
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
+
+ ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+
+ return ConsoleInDev->ConIn.Reset (
+ &ConsoleInDev->ConIn,
+ ExtendedVerification
+ );
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+
+{
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+ return KeyboardReadKeyStrokeWorker (ConsoleInDev, KeyData);
+}
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
+ EFI_TPL OldTpl;
+
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ if (ConsoleInDev->KeyboardErr) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID) {
+ Status = EFI_UNSUPPORTED;
+ goto Exit;
+ }
+
+ //
+ // Update the status light
+ //
+ ConsoleInDev->ScrollLock = FALSE;
+ ConsoleInDev->NumLock = FALSE;
+ ConsoleInDev->CapsLock = FALSE;
+ ConsoleInDev->IsSupportPartialKey = FALSE;
+
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
+ ConsoleInDev->ScrollLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
+ ConsoleInDev->NumLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
+ ConsoleInDev->CapsLock = TRUE;
+ }
+ if ((*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED) {
+ ConsoleInDev->IsSupportPartialKey = TRUE;
+ }
+
+ Status = UpdateStatusLights (ConsoleInDev);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle or KeyNotificationFunction is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+ NewNotify = (KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ NewNotify->Signature = KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&ConsoleInDev->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+ Status = EFI_SUCCESS;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+
+}
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ EFI_STATUS Status;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleInDev;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ ConsoleInDev = TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = ConsoleInDev->NotifyList.ForwardLink; Link != &ConsoleInDev->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ gBS->FreePool (CurrentNotify);
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Can not find the specified Notification Handle
+ //
+ Status = EFI_INVALID_PARAMETER;
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c
new file mode 100644
index 0000000000..c020202349
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.c
@@ -0,0 +1,642 @@
+/** @file
+
+ PS/2 Keyboard driver. Routines that interacts with callers,
+ conforming to EFI driver model
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Keyboard.h"
+
+//
+// Function prototypes
+//
+/**
+ Test controller is a keyboard Controller.
+
+ @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
+ @param Controller driver's controller
+ @param RemainingDevicePath children device path
+
+ @retval EFI_UNSUPPORTED controller is not floppy disk
+ @retval EFI_SUCCESS controller is floppy disk
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
+
+ @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
+ @param Controller driver controller handle
+ @param RemainingDevicePath Children's device path
+
+ @retval whether success to create floppy control instance.
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Free the waiting key notify list.
+
+ @param ListHead Pointer to list head
+
+ @retval EFI_INVALID_PARAMETER ListHead is NULL
+ @retval EFI_SUCCESS Sucess to free NotifyList
+**/
+EFI_STATUS
+KbdFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+//
+// DriverBinding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver = {
+ KbdControllerDriverSupported,
+ KbdControllerDriverStart,
+ KbdControllerDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Test controller is a keyboard Controller.
+
+ @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
+ @param Controller driver's controller
+ @param RemainingDevicePath children device path
+
+ @retval EFI_UNSUPPORTED controller is not floppy disk
+ @retval EFI_SUCCESS controller is floppy disk
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Create KEYBOARD_CONSOLE_IN_DEV instance on controller.
+
+ @param This Pointer of EFI_DRIVER_BINDING_PROTOCOL
+ @param Controller driver controller handle
+ @param RemainingDevicePath Children's device path
+
+ @retval whether success to create floppy control instance.
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS Status1;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ UINT8 Data;
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ StatusCode = 0;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+
+ //
+ // Get the ISA I/O Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Allocate private data
+ //
+ ConsoleIn = AllocateZeroPool (sizeof (KEYBOARD_CONSOLE_IN_DEV));
+ if (ConsoleIn == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ //
+ // Setup the device instance
+ //
+ ConsoleIn->Signature = KEYBOARD_CONSOLE_IN_DEV_SIGNATURE;
+ ConsoleIn->Handle = Controller;
+ (ConsoleIn->ConIn).Reset = KeyboardEfiReset;
+ (ConsoleIn->ConIn).ReadKeyStroke = KeyboardReadKeyStroke;
+ ConsoleIn->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
+ ConsoleIn->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
+ ConsoleIn->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
+ ConsoleIn->IsaIo = IsaIo;
+ ConsoleIn->DevicePath = ParentDevicePath;
+
+ ConsoleIn->ConInEx.Reset = KeyboardEfiResetEx;
+ ConsoleIn->ConInEx.ReadKeyStrokeEx = KeyboardReadKeyStrokeEx;
+ ConsoleIn->ConInEx.SetState = KeyboardSetState;
+ ConsoleIn->ConInEx.RegisterKeyNotify = KeyboardRegisterKeyNotify;
+ ConsoleIn->ConInEx.UnregisterKeyNotify = KeyboardUnregisterKeyNotify;
+
+ InitializeListHead (&ConsoleIn->NotifyList);
+
+ //
+ // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
+ // When KBC decode (IO port 0x60/0x64 decode) is not enabled,
+ // KeyboardRead will read back as 0xFF and return status is EFI_SUCCESS.
+ // So instead we read status register to detect after read if KBC decode is enabled.
+ //
+
+ //
+ // Return code is ignored on purpose.
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ KeyboardRead (ConsoleIn, &Data);
+ if ((KeyReadStatusRegister (ConsoleIn) & (KBC_PARE | KBC_TIM)) == (KBC_PARE | KBC_TIM)) {
+ //
+ // If nobody decodes KBC I/O port, it will read back as 0xFF.
+ // Check the Time-Out and Parity bit to see if it has an active KBC in system
+ //
+ Status = EFI_DEVICE_ERROR;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
+ goto ErrorExit;
+ }
+ }
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ KeyboardWaitForKey,
+ ConsoleIn,
+ &((ConsoleIn->ConIn).WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ //
+ // Setup the WaitForKeyEx event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ KeyboardWaitForKeyEx,
+ ConsoleIn,
+ &(ConsoleIn->ConInEx.WaitForKeyEx)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ // Setup a periodic timer, used for reading keystrokes at a fixed interval
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ KeyboardTimerHandler,
+ ConsoleIn,
+ &ConsoleIn->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+
+ Status = gBS->SetTimer (
+ ConsoleIn->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT,
+ ParentDevicePath
+ );
+
+ //
+ // Reset the keyboard device
+ //
+ Status = ConsoleIn->ConInEx.Reset (&ConsoleIn->ConInEx, FeaturePcdGet (PcdPs2KbdExtendedVerification));
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DETECTED,
+ ParentDevicePath
+ );
+
+ ConsoleIn->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gPs2KeyboardComponentName.SupportedLanguages,
+ &ConsoleIn->ControllerNameTable,
+ L"PS/2 Keyboard Device",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gPs2KeyboardComponentName2.SupportedLanguages,
+ &ConsoleIn->ControllerNameTable,
+ L"PS/2 Keyboard Device",
+ FALSE
+ );
+
+
+ //
+ // Install protocol interfaces for the keyboard device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &ConsoleIn->ConIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &ConsoleIn->ConInEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+
+ return Status;
+
+ErrorExit:
+ //
+ // Report error code
+ //
+ if (StatusCode != 0) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode,
+ ParentDevicePath
+ );
+ }
+
+ if ((ConsoleIn != NULL) && (ConsoleIn->ConIn.WaitForKey != NULL)) {
+ gBS->CloseEvent (ConsoleIn->ConIn.WaitForKey);
+ }
+
+ if ((ConsoleIn != NULL) && (ConsoleIn->TimerEvent != NULL)) {
+ gBS->CloseEvent (ConsoleIn->TimerEvent);
+ }
+ if ((ConsoleIn != NULL) && (ConsoleIn->ConInEx.WaitForKeyEx != NULL)) {
+ gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
+ }
+ KbdFreeNotifyList (&ConsoleIn->NotifyList);
+ if ((ConsoleIn != NULL) && (ConsoleIn->ControllerNameTable != NULL)) {
+ FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
+ }
+ //
+ // Since there will be no timer handler for keyboard input any more,
+ // exhaust input data just in case there is still keyboard data left
+ //
+ if (ConsoleIn != NULL) {
+ Status1 = EFI_SUCCESS;
+ while (!EFI_ERROR (Status1) && (Status != EFI_DEVICE_ERROR)) {
+ Status1 = KeyboardRead (ConsoleIn, &Data);;
+ }
+ }
+
+ if (ConsoleIn != NULL) {
+ gBS->FreePool (ConsoleIn);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+KbdControllerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *ConIn;
+ KEYBOARD_CONSOLE_IN_DEV *ConsoleIn;
+ UINT8 Data;
+
+ //
+ // Disable Keyboard
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &ConIn,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ConsoleIn = KEYBOARD_CONSOLE_IN_DEV_FROM_THIS (ConIn);
+
+ //
+ // Report that the keyboard is being disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_DISABLE,
+ ConsoleIn->DevicePath
+ );
+
+ if (ConsoleIn->TimerEvent != NULL) {
+ gBS->CloseEvent (ConsoleIn->TimerEvent);
+ ConsoleIn->TimerEvent = NULL;
+ }
+
+ //
+ // Since there will be no timer handler for keyboard input any more,
+ // exhaust input data just in case there is still keyboard data left
+ //
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status)) {
+ Status = KeyboardRead (ConsoleIn, &Data);;
+ }
+ //
+ // Uninstall the SimpleTextIn and SimpleTextInEx protocols
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &ConsoleIn->ConIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &ConsoleIn->ConInEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free other resources
+ //
+ if ((ConsoleIn->ConIn).WaitForKey != NULL) {
+ gBS->CloseEvent ((ConsoleIn->ConIn).WaitForKey);
+ (ConsoleIn->ConIn).WaitForKey = NULL;
+ }
+ if (ConsoleIn->ConInEx.WaitForKeyEx != NULL) {
+ gBS->CloseEvent (ConsoleIn->ConInEx.WaitForKeyEx);
+ ConsoleIn->ConInEx.WaitForKeyEx = NULL;
+ }
+ KbdFreeNotifyList (&ConsoleIn->NotifyList);
+ FreeUnicodeStringTable (ConsoleIn->ControllerNameTable);
+ gBS->FreePool (ConsoleIn);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free the waiting key notify list.
+
+ @param ListHead Pointer to list head
+
+ @retval EFI_INVALID_PARAMETER ListHead is NULL
+ @retval EFI_SUCCESS Sucess to free NotifyList
+**/
+EFI_STATUS
+KbdFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ gBS->FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The module Entry Point for module Ps2Keyboard.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePs2Keyboard(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gKeyboardControllerDriver,
+ ImageHandle,
+ &gPs2KeyboardComponentName,
+ &gPs2KeyboardComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h
new file mode 100644
index 0000000000..2023905538
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2Keyboard.h
@@ -0,0 +1,550 @@
+/** @file
+ PS/2 keyboard driver header file
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PS2KEYBOARD_H_
+#define _PS2KEYBOARD_H_
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Ps2Policy.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gKeyboardControllerDriver;
+extern EFI_COMPONENT_NAME_PROTOCOL gPs2KeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPs2KeyboardComponentName2;
+
+//
+// Driver Private Data
+//
+#define KEYBOARD_CONSOLE_IN_DEV_SIGNATURE SIGNATURE_32 ('k', 'k', 'e', 'y')
+#define KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('k', 'c', 'e', 'n')
+
+typedef struct _KEYBOARD_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} KEYBOARD_CONSOLE_IN_EX_NOTIFY;
+
+#define KEYBOARD_SCAN_CODE_MAX_COUNT 32
+typedef struct {
+ UINT8 Buffer[KEYBOARD_SCAN_CODE_MAX_COUNT];
+ UINTN Head;
+ UINTN Tail;
+} SCAN_CODE_QUEUE;
+
+#define KEYBOARD_EFI_KEY_MAX_COUNT 256
+typedef struct {
+ EFI_KEY_DATA Buffer[KEYBOARD_EFI_KEY_MAX_COUNT];
+ UINTN Head;
+ UINTN Tail;
+} EFI_KEY_QUEUE;
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL ConIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL ConInEx;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ EFI_EVENT TimerEvent;
+
+ UINT32 DataRegisterAddress;
+ UINT32 StatusRegisterAddress;
+ UINT32 CommandRegisterAddress;
+
+ BOOLEAN LeftCtrl;
+ BOOLEAN RightCtrl;
+ BOOLEAN LeftAlt;
+ BOOLEAN RightAlt;
+ BOOLEAN LeftShift;
+ BOOLEAN RightShift;
+ BOOLEAN LeftLogo;
+ BOOLEAN RightLogo;
+ BOOLEAN Menu;
+ BOOLEAN SysReq;
+
+ BOOLEAN CapsLock;
+ BOOLEAN NumLock;
+ BOOLEAN ScrollLock;
+
+ BOOLEAN IsSupportPartialKey;
+ //
+ // Queue storing key scancodes
+ //
+ SCAN_CODE_QUEUE ScancodeQueue;
+ EFI_KEY_QUEUE EfiKeyQueue;
+
+ //
+ // Error state
+ //
+ BOOLEAN KeyboardErr;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ //
+ // Notification Function List
+ //
+ LIST_ENTRY NotifyList;
+} KEYBOARD_CONSOLE_IN_DEV;
+
+#define KEYBOARD_CONSOLE_IN_DEV_FROM_THIS(a) CR (a, KEYBOARD_CONSOLE_IN_DEV, ConIn, KEYBOARD_CONSOLE_IN_DEV_SIGNATURE)
+#define TEXT_INPUT_EX_KEYBOARD_CONSOLE_IN_DEV_FROM_THIS(a) \
+ CR (a, \
+ KEYBOARD_CONSOLE_IN_DEV, \
+ ConInEx, \
+ KEYBOARD_CONSOLE_IN_DEV_SIGNATURE \
+ )
+
+#define TABLE_END 0x0
+
+//
+// Driver entry point
+//
+/**
+ The user Entry Point for module Ps2Keyboard. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallPs2KeyboardDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+#define KEYBOARD_8042_DATA_REGISTER 0x60
+#define KEYBOARD_8042_STATUS_REGISTER 0x64
+#define KEYBOARD_8042_COMMAND_REGISTER 0x64
+
+#define KEYBOARD_KBEN 0xF4
+#define KEYBOARD_CMDECHO_ACK 0xFA
+
+#define KEYBOARD_MAX_TRY 256 // 256
+#define KEYBOARD_TIMEOUT 65536 // 0.07s
+#define KEYBOARD_WAITFORVALUE_TIMEOUT 1000000 // 1s
+#define KEYBOARD_BAT_TIMEOUT 4000000 // 4s
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+#define SCANCODE_EXTENDED0 0xE0
+#define SCANCODE_EXTENDED1 0xE1
+#define SCANCODE_CTRL_MAKE 0x1D
+#define SCANCODE_CTRL_BREAK 0x9D
+#define SCANCODE_ALT_MAKE 0x38
+#define SCANCODE_ALT_BREAK 0xB8
+#define SCANCODE_LEFT_SHIFT_MAKE 0x2A
+#define SCANCODE_LEFT_SHIFT_BREAK 0xAA
+#define SCANCODE_RIGHT_SHIFT_MAKE 0x36
+#define SCANCODE_RIGHT_SHIFT_BREAK 0xB6
+#define SCANCODE_CAPS_LOCK_MAKE 0x3A
+#define SCANCODE_NUM_LOCK_MAKE 0x45
+#define SCANCODE_SCROLL_LOCK_MAKE 0x46
+#define SCANCODE_DELETE_MAKE 0x53
+#define SCANCODE_LEFT_LOGO_MAKE 0x5B //GUI key defined in Keyboard scan code
+#define SCANCODE_LEFT_LOGO_BREAK 0xDB
+#define SCANCODE_RIGHT_LOGO_MAKE 0x5C
+#define SCANCODE_RIGHT_LOGO_BREAK 0xDC
+#define SCANCODE_MENU_MAKE 0x5D //APPS key defined in Keyboard scan code
+#define SCANCODE_MENU_BREAK 0xDD
+#define SCANCODE_SYS_REQ_MAKE 0x37
+#define SCANCODE_SYS_REQ_BREAK 0xB7
+#define SCANCODE_SYS_REQ_MAKE_WITH_ALT 0x54
+#define SCANCODE_SYS_REQ_BREAK_WITH_ALT 0xD4
+
+#define SCANCODE_MAX_MAKE 0x60
+
+
+#define KEYBOARD_STATUS_REGISTER_HAS_OUTPUT_DATA BIT0 ///< 0 - Output register has no data; 1 - Output register has data
+#define KEYBOARD_STATUS_REGISTER_HAS_INPUT_DATA BIT1 ///< 0 - Input register has no data; 1 - Input register has data
+#define KEYBOARD_STATUS_REGISTER_SYSTEM_FLAG BIT2 ///< Set to 0 after power on reset
+#define KEYBOARD_STATUS_REGISTER_INPUT_DATA_TYPE BIT3 ///< 0 - Data in input register is data; 1 - Data in input register is command
+#define KEYBOARD_STATUS_REGISTER_ENABLE_FLAG BIT4 ///< 0 - Keyboard is disable; 1 - Keyboard is enable
+#define KEYBOARD_STATUS_REGISTER_TRANSMIT_TIMEOUT BIT5 ///< 0 - Transmit is complete without timeout; 1 - Transmit is timeout without complete
+#define KEYBOARD_STATUS_REGISTER_RECEIVE_TIMEOUT BIT6 ///< 0 - Receive is complete without timeout; 1 - Receive is timeout without complete
+#define KEYBOARD_STATUS_REGISTER_PARITY BIT7 ///< 0 - Odd parity; 1 - Even parity
+
+#define KEYBOARD_8042_COMMAND_READ 0x20
+#define KEYBOARD_8042_COMMAND_WRITE 0x60
+#define KEYBOARD_8042_COMMAND_DISABLE_MOUSE_INTERFACE 0xA7
+#define KEYBOARD_8042_COMMAND_ENABLE_MOUSE_INTERFACE 0xA8
+#define KEYBOARD_8042_COMMAND_CONTROLLER_SELF_TEST 0xAA
+#define KEYBOARD_8042_COMMAND_KEYBOARD_INTERFACE_SELF_TEST 0xAB
+#define KEYBOARD_8042_COMMAND_DISABLE_KEYBOARD_INTERFACE 0xAD
+
+#define KEYBOARD_8048_COMMAND_CLEAR_OUTPUT_DATA 0xF4
+#define KEYBOARD_8048_COMMAND_RESET 0xFF
+#define KEYBOARD_8048_COMMAND_SELECT_SCAN_CODE_SET 0xF0
+
+#define KEYBOARD_8048_RETURN_8042_BAT_SUCCESS 0xAA
+#define KEYBOARD_8048_RETURN_8042_BAT_ERROR 0xFC
+#define KEYBOARD_8048_RETURN_8042_ACK 0xFA
+
+
+//
+// Keyboard Controller Status
+//
+#define KBC_PARE 0x80 // Parity Error
+#define KBC_TIM 0x40 // General Time Out
+
+//
+// Other functions that are used among .c files
+//
+/**
+ Show keyboard status lights according to
+ indicators in ConsoleIn.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @return status
+
+**/
+EFI_STATUS
+UpdateStatusLights (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ );
+
+/**
+ write key to keyboard.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+ @param Data value wanted to be written
+
+ @retval EFI_TIMEOUT - GC_TODO: Add description for return value
+ @retval EFI_SUCCESS - GC_TODO: Add description for return value
+
+**/
+EFI_STATUS
+KeyboardRead (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ OUT UINT8 *Data
+ );
+
+/**
+ Get scancode from scancode buffer and translate into EFI-scancode and unicode defined by EFI spec.
+
+ The function is always called in TPL_NOTIFY.
+
+ @param ConsoleIn KEYBOARD_CONSOLE_IN_DEV instance pointer
+
+**/
+VOID
+KeyGetchar (
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ );
+
+/**
+ Perform 8042 controller and keyboard Initialization.
+ If ExtendedVerification is TRUE, do additional test for
+ the keyboard interface
+
+ @param ConsoleIn - KEYBOARD_CONSOLE_IN_DEV instance pointer
+ @param ExtendedVerification - indicates a thorough initialization
+
+ @retval EFI_DEVICE_ERROR Fail to init keyboard
+ @retval EFI_SUCCESS Success to init keyboard
+**/
+EFI_STATUS
+InitKeyboard (
+ IN OUT KEYBOARD_CONSOLE_IN_DEV *ConsoleIn,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Disable the keyboard interface of the 8042 controller.
+
+ @param ConsoleIn - the device instance
+
+ @return status of issuing disable command
+
+**/
+EFI_STATUS
+DisableKeyboard (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ );
+
+/**
+ Timer event handler: read a series of scancodes from 8042
+ and put them into memory scancode buffer.
+ it read as much scancodes to either fill
+ the memory buffer or empty the keyboard buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event - The timer event
+ @param Context - A KEYBOARD_CONSOLE_IN_DEV pointer
+
+**/
+VOID
+EFIAPI
+KeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ logic reset keyboard
+ Implement SIMPLE_TEXT_IN.Reset()
+ Perform 8042 controller and keyboard initialization
+
+ @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ @param ExtendedVerification Indicate that the driver may perform a more
+ exhaustive verification operation of the device during
+ reset, now this par is ignored in this driver
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardEfiReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Implement SIMPLE_TEXT_IN.ReadKeyStroke().
+ Retrieve key values for driver user.
+
+ @param This Pointer to instance of EFI_SIMPLE_TEXT_INPUT_PROTOCOL
+ @param Key The output buffer for key value
+
+ @retval EFI_SUCCESS success to read key stroke
+**/
+EFI_STATUS
+EFIAPI
+KeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+/**
+ Event notification function for SIMPLE_TEXT_IN.WaitForKey event
+ Signal the event if there is key available
+
+ @param Event the event object
+ @param Context waitting context
+
+**/
+VOID
+EFIAPI
+KeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Read status register.
+
+ @param ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @return value in status register
+
+**/
+UINT8
+KeyReadStatusRegister (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ );
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param[in] ConsoleIn Pointer to instance of KEYBOARD_CONSOLE_IN_DEV
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+**/
+BOOLEAN
+EFIAPI
+CheckKeyboardConnect (
+ IN KEYBOARD_CONSOLE_IN_DEV *ConsoleIn
+ );
+
+/**
+ Event notification function for SIMPLE_TEXT_INPUT_EX_PROTOCOL.WaitForKeyEx event
+ Signal the event if there is key available
+
+ @param Event event object
+ @param Context waiting context
+
+**/
+VOID
+EFIAPI
+KeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Simple Text Input Ex protocol function prototypes
+//
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This - Protocol instance pointer.
+ @param ExtendedVerification - Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS - The device was reset.
+ @retval EFI_DEVICE_ERROR - The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardEfiResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+
+ @param This - Protocol instance pointer.
+ @param KeyData - A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS - The keystroke information was returned.
+ @retval EFI_NOT_READY - There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR - The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER - KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+/**
+ Set certain state for the input device.
+
+ @param This - Protocol instance pointer.
+ @param KeyToggleState - A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS - The device state was set successfully.
+ @retval EFI_DEVICE_ERROR - The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED - The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER - KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This - Protocol instance pointer.
+ @param KeyData - A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction - Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle - Points to the unique handle assigned to the registered notification.
+
+ @retval EFI_SUCCESS - The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES - Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER - KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ );
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This - Protocol instance pointer.
+ @param NotificationHandle - The handle of the notification function being unregistered.
+
+
+ @retval EFI_SUCCESS - The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER - The NotificationHandle is invalid.
+ @retval EFI_NOT_FOUND - Can not find the matching entry in database.
+
+**/
+EFI_STATUS
+EFIAPI
+KeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ Push one key data to the EFI key buffer.
+
+ @param Queue Pointer to instance of EFI_KEY_QUEUE.
+ @param KeyData The key data to push.
+**/
+VOID
+PushEfikeyBufTail (
+ IN EFI_KEY_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ );
+
+/**
+ Judge whether is a registed key
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni
new file mode 100644
index 0000000000..0410dd216a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni
new file mode 100644
index 0000000000..155d2515f8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2KeyboardDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf
new file mode 100644
index 0000000000..13c1ea9091
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf
@@ -0,0 +1,85 @@
+## @file
+# Ps2 Keyboard Driver.
+#
+# Ps2 Keyboard Driver for UEFI. The keyboard type implemented follows IBM
+# compatible PS2 protocol using Scan Code Set 1.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ps2KeyboardDxe
+ MODULE_UNI_FILE = Ps2KeyboardDxe.uni
+ FILE_GUID = 3DC82376-637B-40a6-A8FC-A565417F2C38
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePs2Keyboard
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gKeyboardControllerDriver;
+# COMPONENT_NAME = gPs2KeyboardComponentName;
+# COMPONENT_NAME2 = gPs2KeyboardComponentName2;
+#
+
+[Sources]
+ ComponentName.c
+ Ps2Keyboard.h
+ Ps2KbdCtrller.c
+ Ps2KbdTextIn.c
+ Ps2Keyboard.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiRuntimeServicesTableLib
+ DebugLib
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ UefiLib
+ UefiDriverEntryPoint
+ BaseLib
+ BaseMemoryLib
+ TimerLib
+ PcdLib
+
+[Protocols]
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ gEfiPs2PolicyProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2KbdExtendedVerification ## CONSUMES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFastPS2Detection ## SOMETIMES_CONSUMES
+
+#
+# [Event]
+#
+# ##
+# # Timer event used to read key strokes at a regular interval.
+# #
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Ps2KeyboardDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.c
new file mode 100644
index 0000000000..fb4a75348c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.c
@@ -0,0 +1,923 @@
+/** @file
+ PS2 Mouse Communication Interface.
+
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2MouseAbsolutePointer.h"
+#include "CommPs2.h"
+
+UINT8 SampleRateTbl[MaxSampleRate] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
+
+UINT8 ResolutionTbl[MaxResolution] = { 0, 1, 2, 3 };
+
+/**
+ Issue self test command via IsaIo interface.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Keyboard controller self test
+ //
+ Status = Out8042Command (IsaIo, SELF_TEST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Read return code
+ //
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Data != 0x55) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set system flag
+ //
+ Status = Out8042Command (IsaIo, READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042Command (IsaIo, WRITE_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data |= CMD_SYS_FLAG;
+ Status = Out8042Data (IsaIo, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 enable mouse command
+ //
+ return Out8042Command (IsaIo, ENABLE_AUX);
+}
+
+/**
+ Issue command to disable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 disable mouse command
+ //
+ return Out8042Command (IsaIo, DISABLE_AUX);
+}
+
+/**
+ Issue command to enable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 enable keyboard command
+ //
+ return Out8042Command (IsaIo, ENABLE_KB);
+}
+
+/**
+ Issue command to disable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 disable keyboard command
+ //
+ return Out8042Command (IsaIo, DISABLE_KB);
+}
+
+/**
+ Issue command to check keyboard status.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT BOOLEAN *KeyboardEnable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Send command to read KBC command byte
+ //
+ Status = Out8042Command (IsaIo, READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check keyboard enable or not
+ //
+ if ((Data & CMD_KB_STS) == CMD_KB_DIS) {
+ *KeyboardEnable = FALSE;
+ } else {
+ *KeyboardEnable = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to reset keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check BAT Complete Code
+ //
+ if (Data != PS2MOUSE_BAT1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check BAT Complete Code
+ //
+ if (Data != PS2MOUSE_BAT2) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to set mouse's sample rate
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SR SampleRate
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse sample rate
+ //
+ Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_RE Resolution
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse resolution
+ //
+ Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SF Scaling
+ )
+{
+ UINT8 Command;
+
+ Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD);
+
+ //
+ // Send auxiliary command to set mouse scaling data
+ //
+ return Out8042AuxCommand (IsaIo, Command, FALSE);
+}
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send auxiliary command to enable mouse
+ //
+ return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE);
+}
+
+/**
+ Get mouse packet . Only care first 3 bytes
+
+ @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure
+
+ @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
+ @retval EFI_SUCCESS The data packet is gotten successfully.
+
+**/
+EFI_STATUS
+PS2MouseGetPacket (
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev
+ )
+
+{
+ EFI_STATUS Status;
+ BOOLEAN KeyboardEnable;
+ UINT8 Packet[PS2_PACKET_LENGTH];
+ UINT8 Data;
+ UINTN Count;
+ UINTN State;
+ INT16 RelativeMovementX;
+ INT16 RelativeMovementY;
+ BOOLEAN LButton;
+ BOOLEAN RButton;
+
+ KeyboardEnable = FALSE;
+ Count = 1;
+ State = PS2_READ_BYTE_ONE;
+
+ //
+ // State machine to get mouse packet
+ //
+ while (1) {
+
+ switch (State) {
+ case PS2_READ_BYTE_ONE:
+ //
+ // Read mouse first byte data, if failed, immediately return
+ //
+ KbcDisableAux (MouseAbsolutePointerDev->IsaIo);
+ Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, &Data, &Count, State);
+ if (EFI_ERROR (Status)) {
+ KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 1) {
+ KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
+ return EFI_NOT_READY;
+ }
+
+ if (IS_PS2_SYNC_BYTE (Data)) {
+ Packet[0] = Data;
+ State = PS2_READ_DATA_BYTE;
+
+ CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable);
+ KbcDisableKb (MouseAbsolutePointerDev->IsaIo);
+ KbcEnableAux (MouseAbsolutePointerDev->IsaIo);
+ }
+ break;
+
+ case PS2_READ_DATA_BYTE:
+ Count = 2;
+ Status = PS2MouseRead (MouseAbsolutePointerDev->IsaIo, (Packet + 1), &Count, State);
+ if (EFI_ERROR (Status)) {
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 2) {
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ State = PS2_PROCESS_PACKET;
+ break;
+
+ case PS2_PROCESS_PACKET:
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
+ }
+ //
+ // Decode the packet
+ //
+ RelativeMovementX = Packet[1];
+ RelativeMovementY = Packet[2];
+ //
+ // Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0
+ // Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn
+ // Byte 1 | 8 bit X Movement
+ // Byte 2 | 8 bit Y Movement
+ //
+ // X sign bit + 8 bit X Movement : 9-bit signed twos complement integer that presents the relative displacement of the device in the X direction since the last data transmission.
+ // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement.
+ //
+ //
+ // First, Clear X and Y high 8 bits
+ //
+ RelativeMovementX = (INT16) (RelativeMovementX & 0xFF);
+ RelativeMovementY = (INT16) (RelativeMovementY & 0xFF);
+ //
+ // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
+ //
+ if ((Packet[0] & 0x10) != 0) {
+ RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00);
+ }
+ if ((Packet[0] & 0x20) != 0) {
+ RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00);
+ }
+
+
+ RButton = (UINT8) (Packet[0] & 0x2);
+ LButton = (UINT8) (Packet[0] & 0x1);
+
+ //
+ // Update mouse state
+ //
+ MouseAbsolutePointerDev->State.CurrentX += RelativeMovementX;
+ MouseAbsolutePointerDev->State.CurrentY -= RelativeMovementY;
+ MouseAbsolutePointerDev->State.CurrentZ = 0;
+ MouseAbsolutePointerDev->State.ActiveButtons = (UINT8) (LButton || RButton) & 0x3;
+ MouseAbsolutePointerDev->StateChanged = TRUE;
+
+ return EFI_SUCCESS;
+ }
+ }
+}
+
+/**
+ Read data via IsaIo protocol with given number.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Buffer Buffer receive data of mouse
+ @param BufSize The size of buffer
+ @param State Check input or read data
+
+ @return status of reading mouse data.
+**/
+EFI_STATUS
+PS2MouseRead (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT VOID *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ )
+{
+ EFI_STATUS Status;
+ UINTN BytesRead;
+
+ Status = EFI_SUCCESS;
+ BytesRead = 0;
+
+ if (State == PS2_READ_BYTE_ONE) {
+ //
+ // Check input for mouse
+ //
+ Status = CheckForInput (IsaIo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ while (BytesRead < *BufSize) {
+
+ Status = WaitOutputFull (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer);
+
+ BytesRead++;
+ Buffer = (UINT8 *) Buffer + 1;
+ }
+ //
+ // Verify the correct number of bytes read
+ //
+ if (BytesRead == 0 || BytesRead != *BufSize) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ *BufSize = BytesRead;
+ return Status;
+}
+
+//
+// 8042 I/O function
+//
+/**
+ I/O work flow of outing 8042 command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command I/O command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send command
+ //
+ Data = Command;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Temp;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Temp = Data;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ )
+{
+ UINTN Delay;
+ UINT8 Temp;
+
+ Delay = TIMEOUT / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
+
+ //
+ // Check keyboard controller status bit 0(output buffer status)
+ //
+ if ((Temp & KBC_OUTB) == KBC_OUTB) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ Data = WRITE_AUX_DEV;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send auxiliary device command
+ //
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
+
+ //
+ // Read return code
+ //
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Data == PS2_ACK) {
+ //
+ // Receive mouse acknowledge, command send success
+ //
+ return EFI_SUCCESS;
+
+ } else if (Resend) {
+ //
+ // Resend fail
+ //
+ return EFI_DEVICE_ERROR;
+
+ } else if (Data == PS2_RESEND) {
+ //
+ // Resend command
+ //
+ Status = Out8042AuxCommand (IsaIo, Command, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ } else {
+ //
+ // Invalid return code
+ //
+ return EFI_DEVICE_ERROR;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow.
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Temp;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ Temp = WRITE_AUX_DEV;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Temp = Data;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // wait for output data
+ //
+ Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ UINT8 Data;
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status, if it is output buffer full and for auxiliary device
+ //
+ if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow to wait input buffer empty in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout Wating time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status bit 1(input buffer status)
+ //
+ if ((Data & KBC_INPB) == 0) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow to wait output buffer full in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout given time
+
+ @retval EFI_TIMEOUT output is not full in given time
+ @retval EFI_SUCCESS output is full in given time.
+**/
+EFI_STATUS
+WaitOutputFull (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status bit 0(output buffer status)
+ // & bit5(output buffer for auxiliary device)
+ //
+ if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.h b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.h
new file mode 100644
index 0000000000..59d7b51d44
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/CommPs2.h
@@ -0,0 +1,435 @@
+/** @file
+ Using PS2 Mouse to simulation Absolution Pointer Device.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __COMMPS2_H__
+#define __COMMPS2_H__
+
+#define PS2_PACKET_LENGTH 3
+#define PS2_SYNC_MASK 0xc
+#define PS2_SYNC_BYTE 0x8
+
+#define IS_PS2_SYNC_BYTE(byte) ((byte & PS2_SYNC_MASK) == PS2_SYNC_BYTE)
+
+#define PS2_READ_BYTE_ONE 0
+#define PS2_READ_DATA_BYTE 1
+#define PS2_PROCESS_PACKET 2
+
+#define TIMEOUT 50000
+#define BAT_TIMEOUT 500000
+
+//
+// 8042 I/O Port
+//
+#define KBC_DATA_PORT 0x60
+#define KBC_CMD_STS_PORT 0x64
+
+//
+// 8042 Command
+//
+#define READ_CMD_BYTE 0x20
+#define WRITE_CMD_BYTE 0x60
+#define DISABLE_AUX 0xa7
+#define ENABLE_AUX 0xa8
+#define SELF_TEST 0xaa
+#define DISABLE_KB 0xad
+#define ENABLE_KB 0xae
+#define WRITE_AUX_DEV 0xd4
+
+#define CMD_SYS_FLAG 0x04
+#define CMD_KB_STS 0x10
+#define CMD_KB_DIS 0x10
+#define CMD_KB_EN 0x0
+
+//
+// 8042 Auxiliary Device Command
+//
+#define SETSF1_CMD 0xe6
+#define SETSF2_CMD 0xe7
+#define SETRE_CMD 0xe8
+#define READ_CMD 0xeb
+#define SETRM_CMD 0xf0
+#define SETSR_CMD 0xf3
+#define ENABLE_CMD 0xf4
+#define DISABLE_CMD 0xf5
+#define RESET_CMD 0xff
+
+//
+// return code
+//
+#define PS2_ACK 0xfa
+#define PS2_RESEND 0xfe
+#define PS2MOUSE_BAT1 0xaa
+#define PS2MOUSE_BAT2 0x0
+
+//
+// Keyboard Controller Status
+//
+///
+/// Parity Error
+///
+#define KBC_PARE 0x80
+///
+/// General Time Out
+///
+#define KBC_TIM 0x40
+///
+/// Output buffer for auxiliary device (PS/2):
+/// 0 - Holds keyboard data
+/// 1 - Holds data for auxiliary device
+///
+#define KBC_AUXB 0x20
+///
+/// Keyboard lock status:
+/// 0 - keyboard locked
+/// 1 - keyboard free
+///
+#define KBC_KEYL 0x10
+///
+/// Command/Data:
+/// 0 - data byte written via port 60h
+/// 1 - command byte written via port 64h
+///
+#define KBC_CD 0x08
+///
+/// System Flag:
+/// 0 - power-on reset
+/// 1 - self-test successful
+///
+#define KBC_SYSF 0x04
+///
+/// Input Buffer Status :
+/// 0 - input buffer empty
+/// 1 - CPU data in input buffer
+///
+#define KBC_INPB 0x02
+///
+/// Output Buffer Status :
+/// 0 - output buffer empty
+/// 1 - keyboard controller data in output buffer
+///
+#define KBC_OUTB 0x01
+
+/**
+ Issue self test command via IsaIo interface.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to disable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to enable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to disable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to check keyboard status.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT BOOLEAN *KeyboardEnable
+ );
+
+/**
+ Issue command to reset keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to set mouse's sample rate
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SR SampleRate
+ );
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_RE Resolution
+ );
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SF Scaling
+ );
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Get mouse packet . Only care first 3 bytes
+
+ @param MouseAbsolutePointerDev Pointer to PS2 Absolute Pointer Simulation Device Private Data Structure
+
+ @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
+ @retval EFI_SUCCESS The data packet is gotten successfully.
+
+**/
+EFI_STATUS
+PS2MouseGetPacket (
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev
+ );
+
+/**
+ Read data via IsaIo protocol with given number.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Buffer Buffer receive data of mouse
+ @param BufSize The size of buffer
+ @param State Check input or read data
+
+ @return status of reading mouse data.
+**/
+EFI_STATUS
+PS2MouseRead (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT VOID *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ );
+
+//
+// 8042 I/O function
+//
+/**
+ I/O work flow of outing 8042 command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command I/O command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command
+ );
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ );
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ );
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ I/O work flow to wait input buffer empty in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout Wating time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ );
+
+/**
+ I/O work flow to wait output buffer full in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout given time
+
+ @retval EFI_TIMEOUT output is not full in given time
+ @retval EFI_SUCCESS output is full in given time.
+**/
+EFI_STATUS
+WaitOutputFull (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/ComponentName.c
new file mode 100644
index 0000000000..8fbef28985
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/ComponentName.c
@@ -0,0 +1,241 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Ps2 Absolute Pointer Simulation Dxe driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2MouseAbsolutePointer.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPs2MouseAbsolutePointerComponentName = {
+ Ps2MouseAbsolutePointerComponentNameGetDriverName,
+ Ps2MouseAbsolutePointerComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPs2MouseAbsolutePointerComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Ps2MouseAbsolutePointerComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Ps2MouseAbsolutePointerComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPs2MouseAbsolutePointerDriverNameTable[] = {
+ {
+ "eng;en",
+ L"faked PS/2 Touchpad Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseAbsolutePointerComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPs2MouseAbsolutePointerDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPs2MouseAbsolutePointerComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol;
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+ EFI_ISA_IO_PROTOCOL *IsaIoProtocol;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIoProtocol,
+ gPS2MouseAbsolutePointerDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ gPS2MouseAbsolutePointerDriver.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointerProtocol,
+ gPS2MouseAbsolutePointerDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MouseAbsolutePointerDev = PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (AbsolutePointerProtocol);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ MouseAbsolutePointerDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gPs2MouseAbsolutePointerComponentName)
+ );
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.c
new file mode 100644
index 0000000000..7af35bcd11
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.c
@@ -0,0 +1,778 @@
+/** @file
+ A faked PS/2 Absolute Pointer driver. Routines that interacts with callers,
+ conforming to EFI driver model
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2MouseAbsolutePointer.h"
+#include "CommPs2.h"
+
+//
+// DriverBinding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gPS2MouseAbsolutePointerDriver = {
+ PS2MouseAbsolutePointerDriverSupported,
+ PS2MouseAbsolutePointerDriverStart,
+ PS2MouseAbsolutePointerDriverStop,
+ 0x1,
+ NULL,
+ NULL
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a IsaIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Mouse controller
+ //
+ switch (IsaIo->ResourceList->Device.HID) {
+ case EISA_PNP_ID (0xF03):
+ //
+ // Microsoft PS/2 style mouse
+ //
+ case EISA_PNP_ID (0xF13):
+ //
+ // PS/2 Port for PS/2-style Mice
+ //
+ break;
+
+ case EISA_PNP_ID (0x303):
+ //
+ // IBM Enhanced (101/102-key, PS/2 mouse support)
+ //
+ if (IsaIo->ResourceList->Device.UID == 1) {
+ break;
+ }
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a IsaIo protocol, creating
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
+ finally.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS EmptyStatus;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+ UINT8 Data;
+ EFI_TPL OldTpl;
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ StatusCode = 0;
+ MouseAbsolutePointerDev = NULL;
+ IsaIo = NULL;
+
+ //
+ // Open the device path protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+
+ //
+ // Get the ISA I/O Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Raise TPL to avoid keyboard operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Allocate private data
+ //
+ MouseAbsolutePointerDev = AllocateZeroPool (sizeof (PS2_MOUSE_ABSOLUTE_POINTER_DEV));
+ if (MouseAbsolutePointerDev == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Setup the device instance
+ //
+ MouseAbsolutePointerDev->Signature = PS2_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE;
+ MouseAbsolutePointerDev->Handle = Controller;
+ MouseAbsolutePointerDev->SampleRate = SampleRate20;
+ MouseAbsolutePointerDev->Resolution = MouseResolution4;
+ MouseAbsolutePointerDev->Scaling = Scaling1;
+ MouseAbsolutePointerDev->DataPackageSize = 3;
+ MouseAbsolutePointerDev->IsaIo = IsaIo;
+ MouseAbsolutePointerDev->DevicePath = ParentDevicePath;
+
+ //
+ // Resolution = 4 counts/mm
+ //
+ MouseAbsolutePointerDev->Mode.AbsoluteMaxX = 1024;
+ MouseAbsolutePointerDev->Mode.AbsoluteMinX = 0;
+ MouseAbsolutePointerDev->Mode.AbsoluteMaxY = 798;
+ MouseAbsolutePointerDev->Mode.AbsoluteMinY = 0;
+ MouseAbsolutePointerDev->Mode.AbsoluteMaxZ = 0;
+ MouseAbsolutePointerDev->Mode.AbsoluteMinZ = 0;
+ MouseAbsolutePointerDev->Mode.Attributes = 0x03;
+
+ MouseAbsolutePointerDev->AbsolutePointerProtocol.Reset = MouseAbsolutePointerReset;
+ MouseAbsolutePointerDev->AbsolutePointerProtocol.GetState = MouseAbsolutePointerGetState;
+ MouseAbsolutePointerDev->AbsolutePointerProtocol.Mode = &(MouseAbsolutePointerDev->Mode);
+
+ //
+ // Initialize keyboard controller if necessary
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_MOUSE_PC_SELF_TEST,
+ ParentDevicePath
+ );
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+ if ((Data & KBC_SYSF) != KBC_SYSF) {
+ Status = KbcSelfTest (IsaIo);
+ if (EFI_ERROR (Status)) {
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ }
+
+ KbcEnableAux (IsaIo);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT,
+ ParentDevicePath
+ );
+
+ //
+ // Reset the mouse
+ //
+ Status = MouseAbsolutePointerDev->AbsolutePointerProtocol.Reset (
+ &MouseAbsolutePointerDev->AbsolutePointerProtocol,
+ FeaturePcdGet (PcdPs2MouseExtendedVerification)
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // mouse not connected
+ //
+ Status = EFI_SUCCESS;
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED,
+ ParentDevicePath
+ );
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ MouseAbsolutePointerWaitForInput,
+ MouseAbsolutePointerDev,
+ &((MouseAbsolutePointerDev->AbsolutePointerProtocol).WaitForInput)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Setup a periodic timer, used to poll mouse state
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PollMouseAbsolutePointer,
+ MouseAbsolutePointerDev,
+ &MouseAbsolutePointerDev->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Start timer to poll mouse (100 samples per second)
+ //
+ Status = gBS->SetTimer (MouseAbsolutePointerDev->TimerEvent, TimerPeriodic, 100000);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ MouseAbsolutePointerDev->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gPs2MouseAbsolutePointerComponentName.SupportedLanguages,
+ &MouseAbsolutePointerDev->ControllerNameTable,
+ L"Faked PS/2 Touchpad Device",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gPs2MouseAbsolutePointerComponentName2.SupportedLanguages,
+ &MouseAbsolutePointerDev->ControllerNameTable,
+ L"Faked PS/2 Touchpad Device",
+ FALSE
+ );
+
+
+ //
+ // Install protocol interfaces for the mouse device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &MouseAbsolutePointerDev->AbsolutePointerProtocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+ErrorExit:
+
+ KbcDisableAux (IsaIo);
+
+ if (StatusCode != 0) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode,
+ ParentDevicePath
+ );
+ }
+
+ if ((MouseAbsolutePointerDev != NULL) && (MouseAbsolutePointerDev->AbsolutePointerProtocol.WaitForInput != NULL)) {
+ gBS->CloseEvent (MouseAbsolutePointerDev->AbsolutePointerProtocol.WaitForInput);
+ }
+
+ if ((MouseAbsolutePointerDev != NULL) && (MouseAbsolutePointerDev->TimerEvent != NULL)) {
+ gBS->CloseEvent (MouseAbsolutePointerDev->TimerEvent);
+ }
+
+ if ((MouseAbsolutePointerDev != NULL) && (MouseAbsolutePointerDev->ControllerNameTable != NULL)) {
+ FreeUnicodeStringTable (MouseAbsolutePointerDev->ControllerNameTable);
+ }
+ //
+ // Since there will be no timer handler for mouse input any more,
+ // exhaust input data just in case there is still mouse data left
+ //
+ EmptyStatus = EFI_SUCCESS;
+ while (!EFI_ERROR (EmptyStatus)) {
+ EmptyStatus = In8042Data (IsaIo, &Data);
+ }
+
+ if (MouseAbsolutePointerDev != NULL) {
+ FreePool (MouseAbsolutePointerDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_ABSOLUTE_POINTER_PROTOCOL *AbsolutePointerProtocol;
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+ UINT8 Data;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ (VOID **) &AbsolutePointerProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ MouseAbsolutePointerDev = PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (AbsolutePointerProtocol);
+
+ //
+ // Report that the keyboard is being disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE,
+ MouseAbsolutePointerDev->DevicePath
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiAbsolutePointerProtocolGuid,
+ &MouseAbsolutePointerDev->AbsolutePointerProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Cancel mouse data polling timer, close timer event
+ //
+ gBS->SetTimer (MouseAbsolutePointerDev->TimerEvent, TimerCancel, 0);
+ gBS->CloseEvent (MouseAbsolutePointerDev->TimerEvent);
+
+ //
+ // Since there will be no timer handler for mouse input any more,
+ // exhaust input data just in case there is still mouse data left
+ //
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status)) {
+ Status = In8042Data (MouseAbsolutePointerDev->IsaIo, &Data);
+ }
+
+ gBS->CloseEvent (MouseAbsolutePointerDev->AbsolutePointerProtocol.WaitForInput);
+ FreeUnicodeStringTable (MouseAbsolutePointerDev->ControllerNameTable);
+ FreePool (MouseAbsolutePointerDev);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
+
+
+ @retval EFI_SUCCESS - The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+MouseAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+ EFI_TPL OldTpl;
+ BOOLEAN KeyboardEnable;
+ UINT8 Data;
+
+ MouseAbsolutePointerDev = PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This);
+
+ //
+ // Report reset progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET,
+ MouseAbsolutePointerDev->DevicePath
+ );
+
+ KeyboardEnable = FALSE;
+
+ //
+ // Raise TPL to avoid keyboard operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ ZeroMem (&MouseAbsolutePointerDev->State, sizeof (EFI_ABSOLUTE_POINTER_STATE));
+ MouseAbsolutePointerDev->StateChanged = FALSE;
+
+ //
+ // Exhaust input data
+ //
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status)) {
+ Status = In8042Data (MouseAbsolutePointerDev->IsaIo, &Data);
+ }
+
+ CheckKbStatus (MouseAbsolutePointerDev->IsaIo, &KeyboardEnable);
+
+ KbcDisableKb (MouseAbsolutePointerDev->IsaIo);
+
+ MouseAbsolutePointerDev->IsaIo->Io.Read (MouseAbsolutePointerDev->IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // if there's data block on KBC data port, read it out
+ //
+ if ((Data & KBC_OUTB) == KBC_OUTB) {
+ MouseAbsolutePointerDev->IsaIo->Io.Read (MouseAbsolutePointerDev->IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Data);
+ }
+
+ Status = EFI_SUCCESS;
+ //
+ // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
+ // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
+ // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
+ //
+ if (ExtendedVerification && CheckMouseAbsolutePointerConnect (MouseAbsolutePointerDev)) {
+ //
+ // Send mouse reset command and set mouse default configure
+ //
+ Status = PS2MouseReset (MouseAbsolutePointerDev->IsaIo);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetSampleRate (MouseAbsolutePointerDev->IsaIo, MouseAbsolutePointerDev->SampleRate);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetResolution (MouseAbsolutePointerDev->IsaIo, MouseAbsolutePointerDev->Resolution);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetScaling (MouseAbsolutePointerDev->IsaIo, MouseAbsolutePointerDev->Scaling);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseEnable (MouseAbsolutePointerDev->IsaIo);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseAbsolutePointerDev->IsaIo);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether there is Ps/2 mouse device in system
+
+ @param MouseAbsolutePointerDev - Absolute Pointer Device Private Data Structure
+
+ @retval TRUE - Keyboard in System.
+ @retval FALSE - Keyboard not in System.
+
+**/
+BOOLEAN
+CheckMouseAbsolutePointerConnect (
+ IN PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev
+ )
+
+{
+ EFI_STATUS Status;
+
+ Status = PS2MouseEnable (MouseAbsolutePointerDev->IsaIo);
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get and Clear mouse status.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param State - Output buffer holding status.
+
+ @retval EFI_INVALID_PARAMETER Output buffer is invalid.
+ @retval EFI_NOT_READY Mouse is not changed status yet.
+ @retval EFI_SUCCESS Mouse status is changed and get successful.
+**/
+EFI_STATUS
+EFIAPI
+MouseAbsolutePointerGetState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN OUT EFI_ABSOLUTE_POINTER_STATE *State
+ )
+{
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+ EFI_TPL OldTpl;
+
+ MouseAbsolutePointerDev = PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS (This);
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!MouseAbsolutePointerDev->StateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ CopyMem (State, &(MouseAbsolutePointerDev->State), sizeof (EFI_ABSOLUTE_POINTER_STATE));
+
+ //
+ // clear mouse state
+ //
+ MouseAbsolutePointerDev->State.CurrentX = 0;
+ MouseAbsolutePointerDev->State.CurrentY = 0;
+ MouseAbsolutePointerDev->State.CurrentZ = 0;
+ MouseAbsolutePointerDev->State.ActiveButtons = 0x0;
+ MouseAbsolutePointerDev->StateChanged = FALSE;
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Event notification function for SIMPLE_POINTER.WaitForInput event.
+ Signal the event if there is input from mouse.
+
+ @param Event event object
+ @param Context event context
+
+**/
+VOID
+EFIAPI
+MouseAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+
+ MouseAbsolutePointerDev = (PS2_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ //
+ // Someone is waiting on the mouse event, if there's
+ // input from mouse, signal the event
+ //
+ if (MouseAbsolutePointerDev->StateChanged) {
+ gBS->SignalEvent (Event);
+ }
+
+}
+
+/**
+ Event notification function for TimerEvent event.
+ If mouse device is connected to system, try to get the mouse packet data.
+
+ @param Event - TimerEvent in PS2_MOUSE_DEV
+ @param Context - Pointer to PS2_MOUSE_DEV structure
+
+**/
+VOID
+EFIAPI
+PollMouseAbsolutePointer(
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+
+{
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev;
+
+ MouseAbsolutePointerDev = (PS2_MOUSE_ABSOLUTE_POINTER_DEV *) Context;
+
+ //
+ // Polling mouse packet data
+ //
+ PS2MouseGetPacket (MouseAbsolutePointerDev);
+}
+
+/**
+ The user Entry Point for module Ps2MouseAbsolutePointer. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePs2MouseAbsolutePointer(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPS2MouseAbsolutePointerDriver,
+ ImageHandle,
+ &gPs2MouseAbsolutePointerComponentName,
+ &gPs2MouseAbsolutePointerComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.h b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.h
new file mode 100644
index 0000000000..a4e2174a4c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointer.h
@@ -0,0 +1,400 @@
+/** @file
+ A Ps2MouseAbsolutePointer driver header file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PS2MOUSEABSOLUTEPOINTER_H__
+#define __PS2MOUSEABSOLUTEPOINTER_H__
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/AbsolutePointer.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPS2MouseAbsolutePointerDriver;
+extern EFI_COMPONENT_NAME_PROTOCOL gPs2MouseAbsolutePointerComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPs2MouseAbsolutePointerComponentName2;
+
+//
+// PS/2 mouse sample rate
+//
+typedef enum {
+ SampleRate10,
+ SampleRate20,
+ SampleRate40,
+ SampleRate60,
+ SampleRate80,
+ SampleRate100,
+ SampleRate200,
+ MaxSampleRate
+} MOUSE_SR;
+
+//
+// PS/2 mouse resolution
+//
+typedef enum {
+ MouseResolution1,
+ MouseResolution2,
+ MouseResolution4,
+ MouseResolution8,
+ MaxResolution
+} MOUSE_RE;
+
+//
+// PS/2 mouse scaling
+//
+typedef enum {
+ Scaling1,
+ Scaling2
+} MOUSE_SF;
+
+//
+// Driver Private Data
+//
+#define PS2_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE SIGNATURE_32 ('p', '2', 's', 't')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_ABSOLUTE_POINTER_PROTOCOL AbsolutePointerProtocol;
+ EFI_ABSOLUTE_POINTER_STATE State;
+ EFI_ABSOLUTE_POINTER_MODE Mode;
+ BOOLEAN StateChanged;
+
+ //
+ // PS2 Mouse device specific information
+ //
+ MOUSE_SR SampleRate;
+ MOUSE_RE Resolution;
+ MOUSE_SF Scaling;
+ UINT8 DataPackageSize;
+
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ EFI_EVENT TimerEvent;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} PS2_MOUSE_ABSOLUTE_POINTER_DEV;
+
+#define PS2_MOUSE_ABSOLUTE_POINTER_DEV_FROM_THIS(a) CR (a, PS2_MOUSE_ABSOLUTE_POINTER_DEV, AbsolutePointerProtocol, PS2_MOUSE_ABSOLUTE_POINTER_DEV_SIGNATURE)
+
+//
+// Function prototypes
+//
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a IsaIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a IsaIo
+ protocol, creating PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
+ finnally.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseAbsolutePointerDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseAbsolutePointerComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseAbsolutePointerComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
+
+
+ @retval EFI_SUCCESS - The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+MouseAbsolutePointerReset (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get and Clear mouse status.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param State - Output buffer holding status.
+
+ @retval EFI_INVALID_PARAMETER Output buffer is invalid.
+ @retval EFI_NOT_READY Mouse is not changed status yet.
+ @retval EFI_SUCCESS Mouse status is changed and get successful.
+**/
+EFI_STATUS
+EFIAPI
+MouseAbsolutePointerGetState (
+ IN EFI_ABSOLUTE_POINTER_PROTOCOL *This,
+ IN OUT EFI_ABSOLUTE_POINTER_STATE *State
+ );
+
+/**
+
+ Event notification function for SIMPLE_POINTER.WaitForInput event.
+ Signal the event if there is input from mouse.
+
+ @param Event event object
+ @param Context event context
+
+**/
+VOID
+EFIAPI
+MouseAbsolutePointerWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification function for TimerEvent event.
+ If mouse device is connected to system, try to get the mouse packet data.
+
+ @param Event - TimerEvent in PS2_MOUSE_DEV
+ @param Context - Pointer to PS2_MOUSE_DEV structure
+
+**/
+VOID
+EFIAPI
+PollMouseAbsolutePointer (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ Check whether there is Ps/2 mouse device in system
+
+ @param MouseAbsolutePointerDev - Absolute Pointer Device Private Data Structure
+
+ @retval TRUE - Keyboard in System.
+ @retval FALSE - Keyboard not in System.
+
+**/
+BOOLEAN
+CheckMouseAbsolutePointerConnect (
+ IN PS2_MOUSE_ABSOLUTE_POINTER_DEV *MouseAbsolutePointerDev
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf
new file mode 100644
index 0000000000..be16671a2f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# PS2 Mouse driver providing absolute (touch pad) pointer support.
+#
+# This driver simulates a touch pad absolute pointing device using a standard
+# PS2 mouse as the input hardware.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ps2MouseAbsolutePointerDxe
+ MODULE_UNI_FILE = Ps2MouseAbsolutePointerDxe.uni
+ FILE_GUID = 2899C94A-1FB6-4b1a-B96B-8364975303E0
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePs2MouseAbsolutePointer
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gPS2MouseAbsolutePointerDriver;
+# COMPONENT_NAME = gPs2MouseAbsolutePointerComponentName;
+# COMPONENT_NAME2 = gPs2MouseAbsolutePointerComponentName2;
+#
+
+[Sources]
+ ComponentName.c
+ CommPs2.h
+ CommPs2.c
+ Ps2MouseAbsolutePointer.h
+ Ps2MouseAbsolutePointer.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiAbsolutePointerProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2MouseExtendedVerification ## CONSUMES
+
+#
+# [Event]
+#
+# ##
+# # Timer event used to check the mouse state at a regular interval.
+# #
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Ps2MouseAbsolutePointerDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.uni
new file mode 100644
index 0000000000..22f885d660
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxeExtra.uni
new file mode 100644
index 0000000000..d5d7de237b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c
new file mode 100644
index 0000000000..1c763e97f3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.c
@@ -0,0 +1,921 @@
+/** @file
+ PS2 Mouse Communication Interface.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Mouse.h"
+#include "CommPs2.h"
+
+UINT8 SampleRateTbl[MaxSampleRate] = { 0xa, 0x14, 0x28, 0x3c, 0x50, 0x64, 0xc8 };
+
+UINT8 ResolutionTbl[MaxResolution] = { 0, 1, 2, 3 };
+
+/**
+ Issue self test command via IsaIo interface.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Keyboard controller self test
+ //
+ Status = Out8042Command (IsaIo, SELF_TEST);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Read return code
+ //
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Data != 0x55) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Set system flag
+ //
+ Status = Out8042Command (IsaIo, READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042Command (IsaIo, WRITE_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Data |= CMD_SYS_FLAG;
+ Status = Out8042Data (IsaIo, Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 enable mouse command
+ //
+ return Out8042Command (IsaIo, ENABLE_AUX);
+}
+
+/**
+ Issue command to disable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 disable mouse command
+ //
+ return Out8042Command (IsaIo, DISABLE_AUX);
+}
+
+/**
+ Issue command to enable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 enable keyboard command
+ //
+ return Out8042Command (IsaIo, ENABLE_KB);
+}
+
+/**
+ Issue command to disable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send 8042 disable keyboard command
+ //
+ return Out8042Command (IsaIo, DISABLE_KB);
+}
+
+/**
+ Issue command to check keyboard status.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT BOOLEAN *KeyboardEnable
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Send command to read KBC command byte
+ //
+ Status = Out8042Command (IsaIo, READ_CMD_BYTE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042Data (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check keyboard enable or not
+ //
+ if ((Data & CMD_KB_STS) == CMD_KB_DIS) {
+ *KeyboardEnable = FALSE;
+ } else {
+ *KeyboardEnable = TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to reset keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ Status = Out8042AuxCommand (IsaIo, RESET_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check BAT Complete Code
+ //
+ if (Data != PS2MOUSE_BAT1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check BAT Complete Code
+ //
+ if (Data != PS2MOUSE_BAT2) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Issue command to set mouse's sample rate
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SR SampleRate
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse sample rate
+ //
+ Status = Out8042AuxCommand (IsaIo, SETSR_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (IsaIo, SampleRateTbl[SampleRate]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_RE Resolution
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Send auxiliary command to set mouse resolution
+ //
+ Status = Out8042AuxCommand (IsaIo, SETRE_CMD, FALSE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = Out8042AuxData (IsaIo, ResolutionTbl[Resolution]);
+
+ return Status;
+}
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SF Scaling
+ )
+{
+ UINT8 Command;
+
+ Command = (UINT8) (Scaling == Scaling1 ? SETSF1_CMD : SETSF2_CMD);
+
+ //
+ // Send auxiliary command to set mouse scaling data
+ //
+ return Out8042AuxCommand (IsaIo, Command, FALSE);
+}
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ //
+ // Send auxiliary command to enable mouse
+ //
+ return Out8042AuxCommand (IsaIo, ENABLE_CMD, FALSE);
+}
+
+/**
+ Get mouse packet . Only care first 3 bytes
+
+ @param MouseDev Pointer of PS2 Mouse Private Data Structure
+
+ @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
+ @retval EFI_SUCCESS The data packet is gotten successfully.
+
+**/
+EFI_STATUS
+PS2MouseGetPacket (
+ PS2_MOUSE_DEV *MouseDev
+ )
+
+{
+ EFI_STATUS Status;
+ BOOLEAN KeyboardEnable;
+ UINT8 Packet[PS2_PACKET_LENGTH];
+ UINT8 Data;
+ UINTN Count;
+ UINTN State;
+ INT16 RelativeMovementX;
+ INT16 RelativeMovementY;
+ BOOLEAN LButton;
+ BOOLEAN RButton;
+
+ KeyboardEnable = FALSE;
+ Count = 1;
+ State = PS2_READ_BYTE_ONE;
+
+ //
+ // State machine to get mouse packet
+ //
+ while (1) {
+
+ switch (State) {
+ case PS2_READ_BYTE_ONE:
+ //
+ // Read mouse first byte data, if failed, immediately return
+ //
+ KbcDisableAux (MouseDev->IsaIo);
+ Status = PS2MouseRead (MouseDev->IsaIo, &Data, &Count, State);
+ if (EFI_ERROR (Status)) {
+ KbcEnableAux (MouseDev->IsaIo);
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 1) {
+ KbcEnableAux (MouseDev->IsaIo);
+ return EFI_NOT_READY;
+ }
+
+ if (IS_PS2_SYNC_BYTE (Data)) {
+ Packet[0] = Data;
+ State = PS2_READ_DATA_BYTE;
+
+ CheckKbStatus (MouseDev->IsaIo, &KeyboardEnable);
+ KbcDisableKb (MouseDev->IsaIo);
+ KbcEnableAux (MouseDev->IsaIo);
+ }
+ break;
+
+ case PS2_READ_DATA_BYTE:
+ Count = 2;
+ Status = PS2MouseRead (MouseDev->IsaIo, (Packet + 1), &Count, State);
+ if (EFI_ERROR (Status)) {
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseDev->IsaIo);
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ if (Count != 2) {
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseDev->IsaIo);
+ }
+
+ return EFI_NOT_READY;
+ }
+
+ State = PS2_PROCESS_PACKET;
+ break;
+
+ case PS2_PROCESS_PACKET:
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseDev->IsaIo);
+ }
+ //
+ // Decode the packet
+ //
+ RelativeMovementX = Packet[1];
+ RelativeMovementY = Packet[2];
+ //
+ // Bit 7 | Bit 6 | Bit 5 | Bit 4 | Bit 3 | Bit 2 | Bit 1 | Bit 0
+ // Byte 0 | Y overflow | X overflow | Y sign bit | X sign bit | Always 1 | Middle Btn | Right Btn | Left Btn
+ // Byte 1 | 8 bit X Movement
+ // Byte 2 | 8 bit Y Movement
+ //
+ // X sign bit + 8 bit X Movement : 9-bit signed twos complement integer that presents the relative displacement of the device in the X direction since the last data transmission.
+ // Y sign bit + 8 bit Y Movement : Same as X sign bit + 8 bit X Movement.
+ //
+ //
+ // First, Clear X and Y high 8 bits
+ //
+ RelativeMovementX = (INT16) (RelativeMovementX & 0xFF);
+ RelativeMovementY = (INT16) (RelativeMovementY & 0xFF);
+ //
+ // Second, if the 9-bit signed twos complement integer is negative, set the high 8 bit 0xff
+ //
+ if ((Packet[0] & 0x10) != 0) {
+ RelativeMovementX = (INT16) (RelativeMovementX | 0xFF00);
+ }
+ if ((Packet[0] & 0x20) != 0) {
+ RelativeMovementY = (INT16) (RelativeMovementY | 0xFF00);
+ }
+
+
+ RButton = (UINT8) (Packet[0] & 0x2);
+ LButton = (UINT8) (Packet[0] & 0x1);
+
+ //
+ // Update mouse state
+ //
+ MouseDev->State.RelativeMovementX += RelativeMovementX;
+ MouseDev->State.RelativeMovementY -= RelativeMovementY;
+ MouseDev->State.RightButton = (UINT8) (RButton ? TRUE : FALSE);
+ MouseDev->State.LeftButton = (UINT8) (LButton ? TRUE : FALSE);
+ MouseDev->StateChanged = TRUE;
+
+ return EFI_SUCCESS;
+ }
+ }
+}
+
+/**
+ Read data via IsaIo protocol with given number.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Buffer Buffer receive data of mouse
+ @param BufSize The size of buffer
+ @param State Check input or read data
+
+ @return status of reading mouse data.
+**/
+EFI_STATUS
+PS2MouseRead (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT VOID *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ )
+{
+ EFI_STATUS Status;
+ UINTN BytesRead;
+
+ Status = EFI_SUCCESS;
+ BytesRead = 0;
+
+ if (State == PS2_READ_BYTE_ONE) {
+ //
+ // Check input for mouse
+ //
+ Status = CheckForInput (IsaIo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ while (BytesRead < *BufSize) {
+
+ Status = WaitOutputFull (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Buffer);
+
+ BytesRead++;
+ Buffer = (UINT8 *) Buffer + 1;
+ }
+ //
+ // Verify the correct number of bytes read
+ //
+ if (BytesRead == 0 || BytesRead != *BufSize) {
+ Status = EFI_NOT_FOUND;
+ }
+
+ *BufSize = BytesRead;
+ return Status;
+}
+//
+// 8042 I/O function
+//
+/**
+ I/O work flow of outing 8042 command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command I/O command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send command
+ //
+ Data = Command;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Temp;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Temp = Data;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ )
+{
+ UINTN Delay;
+ UINT8 Temp;
+
+ Delay = TIMEOUT / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
+
+ //
+ // Check keyboard controller status bit 0(output buffer status)
+ //
+ if ((Temp & KBC_OUTB) == KBC_OUTB) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Data;
+
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ Data = WRITE_AUX_DEV;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send auxiliary device command
+ //
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Command);
+
+ //
+ // Read return code
+ //
+ Status = In8042AuxData (IsaIo, &Data);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Data == PS2_ACK) {
+ //
+ // Receive mouse acknowledge, command send success
+ //
+ return EFI_SUCCESS;
+
+ } else if (Resend) {
+ //
+ // Resend fail
+ //
+ return EFI_DEVICE_ERROR;
+
+ } else if (Data == PS2_RESEND) {
+ //
+ // Resend command
+ //
+ Status = Out8042AuxCommand (IsaIo, Command, TRUE);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ } else {
+ //
+ // Invalid return code
+ //
+ return EFI_DEVICE_ERROR;
+
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of outing 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Temp;
+ //
+ // Wait keyboard controller input buffer empty
+ //
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Send write to auxiliary device command
+ //
+ Temp = WRITE_AUX_DEV;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Temp = Data;
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Temp);
+
+ Status = WaitInputEmpty (IsaIo, TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // wait for output data
+ //
+ Status = WaitOutputFull (IsaIo, BAT_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, Data);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ )
+{
+ UINT8 Data;
+
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status, if it is output buffer full and for auxiliary device
+ //
+ if ((Data & (KBC_OUTB | KBC_AUXB)) != (KBC_OUTB | KBC_AUXB)) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow to wait input buffer empty in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout Wating time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status bit 1(input buffer status)
+ //
+ if ((Data & KBC_INPB) == 0) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ I/O work flow to wait output buffer full in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout given time
+
+ @retval EFI_TIMEOUT output is not full in given time
+ @retval EFI_SUCCESS output is full in given time.
+**/
+EFI_STATUS
+WaitOutputFull (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ )
+{
+ UINTN Delay;
+ UINT8 Data;
+
+ Delay = Timeout / 50;
+
+ do {
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // Check keyboard controller status bit 0(output buffer status)
+ // & bit5(output buffer for auxiliary device)
+ //
+ if ((Data & (KBC_OUTB | KBC_AUXB)) == (KBC_OUTB | KBC_AUXB)) {
+ break;
+ }
+
+ gBS->Stall (50);
+ Delay--;
+ } while (Delay != 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h
new file mode 100644
index 0000000000..a48ee8cb09
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/CommPs2.h
@@ -0,0 +1,435 @@
+/** @file
+ PS2 Mouse Communication Interface
+
+Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _COMMPS2_H_
+#define _COMMPS2_H_
+
+#define PS2_PACKET_LENGTH 3
+#define PS2_SYNC_MASK 0xc
+#define PS2_SYNC_BYTE 0x8
+
+#define IS_PS2_SYNC_BYTE(byte) ((byte & PS2_SYNC_MASK) == PS2_SYNC_BYTE)
+
+#define PS2_READ_BYTE_ONE 0
+#define PS2_READ_DATA_BYTE 1
+#define PS2_PROCESS_PACKET 2
+
+#define TIMEOUT 50000
+#define BAT_TIMEOUT 500000
+
+//
+// 8042 I/O Port
+//
+#define KBC_DATA_PORT 0x60
+#define KBC_CMD_STS_PORT 0x64
+
+//
+// 8042 Command
+//
+#define READ_CMD_BYTE 0x20
+#define WRITE_CMD_BYTE 0x60
+#define DISABLE_AUX 0xa7
+#define ENABLE_AUX 0xa8
+#define SELF_TEST 0xaa
+#define DISABLE_KB 0xad
+#define ENABLE_KB 0xae
+#define WRITE_AUX_DEV 0xd4
+
+#define CMD_SYS_FLAG 0x04
+#define CMD_KB_STS 0x10
+#define CMD_KB_DIS 0x10
+#define CMD_KB_EN 0x0
+
+//
+// 8042 Auxiliary Device Command
+//
+#define SETSF1_CMD 0xe6
+#define SETSF2_CMD 0xe7
+#define SETRE_CMD 0xe8
+#define READ_CMD 0xeb
+#define SETRM_CMD 0xf0
+#define SETSR_CMD 0xf3
+#define ENABLE_CMD 0xf4
+#define DISABLE_CMD 0xf5
+#define RESET_CMD 0xff
+
+//
+// return code
+//
+#define PS2_ACK 0xfa
+#define PS2_RESEND 0xfe
+#define PS2MOUSE_BAT1 0xaa
+#define PS2MOUSE_BAT2 0x0
+
+//
+// Keyboard Controller Status
+//
+///
+/// Parity Error
+///
+#define KBC_PARE 0x80
+///
+/// General Time Out
+///
+#define KBC_TIM 0x40
+///
+/// Output buffer for auxiliary device (PS/2):
+/// 0 - Holds keyboard data
+/// 1 - Holds data for auxiliary device
+///
+#define KBC_AUXB 0x20
+///
+/// Keyboard lock status:
+/// 0 - keyboard locked
+/// 1 - keyboard free
+///
+#define KBC_KEYL 0x10
+///
+/// Command/Data:
+/// 0 - data byte written via port 60h
+/// 1 - command byte written via port 64h
+///
+#define KBC_CD 0x08
+///
+/// System Flag:
+/// 0 - power-on reset
+/// 1 - self-test successful
+///
+#define KBC_SYSF 0x04
+///
+/// Input Buffer Status :
+/// 0 - input buffer empty
+/// 1 - CPU data in input buffer
+///
+#define KBC_INPB 0x02
+///
+/// Output Buffer Status :
+/// 0 - output buffer empty
+/// 1 - keyboard controller data in output buffer
+///
+#define KBC_OUTB 0x01
+
+/**
+ Issue self test command via IsaIo interface.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return EFI_SUCCESS Success to do keyboard self testing.
+ @return others Fail to do keyboard self testing.
+**/
+EFI_STATUS
+KbcSelfTest (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to enable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to disable keyboard AUX functionality.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableAux (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to enable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcEnableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to disable keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+KbcDisableKb (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to check keyboard status.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param KeyboardEnable return whether keyboard is enable.
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+CheckKbStatus (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT BOOLEAN *KeyboardEnable
+ );
+
+/**
+ Issue command to reset keyboard.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseReset (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Issue command to set mouse's sample rate
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param SampleRate value of sample rate
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetSampleRate (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SR SampleRate
+ );
+
+/**
+ Issue command to set mouse's resolution.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Resolution value of resolution
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetResolution (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_RE Resolution
+ );
+
+/**
+ Issue command to set mouse's scaling.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Scaling value of scaling
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseSetScaling (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN MOUSE_SF Scaling
+ );
+
+/**
+ Issue command to enable Ps2 mouse.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @return Status of command issuing.
+**/
+EFI_STATUS
+PS2MouseEnable (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ Get mouse packet . Only care first 3 bytes
+
+ @param MouseDev Pointer of PS2 Mouse Private Data Structure
+
+ @retval EFI_NOT_READY Mouse Device not ready to input data packet, or some error happened during getting the packet
+ @retval EFI_SUCCESS The data packet is gotten successfully.
+
+**/
+EFI_STATUS
+PS2MouseGetPacket (
+ PS2_MOUSE_DEV *MouseDev
+ );
+
+/**
+ Read data via IsaIo protocol with given number.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Buffer Buffer receive data of mouse
+ @param BufSize The size of buffer
+ @param State Check input or read data
+
+ @return status of reading mouse data.
+**/
+EFI_STATUS
+PS2MouseRead (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ OUT VOID *Buffer,
+ IN OUT UINTN *BufSize,
+ IN UINTN State
+ );
+
+//
+// 8042 I/O function
+//
+/**
+ I/O work flow of outing 8042 command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command I/O command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Command (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command
+ );
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux command.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Command Aux I/O command
+ @param Resend Whether need resend the Aux command.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxCommand (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Command,
+ IN BOOLEAN Resend
+ );
+
+/**
+ I/O work flow of in 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value.
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ I/O work flow of outing 8042 Aux data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Buffer holding return value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+Out8042AuxData (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINT8 Data
+ );
+
+/**
+ Check keyboard controller status, if it is output buffer full and for auxiliary device.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+
+ @retval EFI_SUCCESS Keyboard controller is ready
+ @retval EFI_NOT_READY Keyboard controller is not ready
+**/
+EFI_STATUS
+CheckForInput (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo
+ );
+
+/**
+ I/O work flow to wait input buffer empty in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout Wating time.
+
+ @retval EFI_TIMEOUT if input is still not empty in given time.
+ @retval EFI_SUCCESS input is empty.
+**/
+EFI_STATUS
+WaitInputEmpty (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ );
+
+/**
+ I/O work flow to wait output buffer full in given time.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Timeout given time
+
+ @retval EFI_TIMEOUT output is not full in given time
+ @retval EFI_SUCCESS output is full in given time.
+**/
+EFI_STATUS
+WaitOutputFull (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN UINTN Timeout
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c
new file mode 100644
index 0000000000..1c3e84ec6d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/ComponentName.c
@@ -0,0 +1,241 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for Ps2MouseDxe driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Mouse.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPs2MouseComponentName = {
+ Ps2MouseComponentNameGetDriverName,
+ Ps2MouseComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPs2MouseComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) Ps2MouseComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) Ps2MouseComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPs2MouseDriverNameTable[] = {
+ {
+ "eng;en",
+ L"PS/2 Mouse Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPs2MouseDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPs2MouseComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
+ PS2_MOUSE_DEV *MouseDev;
+ EFI_ISA_IO_PROTOCOL *IsaIoProtocol;
+
+ //
+ // This is a device driver, so ChildHandle must be NULL.
+ //
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Check Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIoProtocol,
+ gPS2MouseDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ ControllerHandle,
+ &gEfiIsaIoProtocolGuid,
+ gPS2MouseDriver.DriverBindingHandle,
+ ControllerHandle
+ );
+
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Status != EFI_ALREADY_STARTED) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device context
+ //
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointerProtocol,
+ gPS2MouseDriver.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ MouseDev = PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ MouseDev->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gPs2MouseComponentName)
+ );
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c
new file mode 100644
index 0000000000..1623201876
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.c
@@ -0,0 +1,792 @@
+/** @file
+ PS/2 Mouse driver. Routines that interacts with callers,
+ conforming to EFI driver model.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Ps2Mouse.h"
+#include "CommPs2.h"
+
+///
+/// DriverBinding Protocol Instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver = {
+ PS2MouseDriverSupported,
+ PS2MouseDriverStart,
+ PS2MouseDriverStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a IsaIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
+ //
+ switch (IsaIo->ResourceList->Device.HID) {
+ case EISA_PNP_ID (0xF03):
+ //
+ // Microsoft PS/2 style mouse
+ //
+ case EISA_PNP_ID (0xF13):
+ //
+ // PS/2 Port for PS/2-style Mice
+ //
+ break;
+
+ case EISA_PNP_ID (0x303):
+ //
+ // IBM Enhanced (101/102-key, PS/2 mouse support)
+ //
+ if (IsaIo->ResourceList->Device.UID == 1) {
+ break;
+ }
+
+ default:
+ Status = EFI_UNSUPPORTED;
+ break;
+ }
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Start this driver on ControllerHandle by opening a IsaIo protocol, creating
+ PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
+ finally.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS EmptyStatus;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ PS2_MOUSE_DEV *MouseDev;
+ UINT8 Data;
+ EFI_TPL OldTpl;
+ EFI_STATUS_CODE_VALUE StatusCode;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+
+ StatusCode = 0;
+ MouseDev = NULL;
+ IsaIo = NULL;
+
+ //
+ // Open the device path protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+
+ //
+ // Get the ISA I/O Protocol on Controller's handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Raise TPL to avoid keyboard operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Allocate private data
+ //
+ MouseDev = AllocateZeroPool (sizeof (PS2_MOUSE_DEV));
+ if (MouseDev == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Setup the device instance
+ //
+ MouseDev->Signature = PS2_MOUSE_DEV_SIGNATURE;
+ MouseDev->Handle = Controller;
+ MouseDev->SampleRate = SampleRate20;
+ MouseDev->Resolution = MouseResolution4;
+ MouseDev->Scaling = Scaling1;
+ MouseDev->DataPackageSize = 3;
+ MouseDev->IsaIo = IsaIo;
+ MouseDev->DevicePath = ParentDevicePath;
+
+ //
+ // Resolution = 4 counts/mm
+ //
+ MouseDev->Mode.ResolutionX = 4;
+ MouseDev->Mode.ResolutionY = 4;
+ MouseDev->Mode.LeftButton = TRUE;
+ MouseDev->Mode.RightButton = TRUE;
+
+ MouseDev->SimplePointerProtocol.Reset = MouseReset;
+ MouseDev->SimplePointerProtocol.GetState = MouseGetState;
+ MouseDev->SimplePointerProtocol.Mode = &(MouseDev->Mode);
+
+ //
+ // Initialize keyboard controller if necessary
+ //
+ IsaIo->Io.Read (IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+ //
+ // Fix for random hangs in System waiting for the Key if no KBC is present in BIOS.
+ //
+ if ((Data & (KBC_PARE | KBC_TIM)) == (KBC_PARE | KBC_TIM)) {
+ //
+ // If nobody decodes KBC I/O port, it will read back as 0xFF.
+ // Check the Time-Out and Parity bit to see if it has an active KBC in system
+ //
+ Status = EFI_DEVICE_ERROR;
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_MOUSE_PC_SELF_TEST,
+ ParentDevicePath
+ );
+
+ if ((Data & KBC_SYSF) != KBC_SYSF) {
+ Status = KbcSelfTest (IsaIo);
+ if (EFI_ERROR (Status)) {
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_CONTROLLER_ERROR;
+ goto ErrorExit;
+ }
+ }
+
+ KbcEnableAux (IsaIo);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_PRESENCE_DETECT,
+ ParentDevicePath
+ );
+
+ //
+ // Reset the mouse
+ //
+ Status = MouseDev->SimplePointerProtocol.Reset (
+ &MouseDev->SimplePointerProtocol,
+ FeaturePcdGet (PcdPs2MouseExtendedVerification)
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // mouse not connected
+ //
+ Status = EFI_SUCCESS;
+ StatusCode = EFI_PERIPHERAL_MOUSE | EFI_P_EC_NOT_DETECTED;
+ goto ErrorExit;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_DETECTED,
+ ParentDevicePath
+ );
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ MouseWaitForInput,
+ MouseDev,
+ &((MouseDev->SimplePointerProtocol).WaitForInput)
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Setup a periodic timer, used to poll mouse state
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ PollMouse,
+ MouseDev,
+ &MouseDev->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+ //
+ // Start timer to poll mouse (100 samples per second)
+ //
+ Status = gBS->SetTimer (MouseDev->TimerEvent, TimerPeriodic, 100000);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ MouseDev->ControllerNameTable = NULL;
+ AddUnicodeString2 (
+ "eng",
+ gPs2MouseComponentName.SupportedLanguages,
+ &MouseDev->ControllerNameTable,
+ L"PS/2 Mouse Device",
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gPs2MouseComponentName2.SupportedLanguages,
+ &MouseDev->ControllerNameTable,
+ L"PS/2 Mouse Device",
+ FALSE
+ );
+
+
+ //
+ // Install protocol interfaces for the mouse device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimplePointerProtocolGuid,
+ &MouseDev->SimplePointerProtocol,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+ErrorExit:
+
+ if (Status != EFI_DEVICE_ERROR) {
+ KbcDisableAux (IsaIo);
+ }
+
+ if (StatusCode != 0) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode,
+ ParentDevicePath
+ );
+ }
+
+ if ((MouseDev != NULL) && (MouseDev->SimplePointerProtocol.WaitForInput != NULL)) {
+ gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
+ }
+
+ if ((MouseDev != NULL) && (MouseDev->TimerEvent != NULL)) {
+ gBS->CloseEvent (MouseDev->TimerEvent);
+ }
+
+ if ((MouseDev != NULL) && (MouseDev->ControllerNameTable != NULL)) {
+ FreeUnicodeStringTable (MouseDev->ControllerNameTable);
+ }
+
+ if (Status != EFI_DEVICE_ERROR) {
+ //
+ // Since there will be no timer handler for mouse input any more,
+ // exhaust input data just in case there is still mouse data left
+ //
+ EmptyStatus = EFI_SUCCESS;
+ while (!EFI_ERROR (EmptyStatus)) {
+ EmptyStatus = In8042Data (IsaIo, &Data);
+ }
+ }
+
+ if (MouseDev != NULL) {
+ FreePool (MouseDev);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_POINTER_PROTOCOL *SimplePointerProtocol;
+ PS2_MOUSE_DEV *MouseDev;
+ UINT8 Data;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimplePointerProtocolGuid,
+ (VOID **) &SimplePointerProtocol,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ MouseDev = PS2_MOUSE_DEV_FROM_THIS (SimplePointerProtocol);
+
+ //
+ // Report that the keyboard is being disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_DISABLE,
+ MouseDev->DevicePath
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimplePointerProtocolGuid,
+ &MouseDev->SimplePointerProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Cancel mouse data polling timer, close timer event
+ //
+ gBS->SetTimer (MouseDev->TimerEvent, TimerCancel, 0);
+ gBS->CloseEvent (MouseDev->TimerEvent);
+
+ //
+ // Since there will be no timer handler for mouse input any more,
+ // exhaust input data just in case there is still mouse data left
+ //
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status)) {
+ Status = In8042Data (MouseDev->IsaIo, &Data);
+ }
+
+ gBS->CloseEvent (MouseDev->SimplePointerProtocol.WaitForInput);
+ FreeUnicodeStringTable (MouseDev->ControllerNameTable);
+ FreePool (MouseDev);
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
+
+ @param This - Pointer of simple pointer Protocol.
+ @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
+
+
+ @retval EFI_SUCCESS - The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+MouseReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ PS2_MOUSE_DEV *MouseDev;
+ EFI_TPL OldTpl;
+ BOOLEAN KeyboardEnable;
+ UINT8 Data;
+
+ MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
+
+ //
+ // Report reset progress code
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_MOUSE | EFI_P_PC_RESET,
+ MouseDev->DevicePath
+ );
+
+ KeyboardEnable = FALSE;
+
+ //
+ // Raise TPL to avoid keyboard operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ ZeroMem (&MouseDev->State, sizeof (EFI_SIMPLE_POINTER_STATE));
+ MouseDev->StateChanged = FALSE;
+
+ //
+ // Exhaust input data
+ //
+ Status = EFI_SUCCESS;
+ while (!EFI_ERROR (Status)) {
+ Status = In8042Data (MouseDev->IsaIo, &Data);
+ }
+
+ CheckKbStatus (MouseDev->IsaIo, &KeyboardEnable);
+
+ KbcDisableKb (MouseDev->IsaIo);
+
+ MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_CMD_STS_PORT, 1, &Data);
+
+ //
+ // if there's data block on KBC data port, read it out
+ //
+ if ((Data & KBC_OUTB) == KBC_OUTB) {
+ MouseDev->IsaIo->Io.Read (MouseDev->IsaIo, EfiIsaIoWidthUint8, KBC_DATA_PORT, 1, &Data);
+ }
+
+ Status = EFI_SUCCESS;
+ //
+ // The PS2 mouse driver reset behavior is always successfully return no matter wheater or not there is mouse connected to system.
+ // This behavior is needed by performance speed. The following mouse command only succeessfully finish when mouse device is
+ // connected to system, so if PS2 mouse device not connect to system or user not ask for, we skip the mouse configuration and enabling
+ //
+ if (ExtendedVerification && CheckMouseConnect (MouseDev)) {
+ //
+ // Send mouse reset command and set mouse default configure
+ //
+ Status = PS2MouseReset (MouseDev->IsaIo);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetSampleRate (MouseDev->IsaIo, MouseDev->SampleRate);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetResolution (MouseDev->IsaIo, MouseDev->Resolution);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseSetScaling (MouseDev->IsaIo, MouseDev->Scaling);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = PS2MouseEnable (MouseDev->IsaIo);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+Exit:
+ gBS->RestoreTPL (OldTpl);
+
+ if (KeyboardEnable) {
+ KbcEnableKb (MouseDev->IsaIo);
+ }
+
+ return Status;
+}
+
+/**
+ Check whether there is Ps/2 mouse device in system
+
+ @param MouseDev - Mouse Private Data Structure
+
+ @retval TRUE - Keyboard in System.
+ @retval FALSE - Keyboard not in System.
+
+**/
+BOOLEAN
+CheckMouseConnect (
+ IN PS2_MOUSE_DEV *MouseDev
+ )
+
+{
+ EFI_STATUS Status;
+
+ Status = PS2MouseEnable (MouseDev->IsaIo);
+ if (!EFI_ERROR (Status)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Get and Clear mouse status.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param State - Output buffer holding status.
+
+ @retval EFI_INVALID_PARAMETER Output buffer is invalid.
+ @retval EFI_NOT_READY Mouse is not changed status yet.
+ @retval EFI_SUCCESS Mouse status is changed and get successful.
+**/
+EFI_STATUS
+EFIAPI
+MouseGetState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN OUT EFI_SIMPLE_POINTER_STATE *State
+ )
+{
+ PS2_MOUSE_DEV *MouseDev;
+ EFI_TPL OldTpl;
+
+ MouseDev = PS2_MOUSE_DEV_FROM_THIS (This);
+
+ if (State == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (!MouseDev->StateChanged) {
+ return EFI_NOT_READY;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ CopyMem (State, &(MouseDev->State), sizeof (EFI_SIMPLE_POINTER_STATE));
+
+ //
+ // clear mouse state
+ //
+ MouseDev->State.RelativeMovementX = 0;
+ MouseDev->State.RelativeMovementY = 0;
+ MouseDev->State.RelativeMovementZ = 0;
+ MouseDev->StateChanged = FALSE;
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Event notification function for SIMPLE_POINTER.WaitForInput event.
+ Signal the event if there is input from mouse.
+
+ @param Event event object
+ @param Context event context
+
+**/
+VOID
+EFIAPI
+MouseWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ PS2_MOUSE_DEV *MouseDev;
+
+ MouseDev = (PS2_MOUSE_DEV *) Context;
+
+ //
+ // Someone is waiting on the mouse event, if there's
+ // input from mouse, signal the event
+ //
+ if (MouseDev->StateChanged) {
+ gBS->SignalEvent (Event);
+ }
+
+}
+
+/**
+ Event notification function for TimerEvent event.
+ If mouse device is connected to system, try to get the mouse packet data.
+
+ @param Event - TimerEvent in PS2_MOUSE_DEV
+ @param Context - Pointer to PS2_MOUSE_DEV structure
+
+**/
+VOID
+EFIAPI
+PollMouse (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+
+{
+ PS2_MOUSE_DEV *MouseDev;
+
+ MouseDev = (PS2_MOUSE_DEV *) Context;
+
+ //
+ // Polling mouse packet data
+ //
+ PS2MouseGetPacket (MouseDev);
+}
+
+/**
+ The user Entry Point for module Ps2Mouse. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializePs2Mouse(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPS2MouseDriver,
+ ImageHandle,
+ &gPs2MouseComponentName,
+ &gPs2MouseComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h
new file mode 100644
index 0000000000..604fb47e47
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2Mouse.h
@@ -0,0 +1,400 @@
+/** @file
+ PS/2 Mouse driver header file.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PS2MOUSE_H_
+#define _PS2MOUSE_H_
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/SimplePointer.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPS2MouseDriver;
+extern EFI_COMPONENT_NAME_PROTOCOL gPs2MouseComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPs2MouseComponentName2;
+
+//
+// PS/2 mouse sample rate
+//
+typedef enum {
+ SampleRate10,
+ SampleRate20,
+ SampleRate40,
+ SampleRate60,
+ SampleRate80,
+ SampleRate100,
+ SampleRate200,
+ MaxSampleRate
+} MOUSE_SR;
+
+//
+// PS/2 mouse resolution
+//
+typedef enum {
+ MouseResolution1,
+ MouseResolution2,
+ MouseResolution4,
+ MouseResolution8,
+ MaxResolution
+} MOUSE_RE;
+
+//
+// PS/2 mouse scaling
+//
+typedef enum {
+ Scaling1,
+ Scaling2
+} MOUSE_SF;
+
+//
+// Driver Private Data
+//
+#define PS2_MOUSE_DEV_SIGNATURE SIGNATURE_32 ('p', 's', '2', 'm')
+
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_POINTER_PROTOCOL SimplePointerProtocol;
+ EFI_SIMPLE_POINTER_STATE State;
+ EFI_SIMPLE_POINTER_MODE Mode;
+ BOOLEAN StateChanged;
+
+ //
+ // PS2 Mouse device specific information
+ //
+ MOUSE_SR SampleRate;
+ MOUSE_RE Resolution;
+ MOUSE_SF Scaling;
+ UINT8 DataPackageSize;
+
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ EFI_EVENT TimerEvent;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} PS2_MOUSE_DEV;
+
+#define PS2_MOUSE_DEV_FROM_THIS(a) CR (a, PS2_MOUSE_DEV, SimplePointerProtocol, PS2_MOUSE_DEV_SIGNATURE)
+
+//
+// Function prototypes
+//
+/**
+ Test to see if this driver supports ControllerHandle. Any ControllerHandle
+ than contains a IsaIo protocol can be supported.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device
+ @retval EFI_ALREADY_STARTED This driver is already running on this device
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start this driver on ControllerHandle by opening a IsaIo
+ protocol, creating PS2_MOUSE_ABSOLUTE_POINTER_DEV device and install gEfiAbsolutePointerProtocolGuid
+ finnally.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle
+ @retval other This driver does not support this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop this driver on ControllerHandle. Support stoping any child handles
+ created by this driver.
+
+ @param This Protocol instance pointer.
+ @param ControllerHandle Handle of device to stop driver on
+ @param NumberOfChildren Number of Handles in ChildHandleBuffer. If number of
+ children is zero stop the entire bus driver.
+ @param ChildHandleBuffer List of Child Handles to Stop.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+PS2MouseDriverStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+Ps2MouseComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ Reset the Mouse and do BAT test for it, if ExtendedVerification isTRUE and there is a mouse device connectted to system
+
+ @param This - Pointer of simple pointer Protocol.
+ @param ExtendedVerification - Whether configure mouse parameters. True: do; FALSE: skip.
+
+
+ @retval EFI_SUCCESS - The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR - Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+MouseReset (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Get and Clear mouse status.
+
+ @param This - Pointer of simple pointer Protocol.
+ @param State - Output buffer holding status.
+
+ @retval EFI_INVALID_PARAMETER Output buffer is invalid.
+ @retval EFI_NOT_READY Mouse is not changed status yet.
+ @retval EFI_SUCCESS Mouse status is changed and get successful.
+**/
+EFI_STATUS
+EFIAPI
+MouseGetState (
+ IN EFI_SIMPLE_POINTER_PROTOCOL *This,
+ IN OUT EFI_SIMPLE_POINTER_STATE *State
+ );
+
+/**
+
+ Event notification function for SIMPLE_POINTER.WaitForInput event.
+ Signal the event if there is input from mouse.
+
+ @param Event event object
+ @param Context event context
+
+**/
+VOID
+EFIAPI
+MouseWaitForInput (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Event notification function for TimerEvent event.
+ If mouse device is connected to system, try to get the mouse packet data.
+
+ @param Event - TimerEvent in PS2_MOUSE_DEV
+ @param Context - Pointer to PS2_MOUSE_DEV structure
+
+**/
+VOID
+EFIAPI
+PollMouse (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ I/O work flow of in 8042 data.
+
+ @param IsaIo Pointer to instance of EFI_ISA_IO_PROTOCOL
+ @param Data Data value
+
+ @retval EFI_SUCCESS Success to excute I/O work flow
+ @retval EFI_TIMEOUT Keyboard controller time out.
+**/
+EFI_STATUS
+In8042Data (
+ IN EFI_ISA_IO_PROTOCOL *IsaIo,
+ IN OUT UINT8 *Data
+ );
+
+/**
+ Check whether there is Ps/2 mouse device in system
+
+ @param MouseDev - Mouse Private Data Structure
+
+ @retval TRUE - Keyboard in System.
+ @retval FALSE - Keyboard not in System.
+
+**/
+BOOLEAN
+CheckMouseConnect (
+ IN PS2_MOUSE_DEV *MouseDev
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
new file mode 100644
index 0000000000..ea7af5b10b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
@@ -0,0 +1,76 @@
+## @file
+# PS2 Mouse Driver.
+#
+# This dirver provides support for PS2 based mice.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = Ps2MouseDxe
+ MODULE_UNI_FILE = Ps2MouseDxe.uni
+ FILE_GUID = 202A2B0E-9A31-4812-B291-8747DF152439
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializePs2Mouse
+
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gPS2MouseDriver;
+# COMPONENT_NAME = gPs2MouseComponentName;
+# COMPONENT_NAME2 = gPs2MouseComponentName2;
+#
+
+[Sources]
+ ComponentName.c
+ CommPs2.h
+ CommPs2.c
+ Ps2Mouse.h
+ Ps2Mouse.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+ PcdLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiSimplePointerProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2MouseExtendedVerification ## CONSUMES
+
+#
+# [Event]
+#
+# ##
+# # Timer event used to check the mouse state at a regular interval.
+# #
+# EVENT_TYPE_PERIODIC_TIMER ## CONSUMES
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ Ps2MouseDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni
new file mode 100644
index 0000000000..c22c440d85
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni
new file mode 100644
index 0000000000..750a15a849
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c
new file mode 100644
index 0000000000..c541eb8991
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ata.c
@@ -0,0 +1,2799 @@
+/** @file
+ This file contains all helper functions on the ATA command
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+ update - ATAIdentity() func
+ update - AtaBlockIoReadBlocks() func
+ update - AtaBlockIoWriteBlocks() func
+ add - AtaAtapi6Identify() func
+ add - AtaReadSectorsExt() func
+ add - AtaWriteSectorsExt() func
+ add - AtaPioDataInExt() func
+ add - AtaPioDataOutExt() func
+
+**/
+
+#include "IdeBus.h"
+/**
+ This function is called by ATAIdentify() to identity whether this disk
+ supports ATA/ATAPI6 48bit addressing, ie support >120G capacity
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+
+ @retval EFI_SUCCESS The disk specified by IdeDev is a Atapi6 supported one and
+ 48-bit addressing must be used
+ @retval EFI_UNSUPPORTED The disk dosn't not support Atapi6 or it supports but the
+ capacity is below 120G, 48bit addressing is not needed
+ @retval EFI_DEVICE_ERROR The identify data in IdeDev is incorrect
+ @retval EFI_INVALID_PARAMETER The identify data in IdeDev is NULL.
+
+ @note This function must be called after DEVICE_IDENTITY command has been
+ successfully returned
+
+**/
+EFI_STATUS
+AtaAtapi6Identify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 Index;
+ EFI_LBA TmpLba;
+ EFI_LBA Capacity;
+ EFI_IDENTIFY_DATA *Atapi6IdentifyStruct;
+
+ if (IdeDev->IdData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Atapi6IdentifyStruct = IdeDev->IdData;
+
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & (BIT15 | BIT14)) != 0x4000) {
+ //
+ // Per ATA-6 spec, word83: bit15 is zero and bit14 is one
+ //
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Atapi6IdentifyStruct->AtapiData.cmd_set_support_83 & BIT10) == 0) {
+ //
+ // The device dosn't support 48 bit addressing
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // 48 bit address feature set is supported, get maximum capacity
+ //
+ Capacity = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[0];
+ for (Index = 1; Index < 4; Index++) {
+ //
+ // Lower byte goes first: word[100] is the lowest word, word[103] is highest
+ //
+ TmpLba = Atapi6IdentifyStruct->AtaData.maximum_lba_for_48bit_addressing[Index];
+ Capacity |= LShiftU64 (TmpLba, 16 * Index);
+ }
+
+ if (Capacity > MAX_28BIT_ADDRESSING_CAPACITY) {
+ //
+ // Capacity exceeds 120GB. 48-bit addressing is really needed
+ //
+ IdeDev->Type = Ide48bitAddressingHardDisk;
+
+ //
+ // Fill block media information:Media->LogicalPartition ,
+ // Media->WriteCaching will be filledin the DiscoverIdeDevcie() function.
+ //
+ IdeDev->BlkIo.Media->IoAlign = 4;
+ IdeDev->BlkIo.Media->MediaId = 1;
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;
+
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+/**
+ Enable SMART of the disk if supported
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record
+ all the information of the IDE device.
+**/
+VOID
+AtaSMARTSupport (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SMARTSupported;
+ UINT8 Device;
+ EFI_IDENTIFY_DATA *TmpAtaIdentifyPointer;
+ UINT8 DeviceSelect;
+ UINT8 LBAMid;
+ UINT8 LBAHigh;
+
+ //
+ // Detect if the device supports S.M.A.R.T.
+ //
+ if ((IdeDev->IdData->AtaData.command_set_supported_83 & 0xc000) != 0x4000) {
+ //
+ // Data in word 82 is not valid (bit15 shall be zero and bit14 shall be to one)
+ //
+ return ;
+ } else {
+ if ((IdeDev->IdData->AtaData.command_set_supported_82 & 0x0001) != 0x0001) {
+ //
+ // S.M.A.R.T is not supported by the device
+ //
+ SMARTSupported = FALSE;
+ } else {
+ SMARTSupported = TRUE;
+ }
+ }
+
+ if (!SMARTSupported) {
+ //
+ // Report nonsupport status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_NOTSUPPORTED)
+ );
+ } else {
+ //
+ // Enable this feature
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_ENABLE)
+ );
+
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_SMART,
+ Device,
+ ATA_SMART_ENABLE_OPERATION,
+ 0,
+ 0,
+ ATA_CONSTANT_4F,
+ ATA_CONSTANT_C2
+ );
+ //
+ // Detect if this feature is enabled
+ //
+ TmpAtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+ if (TmpAtaIdentifyPointer == NULL) {
+ return;
+ }
+
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) TmpAtaIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_CMD_IDENTIFY_DRIVE,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (TmpAtaIdentifyPointer);
+ return ;
+ }
+
+ //
+ // Check if the feature is enabled
+ //
+ if ((TmpAtaIdentifyPointer->AtaData.command_set_feature_enb_85 & 0x0001) == 0x0001) {
+ //
+ // Read status data
+ //
+ AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_SMART,
+ Device,
+ ATA_SMART_RETURN_STATUS,
+ 0,
+ 0,
+ ATA_CONSTANT_4F,
+ ATA_CONSTANT_C2
+ );
+ LBAMid = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+ LBAHigh = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb);
+
+ if ((LBAMid == 0x4f) && (LBAHigh == 0xc2)) {
+ //
+ // The threshold exceeded condition is not detected by the device
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_UNDERTHRESHOLD)
+ );
+
+ } else if ((LBAMid == 0xf4) && (LBAHigh == 0x2c)) {
+ //
+ // The threshold exceeded condition is detected by the device
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_OVERTHRESHOLD)
+ );
+ }
+
+ } else {
+ //
+ // Report disabled status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_ATA_BUS_SMART_DISABLED)
+ );
+ }
+
+ gBS->FreePool (TmpAtaIdentifyPointer);
+ }
+
+ return ;
+}
+/**
+ Sends out an ATA Identify Command to the specified device.
+
+ This function is called by DiscoverIdeDevice() during its device
+ identification. It sends out the ATA Identify Command to the
+ specified device. Only ATA device responses to this command. If
+ the command succeeds, it returns the Identify data structure which
+ contains information about the device. This function extracts the
+ information it needs to fill the IDE_BLK_IO_DEV data structure,
+ including device type, media block size, media capacity, and etc.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record
+ all the information of the IDE device.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+ @note parameter IdeDev will be updated in this function.
+
+**/
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_IDENTIFY_DATA *AtaIdentifyPointer;
+ UINT32 Capacity;
+ UINT8 DeviceSelect;
+ UINTN Retry;
+
+ //
+ // AtaIdentifyPointer is used for accommodating returned IDENTIFY data of
+ // the ATA Identify command
+ //
+ AtaIdentifyPointer = (EFI_IDENTIFY_DATA *) AllocateZeroPool (sizeof (EFI_IDENTIFY_DATA));
+ if (AtaIdentifyPointer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // use ATA PIO Data In protocol to send ATA Identify command
+ // and receive data from device
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+
+ Retry = 3;
+ while (Retry > 0) {
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) AtaIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_CMD_IDENTIFY_DRIVE,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+ //
+ // If ATA Identify command succeeds, then according to the received
+ // IDENTIFY data,
+ // identify the device type ( ATA or not ).
+ // If ATA device, fill the information in IdeDev.
+ // If not ATA device, return IDE_DEVICE_ERROR
+ //
+ if (!EFI_ERROR (Status)) {
+
+ IdeDev->IdData = AtaIdentifyPointer;
+
+ //
+ // Print ATA Module Name
+ //
+ PrintAtaModuleName (IdeDev);
+
+ //
+ // bit 15 of pAtaIdentify->config is used to identify whether device is
+ // ATA device or ATAPI device.
+ // if 0, means ATA device; if 1, means ATAPI device.
+ //
+ if ((AtaIdentifyPointer->AtaData.config & 0x8000) == 0x00) {
+ //
+ // Detect if support S.M.A.R.T. If yes, enable it as default
+ //
+ AtaSMARTSupport (IdeDev);
+
+ //
+ // Check whether this device needs 48-bit addressing (ATAPI-6 ata device)
+ //
+ Status = AtaAtapi6Identify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ //
+ // It's a disk with >120GB capacity, initialized in AtaAtapi6Identify()
+ //
+ return EFI_SUCCESS;
+ } else if (Status == EFI_DEVICE_ERROR) {
+ //
+ // Some disk with big capacity (>200GB) is slow when being identified
+ // and will return all zero for word83.
+ // We try twice at first. If it fails, we do a SoftRest and try again.
+ //
+ Retry--;
+ if (Retry == 1) {
+ //
+ // Do a SoftRest before the third attempt.
+ //
+ AtaSoftReset (IdeDev);
+ }
+ continue;
+ }
+ //
+ // This is a hard disk <= 120GB capacity, treat it as normal hard disk
+ //
+ IdeDev->Type = IdeHardDisk;
+
+ //
+ // Block Media Information:
+ // Media->LogicalPartition , Media->WriteCaching will be filled
+ // in the DiscoverIdeDevcie() function.
+ //
+ IdeDev->BlkIo.Media->IoAlign = 4;
+ IdeDev->BlkIo.Media->MediaId = 1;
+ IdeDev->BlkIo.Media->RemovableMedia = FALSE;
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+
+ //
+ // Calculate device capacity
+ //
+ Capacity = ((UINT32)AtaIdentifyPointer->AtaData.user_addressable_sectors_hi << 16) |
+ AtaIdentifyPointer->AtaData.user_addressable_sectors_lo ;
+ IdeDev->BlkIo.Media->LastBlock = Capacity - 1;
+
+ return EFI_SUCCESS;
+ }
+
+ }
+ break;
+ }
+
+ gBS->FreePool (AtaIdentifyPointer);
+ //
+ // Make sure the pIdData will not be freed again.
+ //
+ IdeDev->IdData = NULL;
+
+ return EFI_DEVICE_ERROR;
+}
+
+/**
+ This function is a helper function used to change the char order in a string. It
+ is designed specially for the PrintAtaModuleName() function. After the IDE device
+ is detected, the IDE driver gets the device module name by sending ATA command
+ called ATA Identify Command or ATAPI Identify Command to the specified IDE device.
+ The module name returned is a string of ASCII characters: the first character is bit8--bit15
+ of the first word, the second character is BIT0--bit7 of the first word and so on. Thus
+ the string can not be print directly before it is preprocessed by this func to change
+ the order of characters in each word in the string.
+
+ @param Destination Indicates the destination string.
+ @param Source Indicates the source string.
+ @param Size the length of the string
+**/
+VOID
+SwapStringChars (
+ IN CHAR8 *Destination,
+ IN CHAR8 *Source,
+ IN UINT32 Size
+ )
+{
+ UINT32 Index;
+ CHAR8 Temp;
+
+ for (Index = 0; Index < Size; Index += 2) {
+
+ Temp = Source[Index + 1];
+ Destination[Index + 1] = Source[Index];
+ Destination[Index] = Temp;
+ }
+}
+/**
+ This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+**/
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ if (IdeDev->IdData == NULL) {
+ return ;
+ }
+
+ SwapStringChars (IdeDev->ModelName, IdeDev->IdData->AtaData.ModelName, 40);
+ IdeDev->ModelName[40] = 0x00;
+}
+
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param Buffer buffer contained data transferred from device to host.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param Head value of the Head/Device Register
+ @param SectorCount value of the Sector Count Register
+ @param SectorNumber value of the Sector Number Register
+ @param CylinderLsb value of the low byte of the Cylinder Register
+ @param CylinderMsb value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.
+ // bit6 set means LBA mode
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+ );
+
+ //
+ // All ATAPI device's ATA commands can be issued regardless of the
+ // state of the DRDY
+ //
+ if (IdeDev->Type == IdeHardDisk) {
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (AtaCommand == ATA_CMD_SET_FEATURES) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+ //
+ // send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data in protocol, host can perform a series of reads to
+ // the data register after each time device set DRQ ready;
+ // The data size of "a series of read" is command specific.
+ // For most ATA command, data size received from device will not exceed
+ // 1 sector, hence the data size for "a series of read" can be the whole data
+ // size of one command request.
+ // For ATA command such as Read Sector command, the data size of one ATA
+ // command request is often larger than 1 sector, according to the
+ // Read Sector command, the data size of "a series of read" is exactly 1
+ // sector.
+ // Here for simplification reason, we specify the data size for
+ // "a series of read" to 1 sector (256 words) if data size of one ATA command
+ // request is larger than 256 words.
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ DRQClear (IdeDev, ATATIMEOUT);
+
+ return CheckErrorStatus (IdeDev);
+}
+
+/**
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param *Buffer buffer contained data transferred from host to device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param Head value of the Head/Device Register
+ @param SectorCount value of the Sector Count Register
+ @param SectorNumber value of the Sector Number Register
+ @param CylinderLsb value of the low byte of the Cylinder Register
+ @param CylinderMsb value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device received required
+ data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ )
+{
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // select device via Head/Device register.
+ // Before write Head/Device register, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // e0:1110,0000-- bit7 and bit5 are reserved bits.
+ // bit6 set means LBA mode
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0 | Head)
+ );
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, SectorNumber);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, CylinderLsb);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, CylinderMsb);
+
+ //
+ // send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data out protocol, host can perform a series of
+ // writes to the data register after each time device set DRQ ready;
+ // The data size of "a series of read" is command specific.
+ // For most ATA command, data size written to device will not exceed 1 sector,
+ // hence the data size for "a series of write" can be the data size of one
+ // command request.
+ // For ATA command such as Write Sector command, the data size of one
+ // ATA command request is often larger than 1 sector, according to the
+ // Write Sector command, the data size of "a series of read" is exactly
+ // 1 sector.
+ // Here for simplification reason, we specify the data size for
+ // "a series of write" to 1 sector (256 words) if data size of one ATA command
+ // request is larger than 256 words.
+ //
+ Increment = 256;
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+
+ //
+ // DRQReady2-- read Alternate Status Register to determine the DRQ bit
+ // data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Check the remaining byte count is less than 512 bytes
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+ //
+ // perform a series of write without check DRQ ready
+ //
+
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ DRQClear (IdeDev, ATATIMEOUT);
+
+ return CheckErrorStatus (IdeDev);
+}
+
+/**
+ This function is used to analyze the Status Register and print out
+ some debug information and if there is ERR bit set in the Status
+ Register, the Error Register's value is also be parsed and print out.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
+ record all the information of the IDE device.
+
+ @retval EFI_SUCCESS No err information in the Status Register.
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ DEBUG_CODE_BEGIN ();
+
+ if ((StatusRegister & ATA_STSREG_DWF) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Write Fault\n",
+ StatusRegister)
+ );
+ }
+
+ if ((StatusRegister & ATA_STSREG_CORR) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Corrected Data\n",
+ StatusRegister)
+ );
+ }
+
+ if ((StatusRegister & ATA_STSREG_ERR) != 0) {
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ if ((ErrorRegister & ATA_ERRREG_BBK) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Bad Block Detected\n",
+ ErrorRegister)
+ );
+ }
+
+ if ((ErrorRegister & ATA_ERRREG_UNC) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Uncorrectable Data\n",
+ ErrorRegister)
+ );
+ }
+
+ if ((ErrorRegister & ATA_ERRREG_MC) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Media Change\n",
+ ErrorRegister)
+ );
+ }
+
+ if ((ErrorRegister & ATA_ERRREG_ABRT) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Abort\n",
+ ErrorRegister)
+ );
+ }
+
+ if ((ErrorRegister & ATA_ERRREG_TK0NF) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Track 0 Not Found\n",
+ ErrorRegister)
+ );
+ }
+
+ if ((ErrorRegister & ATA_ERRREG_AMNF) != 0) {
+ DEBUG (
+ (EFI_D_BLKIO,
+ "CheckErrorStatus()-- %02x : Error : Address Mark Not Found\n",
+ ErrorRegister)
+ );
+ }
+ }
+
+ DEBUG_CODE_END ();
+
+ if ((StatusRegister & (ATA_STSREG_ERR | ATA_STSREG_DWF | ATA_STSREG_CORR)) == 0) {
+ return EFI_SUCCESS;
+ }
+
+ return EFI_DEVICE_ERROR;
+
+}
+
+/**
+ This function is called by the AtaBlkIoReadBlocks() to perform reading from
+ media in block unit.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param DataBuffer A pointer to the destination buffer for the data.
+ @param Lba The starting logical block address to read from on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtaPioDataIn() function.
+
+**/
+EFI_STATUS
+AtaReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+ UINT8 AtaCommand;
+ UINT8 SectorCount8;
+ UINT16 SectorCount;
+ UINTN ByteCount;
+ VOID *Buffer;
+
+ Buffer = DataBuffer;
+
+ //
+ // Using ATA Read Sector(s) command (opcode=0x20) with PIO DATA IN protocol
+ //
+ AtaCommand = ATA_CMD_READ_SECTORS;
+
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Lba32 = (UINT32) Lba;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ //
+ // in ATA-3 spec, LBA is in 28 bit width
+ //
+ Lba0 = (UINT8) Lba32;
+ Lba1 = (UINT8) (Lba32 >> 8);
+ Lba2 = (UINT8) (Lba32 >> 16);
+ //
+ // low 4 bit of Lba3 stands for LBA bit24~bit27.
+ //
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+ if (BlocksRemaining >= 0x100) {
+
+ //
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256
+ // sectors to be read
+ //
+ SectorCount8 = 0x00;
+ //
+ // SectorCount is used to record the number of sectors to be read
+ //
+ SectorCount = 256;
+ } else {
+
+ SectorCount8 = (UINT8) BlocksRemaining;
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be read
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // call AtaPioDataIn() to send Read Sector Command and receive data read
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ Buffer,
+ (UINT32) ByteCount,
+ AtaCommand,
+ Lba3,
+ SectorCount8,
+ Lba0,
+ Lba1,
+ Lba2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+/**
+ This function is called by the AtaBlkIoWriteBlocks() to perform writing onto
+ media in block unit.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record
+ all the information of the IDE device.
+ @param BufferData A pointer to the source buffer for the data.
+ @param Lba The starting logical block address to write onto the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtaPioDataIn() function.
+
+**/
+EFI_STATUS
+AtaWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *BufferData,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+ UINT8 AtaCommand;
+ UINT8 SectorCount8;
+ UINT16 SectorCount;
+ UINTN ByteCount;
+ VOID *Buffer;
+
+ Buffer = BufferData;
+
+ //
+ // Using Write Sector(s) command (opcode=0x30) with PIO DATA OUT protocol
+ //
+ AtaCommand = ATA_CMD_WRITE_SECTORS;
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Lba32 = (UINT32) Lba;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ Lba0 = (UINT8) Lba32;
+ Lba1 = (UINT8) (Lba32 >> 8);
+ Lba2 = (UINT8) (Lba32 >> 16);
+ Lba3 = (UINT8) ((Lba32 >> 24) & 0x0f);
+
+ if (BlocksRemaining >= 0x100) {
+
+ //
+ // SectorCount8 is sent to Sector Count register, 0x00 means 256 sectors
+ // to be written
+ //
+ SectorCount8 = 0x00;
+ //
+ // SectorCount is used to record the number of sectors to be written
+ //
+ SectorCount = 256;
+ } else {
+
+ SectorCount8 = (UINT8) BlocksRemaining;
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ Status = AtaPioDataOut (
+ IdeDev,
+ Buffer,
+ (UINT32) ByteCount,
+ AtaCommand,
+ Lba3,
+ SectorCount8,
+ Lba0,
+ Lba1,
+ Lba2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+/**
+ This function is used to implement the Soft Reset on the specified device. But,
+ the ATA Soft Reset mechanism is so strong a reset method that it will force
+ resetting on both devices connected to the same cable.
+
+ It is called by IdeBlkIoReset(), a interface function of Block
+ I/O protocol.
+
+ This function can also be used by the ATAPI device to perform reset when
+ ATAPI Reset command is failed.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @retval EFI_SUCCESS Soft reset completes successfully.
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+ @note The registers initial values after ATA soft reset are different
+ to the ATA device and ATAPI device.
+**/
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+
+ UINT8 DeviceControl;
+
+ DeviceControl = 0;
+ //
+ // set SRST bit to initiate soft reset
+ //
+ DeviceControl |= ATA_CTLREG_SRST;
+
+ //
+ // disable Interrupt
+ //
+ DeviceControl |= BIT1;
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ //
+ // SRST should assert for at least 5 us, we use 10 us for
+ // better compatibility
+ //
+ gBS->Stall (10);
+
+ //
+ // Enable interrupt to support UDMA, and clear SRST bit
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ //
+ // Wait for at least 2 ms to check BSY status, we use 10 ms
+ // for better compatibility
+ //
+ gBS->Stall(10000);
+ //
+ // slave device needs at most 31s to clear BSY
+ //
+ if (WaitForBSYClear (IdeDev, 31000) == EFI_TIMEOUT) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In
+ Protocol, supporting ATA/ATAPI-6 standard
+
+ Comparing with ATA-3 data in protocol, we have two differents here:
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+ wait will frequently fail... cause writing function return error)
+
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+ slow down writing performance by 100 times!)
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Buffer buffer contained data transferred from device to host.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param StartLba the start LBA of this transaction
+ @param SectorCount the count of sectors to be transfered
+
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN OUT VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+{
+ UINT8 DevSel;
+ UINT8 SectorCount8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device, set bit6 as 1 to indicate LBA mode is used
+ //
+ DevSel = (UINT8) (IdeDev->Device << 4);
+ DevSel |= 0x40;
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ DevSel
+ );
+
+ //
+ // Wait for DRDY singnal asserting. ATAPI device needn't wait
+ //
+ if ( (IdeDev->Type == IdeHardDisk) ||
+ (IdeDev->Type == Ide48bitAddressingHardDisk)) {
+
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ //
+ // Fill feature register if needed
+ //
+ if (AtaCommand == ATA_CMD_SET_FEATURES) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) StartLba;
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register, invoking the processing of this command
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO data in protocol, host can perform a series of reads to
+ // the data register after each time device set DRQ ready;
+ //
+
+ //
+ // 256 words
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get the byte count for one series of read
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+
+ return CheckErrorStatus (IdeDev);
+}
+/**
+ Send ATA Ext command into device with NON_DATA protocol.
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+AtaCommandIssueExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) (Feature >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ LbaLow = (UINT8) LbaAddress;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Work around for Segate 160G disk writing
+ //
+ gBS->Stall (1800);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Stall at least 400ns
+ //
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+/**
+ Send ATA Ext command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_DEVICE_ERROR Error executing commands on this device.
+
+**/
+EFI_STATUS
+AtaCommandIssue (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 Lba0;
+ UINT8 Lba1;
+ UINT8 Lba2;
+ UINT8 Lba3;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Lba0 = (UINT8) LbaAddress;
+ Lba1 = (UINT8) RShiftU64 (LbaAddress, 8);
+ Lba2 = (UINT8) RShiftU64 (LbaAddress, 16);
+ Lba3 = (UINT8) RShiftU64 (LbaAddress, 24);
+ Device = (UINT8) (Device | Lba3);
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, Lba0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, Lba1);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, Lba2);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Stall at least 400ns
+ //
+ gBS->Stall (100);
+
+ return EFI_SUCCESS;
+}
+/**
+ Perform an ATA Udma operation (Read, ReadExt, Write, WriteExt).
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DataBuffer A pointer to the source buffer for the data.
+ @param StartLba The starting logical block address to write to
+ on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+ @param UdmaOp The perform operations could be AtaUdmaReadOp, AtaUdmaReadExOp,
+ AtaUdmaWriteOp, AtaUdmaWriteExOp
+
+ @retval EFI_SUCCESS the operation is successful.
+ @retval EFI_OUT_OF_RESOURCES Build PRD table failed
+ @retval EFI_UNSUPPORTED Unknown channel or operations command
+ @retval EFI_DEVICE_ERROR Ata command execute failed
+
+**/
+EFI_STATUS
+DoAtaUdma (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks,
+ IN ATA_UDMA_OPERATION UdmaOp
+ )
+{
+ IDE_DMA_PRD *PrdAddr;
+ IDE_DMA_PRD *UsedPrdAddr;
+ IDE_DMA_PRD *TempPrdAddr;
+ UINT8 RegisterValue;
+ UINT8 Device;
+ UINT64 IoPortForBmic;
+ UINT64 IoPortForBmis;
+ UINT64 IoPortForBmid;
+ EFI_STATUS Status;
+ UINTN PrdTableNum;
+ UINTN ByteCount;
+ UINTN ByteAvailable;
+ UINT8 *PrdBuffer;
+ UINTN RemainBlockNum;
+ UINT8 DeviceControl;
+ UINT32 Count;
+ UINTN PageCount;
+ VOID *Map;
+ VOID *MemPage;
+ EFI_PHYSICAL_ADDRESS DeviceAddress;
+ UINTN MaxDmaCommandSectors;
+ EFI_PCI_IO_PROTOCOL_OPERATION PciIoProtocolOp;
+ UINT8 AtaCommand;
+
+ switch (UdmaOp) {
+ case AtaUdmaReadOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;
+ AtaCommand = ATA_CMD_READ_DMA;
+ break;
+ case AtaUdmaReadExtOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterWrite;
+ AtaCommand = ATA_CMD_READ_DMA_EXT;
+ break;
+ case AtaUdmaWriteOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;
+ AtaCommand = ATA_CMD_WRITE_DMA;
+ break;
+ case AtaUdmaWriteExtOp:
+ MaxDmaCommandSectors = ATAPI_MAX_DMA_EXT_CMD_SECTORS;
+ PciIoProtocolOp = EfiPciIoOperationBusMasterRead;
+ AtaCommand = ATA_CMD_WRITE_DMA_EXT;
+ break;
+ default:
+ return EFI_UNSUPPORTED;
+ break;
+ }
+
+ //
+ // Select device
+ //
+ Device = (UINT8) ((IdeDev->Device << 4) | 0xe0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Enable interrupt to support UDMA
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICP_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmic = IdeDev->IoPort->BusMasterBaseAddr + BMICS_OFFSET;
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ IoPortForBmid = IdeDev->IoPort->BusMasterBaseAddr + BMIDS_OFFSET;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ Status = EFI_SUCCESS;
+
+ RemainBlockNum = NumberOfBlocks;
+ while (RemainBlockNum > 0) {
+
+ if (RemainBlockNum >= MaxDmaCommandSectors) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ NumberOfBlocks = MaxDmaCommandSectors;
+ RemainBlockNum -= MaxDmaCommandSectors;
+ } else {
+ NumberOfBlocks = (UINT16) RemainBlockNum;
+ RemainBlockNum = 0;
+ }
+
+ //
+ // Calculate the number of PRD table to make sure the memory region
+ // not cross 64K boundary
+ //
+ ByteCount = NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ PrdTableNum = ((ByteCount >> 16) + 1) + 1;
+
+ //
+ // Build PRD table
+ //
+ PageCount = EFI_SIZE_TO_PAGES (2 * PrdTableNum * sizeof (IDE_DMA_PRD));
+ Status = IdeDev->PciIo->AllocateBuffer (
+ IdeDev->PciIo,
+ AllocateAnyPages,
+ EfiBootServicesData,
+ PageCount,
+ &MemPage,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ ZeroMem ((VOID *) ((UINTN) MemPage), EFI_PAGES_TO_SIZE (PageCount));
+
+ PrdAddr = (IDE_DMA_PRD *) ((UINTN) MemPage);
+ //
+ // To make sure PRD is allocated in one 64K page
+ //
+ if (((UINTN) PrdAddr & 0x0FFFF) > (((UINTN) PrdAddr + PrdTableNum * sizeof (IDE_DMA_PRD) - 1) & 0x0FFFF)) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x10000) & 0xFFFF0000);
+ } else {
+ if ((UINTN) PrdAddr & 0x03) {
+ UsedPrdAddr = (IDE_DMA_PRD *) ((UINTN) ((UINT8 *) PrdAddr + 0x04) & 0xFFFFFFFC);
+ } else {
+ UsedPrdAddr = PrdAddr;
+ }
+ }
+
+ //
+ // Build the PRD table
+ //
+ Status = IdeDev->PciIo->Map (
+ IdeDev->PciIo,
+ PciIoProtocolOp,
+ DataBuffer,
+ &ByteCount,
+ &DeviceAddress,
+ &Map
+ );
+ if (EFI_ERROR (Status)) {
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ PrdBuffer = (VOID *) ((UINTN) DeviceAddress);
+ TempPrdAddr = UsedPrdAddr;
+ while (TRUE) {
+
+ ByteAvailable = 0x10000 - ((UINTN) PrdBuffer & 0xFFFF);
+
+ if (ByteCount <= ByteAvailable) {
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteCount;
+ TempPrdAddr->EndOfTable = 0x8000;
+ break;
+ }
+
+ TempPrdAddr->RegionBaseAddr = (UINT32) ((UINTN) PrdBuffer);
+ TempPrdAddr->ByteCount = (UINT16) ByteAvailable;
+
+ ByteCount -= ByteAvailable;
+ PrdBuffer += ByteAvailable;
+ TempPrdAddr++;
+ }
+
+ //
+ // Set the base address to BMID register
+ //
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmid,
+ 1,
+ &UsedPrdAddr
+ );
+
+ //
+ // Set BMIC register to identify the operation direction
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ if (UdmaOp == AtaUdmaReadExtOp || UdmaOp == AtaUdmaReadOp) {
+ RegisterValue |= BMIC_NREAD;
+ } else {
+ RegisterValue &= ~((UINT8) BMIC_NREAD);
+ }
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ if (UdmaOp == AtaUdmaWriteExtOp || UdmaOp == AtaUdmaReadExtOp) {
+ Status = AtaCommandIssueExt (
+ IdeDev,
+ AtaCommand,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ } else {
+ Status = AtaCommandIssue (
+ IdeDev,
+ AtaCommand,
+ Device,
+ 0,
+ (UINT16) NumberOfBlocks,
+ StartLba
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Set START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= BMIC_START;
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Check the INTERRUPT and ERROR bit of BMIS
+ // Max transfer number of sectors for one command is 65536(32Mbyte),
+ // it will cost 1 second to transfer these data in UDMA mode 2(33.3MBps).
+ // So set the variable Count to 2000, for about 2 second timeout time.
+ //
+ Status = EFI_SUCCESS;
+ Count = 2000;
+ while (TRUE) {
+
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ if (((RegisterValue & (BMIS_INTERRUPT | BMIS_ERROR)) != 0) || (Count == 0)) {
+ if (((RegisterValue & BMIS_ERROR) != 0) || (Count == 0)) {
+ Status = EFI_DEVICE_ERROR;
+ break;
+ }
+ break;
+ }
+
+ gBS->Stall (1000);
+ Count --;
+ }
+
+ IdeDev->PciIo->FreeBuffer (IdeDev->PciIo, PageCount, MemPage);
+ IdeDev->PciIo->Unmap (IdeDev->PciIo, Map);
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+ //
+ // Read Status Register of IDE device to clear interrupt
+ //
+ RegisterValue = IDEReadPortB(IdeDev->PciIo,IdeDev->IoPort->Reg.Status);
+ //
+ // Clear START bit of BMIC register
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue &= ~((UINT8) BMIC_START);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmic,
+ 1,
+ &RegisterValue
+ );
+
+ if ((RegisterValue & BMIS_ERROR) != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ DataBuffer = (UINT8 *) DataBuffer + NumberOfBlocks * IdeDev->BlkIo.Media->BlockSize;
+ StartLba += NumberOfBlocks;
+ }
+
+ //
+ // Disable interrupt of Select device
+ //
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl);
+ DeviceControl |= ATA_CTLREG_IEN_L;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ return Status;
+}
+
+
+/**
+ This function is called by the AtaBlkIoReadBlocks() to perform reading from
+ media in block unit. The function has been enhanced to support >120GB access
+ and transfer at most 65536 blocks per command
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param DataBuffer A pointer to the destination buffer for the data.
+ @param StartLba The starting logical block address to read from on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaReadExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadExtOp);
+}
+/**
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param DataBuffer A pointer to the destination buffer for the data.
+ @param StartLba The starting logical block address to read from
+ on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaRead (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaReadOp);
+}
+
+/**
+ This function is called by the AtaBlkIoReadBlocks() to perform
+ reading from media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param DataBuffer A pointer to the destination buffer for the data.
+ @param StartLba The starting logical block address to read from on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtaPioDataInExt() function.
+**/
+EFI_STATUS
+AtaReadSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ EFI_LBA Lba64;
+ UINT8 AtaCommand;
+ UINT16 SectorCount;
+ UINT32 ByteCount;
+ VOID *Buffer;
+
+ //
+ // Using ATA "Read Sectors Ext" command(opcode=0x24) with PIO DATA IN protocol
+ //
+ AtaCommand = ATA_CMD_READ_SECTORS_EXT;
+ Buffer = DataBuffer;
+ BlocksRemaining = NumberOfBlocks;
+ Lba64 = StartLba;
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= 0x10000) {
+ //
+ // SectorCount is used to record the number of sectors to be read
+ // Max 65536 sectors can be transfered at a time.
+ //
+ SectorCount = 0xffff;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be read
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // call AtaPioDataInExt() to send Read Sector Command and receive data read
+ //
+ Status = AtaPioDataInExt (
+ IdeDev,
+ Buffer,
+ ByteCount,
+ AtaCommand,
+ Lba64,
+ SectorCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba64 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+/**
+ This function is the ATA implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the memory that data is read into.
+
+ @retval EFI_SUCCESS Read Blocks successfully.
+ @retval EFI_DEVICE_ERROR Read Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note If Read Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (!(Media->MediaPresent)) {
+ return EFI_NO_MEDIA;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 read block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaReadExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ } else {
+ Status = AtaReadSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 read block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaRead (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ } else {
+ Status = AtaReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+/**
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol, supporting ATA/ATAPI-6 standard
+
+ Comparing with ATA-3 data out protocol, we have two differents here:<BR>
+ 1. Do NOT wait for DRQ clear before sending command into IDE device.(the
+ wait will frequently fail... cause writing function return error)
+
+ 2. Do NOT wait for DRQ clear after all data readed.(the wait greatly
+ slow down writing performance by 100 times!)
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Buffer buffer contained data transferred from host to device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param StartLba the start LBA of this transaction
+ @param SectorCount the count of sectors to be transfered
+
+ @retval EFI_SUCCESS send out the ATA command and device receive required
+ data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOutExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN EFI_LBA StartLba,
+ IN UINT16 SectorCount
+ )
+{
+ UINT8 DevSel;
+ UINT8 SectorCount8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+ UINTN WordCount;
+ UINTN Increment;
+ UINT16 *Buffer16;
+ EFI_STATUS Status;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device. Set bit6 as 1 to indicate LBA mode is used
+ //
+ DevSel = (UINT8) (IdeDev->Device << 4);
+ DevSel |= 0x40;
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ DevSel
+ );
+
+ //
+ // Wait for DRDY singnal asserting.
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Fill feature register if needed
+ //
+ if (AtaCommand == ATA_CMD_SET_FEATURES) {
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x03);
+ }
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (StartLba, 24);
+ LbaMid = (UINT8) RShiftU64 (StartLba, 32);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) StartLba;
+ LbaMid = (UINT8) RShiftU64 (StartLba, 8);
+ LbaHigh = (UINT8) RShiftU64 (StartLba, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register, invoking the processing of this command
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ Buffer16 = (UINT16 *) Buffer;
+
+ //
+ // According to PIO Data Out protocol, host can perform a series of writes to
+ // the data register after each time device set DRQ ready;
+ //
+ Increment = 256;
+
+ //
+ // used to record bytes of currently transfered data
+ //
+ WordCount = 0;
+
+ while (WordCount < ByteCount / 2) {
+ //
+ // Poll DRQ bit set, data transfer can be performed only when DRQ is ready.
+ //
+ Status = DRQReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = CheckErrorStatus (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Write data into device by one series of writing to data register
+ //
+ if ((WordCount + Increment) > ByteCount / 2) {
+ Increment = ByteCount / 2 - WordCount;
+ }
+
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ Increment,
+ Buffer16
+ );
+
+ WordCount += Increment;
+ Buffer16 += Increment;
+
+ }
+ return CheckErrorStatus (IdeDev);
+}
+/**
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing to media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DataBuffer A pointer to the source buffer for the data.
+ @param StartLba The starting logical block address to write to
+ on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaWriteExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteExtOp);
+}
+
+/**
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing to media in block unit.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DataBuffer A pointer to the source buffer for the data.
+ @param StartLba The starting logical block address to write to
+ on the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status depends on the function DoAtaUdma() returns.
+**/
+EFI_STATUS
+AtaUdmaWrite (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ return DoAtaUdma (IdeDev, DataBuffer, StartLba, NumberOfBlocks, AtaUdmaWriteOp);
+}
+/**
+ This function is called by the AtaBlkIoWriteBlocks() to perform
+ writing onto media in block unit. The function has been enhanced to
+ support >120GB access and transfer at most 65536 blocks per command
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used
+ to record all the information of the IDE device.
+ @param DataBuffer A pointer to the source buffer for the data.
+ @param StartLba The starting logical block address to write onto the device
+ media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtaPioDataOutExt() function.
+**/
+EFI_STATUS
+AtaWriteSectorsExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *DataBuffer,
+ IN EFI_LBA StartLba,
+ IN UINTN NumberOfBlocks
+ )
+{
+ EFI_STATUS Status;
+ EFI_LBA Lba64;
+ UINTN BlocksRemaining;
+ UINT8 AtaCommand;
+ UINT16 SectorCount;
+ UINT32 ByteCount;
+ VOID *Buffer;
+
+ //
+ // Using ATA "Write Sectors Ext" cmd(opcode=0x24) with PIO DATA OUT protocol
+ //
+ AtaCommand = ATA_CMD_WRITE_SECTORS_EXT;
+ Lba64 = StartLba;
+ Buffer = DataBuffer;
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= 0x10000) {
+ //
+ // SectorCount is used to record the number of sectors to be written.
+ // Max 65536 sectors can be transfered at a time.
+ //
+ SectorCount = 0xffff;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // ByteCount is the number of bytes that will be written
+ //
+ ByteCount = SectorCount * (IdeDev->BlkIo.Media->BlockSize);
+
+ //
+ // Call AtaPioDataOutExt() to send "Write Sectors Ext" Command
+ //
+ Status = AtaPioDataOutExt (
+ IdeDev,
+ Buffer,
+ ByteCount,
+ AtaCommand,
+ Lba64,
+ SectorCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba64 += SectorCount;
+ Buffer = ((UINT8 *) Buffer + ByteCount);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+/**
+ This function is the ATA implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the write request is for.
+ @param Lba The starting logical block address to write onto the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the source buffer for the data.The caller
+ is responsible for either having implicit or explicit
+ ownership of the memory that data is written from.
+
+ @retval EFI_SUCCESS Write Blocks successfully.
+ @retval EFI_DEVICE_ERROR Write Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note If Write Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+**/
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ if (IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ //
+ // For ATA/ATAPI-6 device(capcity > 120GB), use ATA-6 write block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaWriteExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ } else {
+ Status = AtaWriteSectorsExt (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ }
+ } else {
+ //
+ // For ATA-3 compatible device, use ATA-3 write block mechanism
+ //
+ if (IdeBlkIoDevice->UdmaMode.Valid) {
+ Status = AtaUdmaWrite (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ } else {
+ Status = AtaWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ AtaSoftReset (IdeBlkIoDevice);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Enable Long Physical Sector Feature for ATA device.
+
+ @param IdeDev The IDE device data
+
+ @retval EFI_SUCCESS The ATA device supports Long Physical Sector feature
+ and corresponding fields in BlockIo structure is updated.
+ @retval EFI_UNSUPPORTED The device is not ATA device or Long Physical Sector
+ feature is not supported.
+**/
+EFI_STATUS
+AtaEnableLongPhysicalSector (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_ATA_IDENTIFY_DATA *AtaIdentifyData;
+ UINT16 PhyLogicSectorSupport;
+
+ ASSERT (IdeDev->IdData != NULL);
+ //
+ // Only valid for ATA device
+ //
+ AtaIdentifyData = (EFI_ATA_IDENTIFY_DATA *) &IdeDev->IdData->AtaData;
+ if ((AtaIdentifyData->config & 0x8000) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+ PhyLogicSectorSupport = AtaIdentifyData->phy_logic_sector_support;
+ //
+ // Check whether Long Physical Sector Feature is supported
+ //
+ if ((PhyLogicSectorSupport & 0xc000) == 0x4000) {
+ IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock = 1;
+ IdeDev->BlkIo.Media->LowestAlignedLba = 0;
+ //
+ // Check whether one physical block contains multiple physical blocks
+ //
+ if ((PhyLogicSectorSupport & 0x2000) != 0) {
+ IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock =
+ (UINT32) (1 << (PhyLogicSectorSupport & 0x000f));
+ //
+ // Check lowest alignment of logical blocks within physical block
+ //
+ if ((AtaIdentifyData->alignment_logic_in_phy_blocks & 0xc000) == 0x4000) {
+ IdeDev->BlkIo.Media->LowestAlignedLba =
+ (EFI_LBA) ((IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock - ((UINT32)AtaIdentifyData->alignment_logic_in_phy_blocks & 0x3fff)) %
+ IdeDev->BlkIo.Media->LogicalBlocksPerPhysicalBlock);
+ }
+ }
+ //
+ // Check logical block size
+ //
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+ if ((PhyLogicSectorSupport & 0x1000) != 0) {
+ IdeDev->BlkIo.Media->BlockSize = (UINT32) (
+ ((AtaIdentifyData->logic_sector_size_hi << 16) |
+ AtaIdentifyData->logic_sector_size_lo) * sizeof (UINT16)
+ );
+ }
+ return EFI_SUCCESS;
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+}
+/**
+ Send ATA command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaLow The value in LBA_LOW register
+ @param LbaMiddle The value in LBA_MIDDLE register
+ @param LbaHigh The value in LBA_HIGH register
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT8 Feature,
+ IN UINT8 SectorCount,
+ IN UINT8 LbaLow,
+ IN UINT8 LbaMiddle,
+ IN UINT8 LbaHigh
+ )
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set Lba mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMiddle);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Wait for command completion
+ // For ATAPI_SMART_CMD, we may need more timeout to let device
+ // adjust internal states.
+ //
+ if (AtaCommand == ATA_CMD_SMART) {
+ Status = WaitForBSYClear (IdeDev, ATASMARTTIMEOUT);
+ } else {
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The LBA address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ )
+{
+ EFI_STATUS Status;
+ UINT8 StatusRegister;
+ UINT8 SectorCount8;
+ UINT8 Feature8;
+ UINT8 LbaLow;
+ UINT8 LbaMid;
+ UINT8 LbaHigh;
+
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device (bit4), set LBA mode(bit6) (use 0xe0 for compatibility)
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | 0xe0)
+ );
+
+ //
+ // ATA commands for ATA device must be issued when DRDY is set
+ //
+ Status = DRDYReady (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Pass parameter into device register block
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, Device);
+
+ //
+ // Fill the feature register, which is a two-byte FIFO. Need write twice.
+ //
+ Feature8 = (UINT8) (Feature >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ Feature8 = (UINT8) Feature;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, Feature8);
+
+ //
+ // Fill the sector count register, which is a two-byte FIFO. Need write twice.
+ //
+ SectorCount8 = (UINT8) (SectorCount >> 8);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ SectorCount8 = (UINT8) SectorCount;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorCount, SectorCount8);
+
+ //
+ // Fill the start LBA registers, which are also two-byte FIFO
+ //
+ LbaLow = (UINT8) RShiftU64 (LbaAddress, 24);
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 32);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 40);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ LbaLow = (UINT8) LbaAddress;
+ LbaMid = (UINT8) RShiftU64 (LbaAddress, 8);
+ LbaHigh = (UINT8) RShiftU64 (LbaAddress, 16);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->SectorNumber, LbaLow);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb, LbaMid);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb, LbaHigh);
+
+ //
+ // Send command via Command Register
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, AtaCommand);
+
+ //
+ // Wait for command completion
+ //
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ATA_STSREG_ERR) == ATA_STSREG_ERR) {
+ //
+ // Failed to execute command, abort operation
+ //
+ return EFI_ABORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c
new file mode 100644
index 0000000000..1a3cb2e0a0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Atapi.c
@@ -0,0 +1,1952 @@
+/** @file
+ This file contains all helper functions on the ATAPI command
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IdeBus.h"
+
+/**
+ This function is used to get the current status of the media residing
+ in the LS-120 drive or ZIP drive. The media status is returned in the
+ Error Status.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS The media status is achieved successfully and the media
+ can be read/written.
+ @retval EFI_DEVICE_ERROR Get Media Status Command is failed.
+ @retval EFI_NO_MEDIA There is no media in the drive.
+ @retval EFI_WRITE_PROTECTED The media is writing protected.
+
+ @note This function must be called after the LS120EnableMediaStatus()
+ with second parameter set to TRUE
+ (means enable media status notification) is called.
+**/
+EFI_STATUS
+LS120GetMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 DeviceSelect;
+ UINT8 StatusValue;
+ EFI_STATUS EfiStatus;
+ //
+ // Poll Alternate Register for BSY clear within timeout.
+ //
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ //
+ // Poll Alternate Register for DRDY set within timeout.
+ // After device is selected, DRDY set indicates the device is ready to
+ // accept command.
+ //
+ EfiStatus = DRDYReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Get Media Status Command is sent
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xDA);
+
+ //
+ // BSY bit will clear after command is complete.
+ //
+ EfiStatus = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (EfiStatus)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // the media status is returned by the command in the ERROR register
+ //
+ StatusValue = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+
+ if ((StatusValue & BIT1) != 0) {
+ return EFI_NO_MEDIA;
+ }
+
+ if ((StatusValue & BIT6) != 0) {
+ return EFI_WRITE_PROTECTED;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+/**
+ This function is used to send Enable Media Status Notification Command
+ or Disable Media Status Notification Command.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param Enable a flag that indicates whether enable or disable media
+ status notification.
+ @retval EFI_SUCCESS If command completes successfully.
+ @retval EFI_DEVICE_ERROR If command failed.
+**/
+EFI_STATUS
+LS120EnableMediaStatus (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN BOOLEAN Enable
+ )
+{
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // Poll Alternate Register for BSY clear within timeout.
+ //
+ Status = WaitForBSYClear2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4 | 0xe0);
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ //
+ // Poll Alternate Register for DRDY set within timeout.
+ // After device is selected, DRDY set indicates the device is ready to
+ // accept command.
+ //
+ Status = DRDYReady2 (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Enable) {
+ //
+ // 0x95: Enable media status notification
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x95);
+ } else {
+ //
+ // 0x31: Disable media status notification
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x31);
+ }
+ //
+ // Set Feature Command is sent
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0xEF);
+
+ //
+ // BSY bit will clear after command is complete.
+ //
+ Status = WaitForBSYClear (IdeDev, ATATIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function reads the pending data in the device.
+
+ @param IdeDev Indicates the calling context.
+
+ @retval EFI_SUCCESS Successfully read.
+ @retval EFI_NOT_READY The BSY is set avoiding reading.
+
+**/
+EFI_STATUS
+AtapiReadPendingData (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 AltRegister;
+ UINT16 TempWordBuffer;
+
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ if ((AltRegister & ATA_STSREG_BSY) == ATA_STSREG_BSY) {
+ return EFI_NOT_READY;
+ }
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+ while ((TempWordBuffer & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ 1,
+ &TempWordBuffer
+ );
+ TempWordBuffer = IDEReadPortB (IdeDev->PciIo,IdeDev->IoPort->Alt.AltStatus);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called by either AtapiPacketCommandIn() or AtapiPacketCommandOut().
+ It is used to transfer data between host and device. The data direction is specified
+ by the fourth parameter.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param Buffer buffer contained data transferred between host and device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param Read flag used to determine the data transfer direction.
+ Read equals 1, means data transferred from device to host;
+ Read equals 0, means data transferred from host to device.
+ @param TimeOut timeout value for wait DRQ ready before each data stream's transfer.
+
+ @retval EFI_SUCCESS data is transferred successfully.
+ @retval EFI_DEVICE_ERROR the device failed to transfer data.
+**/
+EFI_STATUS
+PioReadWriteData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN BOOLEAN Read,
+ IN UINTN TimeOut
+ )
+{
+ //
+ // required transfer data in word unit.
+ //
+ UINT32 RequiredWordCount;
+
+ //
+ // actual transfer data in word unit.
+ //
+ UINT32 ActualWordCount;
+ UINT32 WordCount;
+ EFI_STATUS Status;
+ UINT16 *PtrBuffer;
+
+ //
+ // No data transfer is premitted.
+ //
+ if (ByteCount == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // for performance, we assert the ByteCount is an even number
+ // which is actually a resonable assumption
+ ASSERT((ByteCount%2) == 0);
+
+ PtrBuffer = Buffer;
+ RequiredWordCount = ByteCount / 2;
+ //
+ // ActuralWordCount means the word count of data really transferred.
+ //
+ ActualWordCount = 0;
+
+ while (ActualWordCount < RequiredWordCount) {
+
+ //
+ // before each data transfer stream, the host should poll DRQ bit ready,
+ // to see whether indicates device is ready to transfer data.
+ //
+ Status = DRQReady2 (IdeDev, TimeOut);
+ if (EFI_ERROR (Status)) {
+ return CheckErrorStatus (IdeDev);
+ }
+
+ //
+ // read Status Register will clear interrupt
+ //
+ IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // get current data transfer size from Cylinder Registers.
+ //
+ WordCount = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderMsb) << 8;
+ WordCount = WordCount | IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->CylinderLsb);
+ WordCount = WordCount & 0xffff;
+ WordCount /= 2;
+
+ WordCount = MIN (WordCount, (RequiredWordCount - ActualWordCount));
+
+ if (Read) {
+ IDEReadPortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ WordCount,
+ PtrBuffer
+ );
+ } else {
+ IDEWritePortWMultiple (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Data,
+ WordCount,
+ PtrBuffer
+ );
+ }
+
+ PtrBuffer += WordCount;
+ ActualWordCount += WordCount;
+ }
+
+ if (Read) {
+ //
+ // In the case where the drive wants to send more data than we need to read,
+ // the DRQ bit will be set and cause delays from DRQClear2().
+ // We need to read data from the drive until it clears DRQ so we can move on.
+ //
+ AtapiReadPendingData (IdeDev);
+ }
+
+ //
+ // After data transfer is completed, normally, DRQ bit should clear.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // read status register to check whether error happens.
+ //
+ return CheckErrorStatus (IdeDev);
+}
+
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Data In Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Packet pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+ @param Buffer buffer contained data transferred from device to host.
+ @param ByteCount data size in byte unit of the buffer.
+ @param TimeOut this parameter is used to specify the timeout value for the
+ PioReadWriteData() function.
+
+ @retval EFI_SUCCESS send out the ATAPI packet command successfully
+ and device sends data successfully.
+ @retval EFI_DEVICE_ERROR the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+{
+ UINT16 *CommandIndex;
+ EFI_STATUS Status;
+ UINT32 Count;
+
+ //
+ // Set all the command parameters by fill related registers.
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to let the device
+ // determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+ );
+
+ //
+ // ATA_DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+ Status = DRQReady (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Send out command packet
+ //
+ CommandIndex = Packet->Data16;
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {
+
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+ gBS->Stall (10);
+ }
+
+ //
+ // call PioReadWriteData() function to get
+ // requested transfer data form device.
+ //
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 1, TimeOut);
+}
+/**
+ This function is used to send out ATAPI commands conforms to the Packet Command
+ with PIO Data Out Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Packet pointer pointing to ATAPI_PACKET_COMMAND data structure
+ which contains the contents of the command.
+ @param Buffer buffer contained data transferred from host to device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param TimeOut this parameter is used to specify the timeout value
+ for the PioReadWriteData() function.
+ @retval EFI_SUCCESS send out the ATAPI packet command successfully
+ and device received data successfully.
+ @retval EFI_DEVICE_ERROR the device failed to send data.
+
+**/
+EFI_STATUS
+AtapiPacketCommandOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATAPI_PACKET_COMMAND *Packet,
+ IN UINT16 *Buffer,
+ IN UINT32 ByteCount,
+ IN UINTN TimeOut
+ )
+{
+ UINT16 *CommandIndex;
+ EFI_STATUS Status;
+ UINT32 Count;
+
+ //
+ // set all the command parameters
+ // Before write to all the following registers, BSY and DRQ must be 0.
+ //
+ Status = DRQClear2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select device via Device/Head Register.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((IdeDev->Device << 4) | ATA_DEFAULT_CMD) // ATA_DEFAULT_CMD: 0xa0 (1010,0000)
+ );
+
+ //
+ // No OVL; No DMA
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Feature, 0x00);
+
+ //
+ // set the transfersize to ATAPI_MAX_BYTE_COUNT to
+ // let the device determine how many data should be transferred.
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT & 0x00ff)
+ );
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb,
+ (UINT8) (ATAPI_MAX_BYTE_COUNT >> 8)
+ );
+
+ //
+ // DEFAULT_CTL:0x0a (0000,1010)
+ // Disable interrupt
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, ATA_DEFAULT_CTL);
+
+ //
+ // Send Packet command to inform device
+ // that the following data bytes are command packet.
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, ATA_CMD_PACKET);
+
+ Status = DRQReady2 (IdeDev, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Send out command packet
+ //
+ CommandIndex = Packet->Data16;
+ for (Count = 0; Count < 6; Count++, CommandIndex++) {
+ IDEWritePortW (IdeDev->PciIo, IdeDev->IoPort->Data, *CommandIndex);
+ gBS->Stall (10);
+ }
+
+ //
+ // call PioReadWriteData() function to send requested transfer data to device.
+ //
+ return PioReadWriteData (IdeDev, Buffer, ByteCount, 0, TimeOut);
+}
+/**
+ Sends out ATAPI Inquiry Packet Command to the specified device. This command will
+ return INQUIRY data of the device.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Inquiry command completes successfully.
+ @retval EFI_DEVICE_ERROR Inquiry command failed.
+
+ @note Parameter "IdeDev" will be updated in this function.
+
+**/
+EFI_STATUS
+AtapiInquiry (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ ATAPI_INQUIRY_DATA *InquiryData;
+
+ //
+ // prepare command packet for the ATAPI Inquiry Packet Command.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = ATA_CMD_INQUIRY;
+ Packet.Inquiry.page_code = 0;
+ Packet.Inquiry.allocation_length = (UINT8) sizeof (ATAPI_INQUIRY_DATA);
+
+ InquiryData = AllocatePool (sizeof (ATAPI_INQUIRY_DATA));
+ if (InquiryData == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Send command packet and get requested Inquiry data.
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) InquiryData,
+ sizeof (ATAPI_INQUIRY_DATA),
+ ATAPITIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (InquiryData);
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->InquiryData = InquiryData;
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is called by DiscoverIdeDevice() during its device
+ identification.
+ Its main purpose is to get enough information for the device media
+ to fill in the Media data structure of the Block I/O Protocol interface.
+
+ There are 5 steps to reach such objective:
+ 1. Sends out the ATAPI Identify Command to the specified device.
+ Only ATAPI device responses to this command. If the command succeeds,
+ it returns the Identify data structure which filled with information
+ about the device. Since the ATAPI device contains removable media,
+ the only meaningful information is the device module name.
+ 2. Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return inquiry data of the device, which contains
+ the device type information.
+ 3. Allocate sense data space for future use. We don't detect the media
+ presence here to improvement boot performance, especially when CD
+ media is present. The media detection will be performed just before
+ each BLK_IO read/write
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Identify ATAPI device successfully.
+ @retval EFI_DEVICE_ERROR ATAPI Identify Device Command failed or device type
+ is not supported by this IDE driver.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory for sense data failed
+
+ @note Parameter "IdeDev" will be updated in this function.
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_IDENTIFY_DATA *AtapiIdentifyPointer;
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // device select bit
+ //
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+ AtapiIdentifyPointer = AllocatePool (sizeof (EFI_IDENTIFY_DATA));
+ if (AtapiIdentifyPointer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Send ATAPI Identify Command to get IDENTIFY data.
+ //
+ Status = AtaPioDataIn (
+ IdeDev,
+ (VOID *) AtapiIdentifyPointer,
+ sizeof (EFI_IDENTIFY_DATA),
+ ATA_CMD_IDENTIFY_DEVICE,
+ DeviceSelect,
+ 0,
+ 0,
+ 0,
+ 0
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (AtapiIdentifyPointer);
+ return EFI_DEVICE_ERROR;
+ }
+
+ IdeDev->IdData = AtapiIdentifyPointer;
+ PrintAtaModuleName (IdeDev);
+
+ //
+ // Send ATAPI Inquiry Packet Command to get INQUIRY data.
+ //
+ Status = AtapiInquiry (IdeDev);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (IdeDev->IdData);
+ //
+ // Make sure the pIdData will not be freed again.
+ //
+ IdeDev->IdData = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Get media removable info from INQUIRY data.
+ //
+ IdeDev->BlkIo.Media->RemovableMedia = (UINT8) ((IdeDev->InquiryData->RMB & 0x80) == 0x80);
+
+ //
+ // Identify device type via INQUIRY data.
+ //
+ switch (IdeDev->InquiryData->peripheral_type & 0x1f) {
+
+ //
+ // Magnetic Disk
+ //
+ case 0x00:
+
+ //
+ // device is LS120 or ZIP drive.
+ //
+ IdeDev->Type = IdeMagnetic;
+
+ IdeDev->BlkIo.Media->MediaId = 0;
+ //
+ // Give initial value
+ //
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+ break;
+
+ //
+ // CD-ROM
+ //
+ case 0x05:
+
+ IdeDev->Type = IdeCdRom;
+ IdeDev->BlkIo.Media->MediaId = 0;
+ //
+ // Give initial value
+ //
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ IdeDev->BlkIo.Media->BlockSize = 0x800;
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+ break;
+
+ //
+ // Tape
+ //
+ case 0x01:
+
+ //
+ // WORM
+ //
+ case 0x04:
+
+ //
+ // Optical
+ //
+ case 0x07:
+
+ default:
+ IdeDev->Type = IdeUnknown;
+ gBS->FreePool (IdeDev->IdData);
+ gBS->FreePool (IdeDev->InquiryData);
+ //
+ // Make sure the pIdData and pInquiryData will not be freed again.
+ //
+ IdeDev->IdData = NULL;
+ IdeDev->InquiryData = NULL;
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // original sense data numbers
+ //
+ IdeDev->SenseDataNumber = 20;
+
+ IdeDev->SenseData = AllocatePool (IdeDev->SenseDataNumber * sizeof (ATAPI_REQUEST_SENSE_DATA));
+ if (IdeDev->SenseData == NULL) {
+ gBS->FreePool (IdeDev->IdData);
+ gBS->FreePool (IdeDev->InquiryData);
+ //
+ // Make sure the pIdData and pInquiryData will not be freed again.
+ //
+ IdeDev->IdData = NULL;
+ IdeDev->InquiryData = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Sends out ATAPI Request Sense Packet Command to the specified device. This command
+ will return all the current Sense data in the device. This function will pack
+ all the Sense data in one single buffer.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param SenseCounts allocated in this function, and freed by the calling function.
+ This buffer is used to accommodate all the sense data returned
+ by the device.
+
+ @retval EFI_SUCCESS Request Sense command completes successfully.
+ @retval EFI_DEVICE_ERROR Request Sense command failed.
+**/
+EFI_STATUS
+AtapiRequestSense (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT UINTN *SenseCounts
+ )
+{
+ EFI_STATUS Status;
+ ATAPI_REQUEST_SENSE_DATA *Sense;
+ UINT16 *Ptr;
+ BOOLEAN FetchSenseData;
+ ATAPI_PACKET_COMMAND Packet;
+
+ *SenseCounts = 0;
+
+ ZeroMem (IdeDev->SenseData, sizeof (ATAPI_REQUEST_SENSE_DATA) * (IdeDev->SenseDataNumber));
+ //
+ // fill command packet for Request Sense Packet Command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.RequestSence.opcode = ATA_CMD_REQUEST_SENSE;
+ Packet.RequestSence.allocation_length = (UINT8) sizeof (ATAPI_REQUEST_SENSE_DATA);
+
+ //
+ // initialize pointer
+ //
+ Ptr = (UINT16 *) IdeDev->SenseData;
+ //
+ // request sense data from device continuously until no sense data
+ // exists in the device.
+ //
+ for (FetchSenseData = TRUE; FetchSenseData;) {
+
+ Sense = (ATAPI_REQUEST_SENSE_DATA *) Ptr;
+
+ //
+ // send out Request Sense Packet Command and get one Sense data form device
+ //
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ Ptr,
+ sizeof (ATAPI_REQUEST_SENSE_DATA),
+ ATAPITIMEOUT
+ );
+ //
+ // failed to get Sense data
+ //
+ if (EFI_ERROR (Status)) {
+ if (*SenseCounts == 0) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return EFI_SUCCESS;
+ }
+ }
+
+ (*SenseCounts)++;
+ //
+ // We limit MAX sense data count to 20 in order to avoid dead loop. Some
+ // incompatible ATAPI devices don't retrive NO_SENSE when there is no media.
+ // In this case, dead loop occurs if we don't have a gatekeeper. 20 is
+ // supposed to be large enough for any ATAPI device.
+ //
+ if ((Sense->sense_key != ATA_SK_NO_SENSE) && ((*SenseCounts) < 20)) {
+ //
+ // Ptr is word-based pointer
+ //
+ Ptr += (sizeof (ATAPI_REQUEST_SENSE_DATA) + 1) >> 1;
+
+ } else {
+ //
+ // when no sense key, skip out the loop
+ //
+ FetchSenseData = FALSE;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to parse sense data. Only the first sense data is honoured
+
+ @param IdeDev Indicates the calling context.
+ @param SenseCount Count of sense data.
+ @param Result The parsed result.
+
+ @retval EFI_SUCCESS Successfully parsed.
+ @retval EFI_INVALID_PARAMETER Count of sense data is zero.
+
+**/
+EFI_STATUS
+ParseSenseData (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN SenseCount,
+ OUT SENSE_RESULT *Result
+ )
+{
+ ATAPI_REQUEST_SENSE_DATA *SenseData;
+
+ if (SenseCount == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Only use the first sense data
+ //
+ SenseData = IdeDev->SenseData;
+ *Result = SenseOtherSense;
+
+ switch (SenseData->sense_key) {
+ case ATA_SK_NO_SENSE:
+ *Result = SenseNoSenseKey;
+ break;
+ case ATA_SK_NOT_READY:
+ switch (SenseData->addnl_sense_code) {
+ case ATA_ASC_NO_MEDIA:
+ *Result = SenseNoMedia;
+ break;
+ case ATA_ASC_MEDIA_UPSIDE_DOWN:
+ *Result = SenseMediaError;
+ break;
+ case ATA_ASC_NOT_READY:
+ if (SenseData->addnl_sense_code_qualifier == ATA_ASCQ_IN_PROGRESS) {
+ *Result = SenseDeviceNotReadyNeedRetry;
+ } else {
+ *Result = SenseDeviceNotReadyNoRetry;
+ }
+ break;
+ }
+ break;
+ case ATA_SK_UNIT_ATTENTION:
+ if (SenseData->addnl_sense_code == ATA_ASC_MEDIA_CHANGE) {
+ *Result = SenseMediaChange;
+ }
+ break;
+ case ATA_SK_MEDIUM_ERROR:
+ switch (SenseData->addnl_sense_code) {
+ case ATA_ASC_MEDIA_ERR1:
+ case ATA_ASC_MEDIA_ERR2:
+ case ATA_ASC_MEDIA_ERR3:
+ case ATA_ASC_MEDIA_ERR4:
+ *Result = SenseMediaError;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sends out ATAPI Test Unit Ready Packet Command to the specified device
+ to find out whether device is accessible.
+
+ @param IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param SResult Sense result for this packet command.
+
+ @retval EFI_SUCCESS Device is accessible.
+ @retval EFI_DEVICE_ERROR Device is not accessible.
+
+**/
+EFI_STATUS
+AtapiTestUnitReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT SENSE_RESULT *SResult
+ )
+{
+ ATAPI_PACKET_COMMAND Packet;
+ EFI_STATUS Status;
+ UINTN SenseCount;
+
+ //
+ // fill command packet
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.TestUnitReady.opcode = ATA_CMD_TEST_UNIT_READY;
+
+ //
+ // send command packet
+ //
+ Status = AtapiPacketCommandIn (IdeDev, &Packet, NULL, 0, ATAPITIMEOUT);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = AtapiRequestSense (IdeDev, &SenseCount);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ParseSenseData (IdeDev, SenseCount, SResult);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Sends out ATAPI Read Capacity Packet Command to the specified device.
+ This command will return the information regarding the capacity of the
+ media in the device.
+
+ Current device status will impact device's response to the Read Capacity
+ Command. For example, if the device once reset, the Read Capacity
+ Command will fail. The Sense data record the current device status, so
+ if the Read Capacity Command failed, the Sense data must be requested
+ and be analyzed to determine if the Read Capacity Command should retry.
+
+ @param IdeDev Pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param SResult Sense result for this packet command
+
+ @retval EFI_SUCCESS Read Capacity Command finally completes successfully.
+ @retval EFI_DEVICE_ERROR Read Capacity Command failed because of device error.
+ @retval EFI_NOT_READY Operation succeeds but returned capacity is 0
+
+ @note Parameter "IdeDev" will be updated in this function.
+
+
+**/
+EFI_STATUS
+AtapiReadCapacity (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT SENSE_RESULT *SResult
+ )
+{
+ //
+ // status returned by Read Capacity Packet Command
+ //
+ EFI_STATUS Status;
+ EFI_STATUS SenseStatus;
+ ATAPI_PACKET_COMMAND Packet;
+ UINTN SenseCount;
+
+ //
+ // used for capacity data returned from ATAPI device
+ //
+ ATAPI_READ_CAPACITY_DATA Data;
+ ATAPI_READ_FORMAT_CAPACITY_DATA FormatData;
+
+ ZeroMem (&Data, sizeof (Data));
+ ZeroMem (&FormatData, sizeof (FormatData));
+
+ if (IdeDev->Type == IdeCdRom) {
+
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.Inquiry.opcode = ATA_CMD_READ_CAPACITY;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &Data,
+ sizeof (ATAPI_READ_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+
+ } else {
+ //
+ // Type == IdeMagnetic
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Packet.ReadFormatCapacity.opcode = ATA_CMD_READ_FORMAT_CAPACITY;
+ Packet.ReadFormatCapacity.allocation_length_lo = 12;
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) &FormatData,
+ sizeof (ATAPI_READ_FORMAT_CAPACITY_DATA),
+ ATAPITIMEOUT
+ );
+ }
+
+ if (Status == EFI_TIMEOUT) {
+ return Status;
+ }
+
+ SenseStatus = AtapiRequestSense (IdeDev, &SenseCount);
+
+ if (!EFI_ERROR (SenseStatus)) {
+ ParseSenseData (IdeDev, SenseCount, SResult);
+
+ if (!EFI_ERROR (Status) && *SResult == SenseNoSenseKey) {
+ if (IdeDev->Type == IdeCdRom) {
+
+ IdeDev->BlkIo.Media->LastBlock = (Data.LastLba3 << 24) |
+ (Data.LastLba2 << 16) |
+ (Data.LastLba1 << 8) |
+ Data.LastLba0;
+
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+
+ //
+ // Because the user data portion in the sector of the Data CD supported
+ // is always 0x800
+ //
+ IdeDev->BlkIo.Media->BlockSize = 0x800;
+ }
+
+ if (IdeDev->Type == IdeMagnetic) {
+
+ if (FormatData.DesCode == 3) {
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ } else {
+
+ IdeDev->BlkIo.Media->LastBlock = (FormatData.LastLba3 << 24) |
+ (FormatData.LastLba2 << 16) |
+ (FormatData.LastLba1 << 8) |
+ FormatData.LastLba0;
+ if (IdeDev->BlkIo.Media->LastBlock != 0) {
+ IdeDev->BlkIo.Media->LastBlock--;
+
+ IdeDev->BlkIo.Media->BlockSize = (FormatData.BlockSize2 << 16) |
+ (FormatData.BlockSize1 << 8) |
+ FormatData.BlockSize0;
+
+ IdeDev->BlkIo.Media->MediaPresent = TRUE;
+ } else {
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ //
+ // Return EFI_NOT_READY operation succeeds but returned capacity is 0
+ //
+ return EFI_NOT_READY;
+ }
+
+ IdeDev->BlkIo.Media->BlockSize = 0x200;
+
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+
+ } else {
+ return EFI_DEVICE_ERROR;
+ }
+}
+/**
+ This function is used to test the current media write-protected or not residing
+ in the LS-120 drive or ZIP drive.
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param WriteProtected if True, current media is write protected.
+ if FALSE, current media is writable
+
+ @retval EFI_SUCCESS The media write-protected status is achieved successfully
+ @retval EFI_DEVICE_ERROR Get Media Status Command is failed.
+**/
+EFI_STATUS
+IsLS120orZipWriteProtected (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *WriteProtected
+ )
+{
+ EFI_STATUS Status;
+
+ *WriteProtected = FALSE;
+
+ Status = LS120EnableMediaStatus (IdeDev, TRUE);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // the Get Media Status Command is only valid
+ // if a Set Features/Enable Media Status Command has been priviously issued.
+ //
+ if (LS120GetMediaStatus (IdeDev) == EFI_WRITE_PROTECTED) {
+
+ *WriteProtected = TRUE;
+ } else {
+
+ *WriteProtected = FALSE;
+ }
+
+ //
+ // After Get Media Status Command completes,
+ // Set Features/Disable Media Command should be sent.
+ //
+ Status = LS120EnableMediaStatus (IdeDev, FALSE);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Used before read/write blocks from/to ATAPI device media. Since ATAPI device
+ media is removable, it is necessary to detect whether media is present and
+ get current present media's information, and if media has been changed, Block
+ I/O Protocol need to be reinstalled.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param MediaChange return value that indicates if the media of the device has been
+ changed.
+
+ @retval EFI_SUCCESS media found successfully.
+ @retval EFI_DEVICE_ERROR any error encounters during media detection.
+ @retval EFI_NO_MEDIA media not found.
+
+ @note
+ parameter IdeDev may be updated in this function.
+
+**/
+EFI_STATUS
+AtapiDetectMedia (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ OUT BOOLEAN *MediaChange
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS CleanStateStatus;
+ EFI_BLOCK_IO_MEDIA OldMediaInfo;
+ UINTN RetryTimes;
+ UINTN RetryNotReady;
+ SENSE_RESULT SResult;
+ BOOLEAN WriteProtected;
+
+ CopyMem (&OldMediaInfo, IdeDev->BlkIo.Media, sizeof (EFI_BLOCK_IO_MEDIA));
+ *MediaChange = FALSE;
+ //
+ // Retry for SenseDeviceNotReadyNeedRetry.
+ // Each retry takes 1s and we limit the upper boundary to
+ // 120 times about 2 min.
+ //
+ RetryNotReady = 120;
+
+ //
+ // Do Test Unit Ready
+ //
+ DoTUR:
+ //
+ // Retry 5 times
+ //
+ RetryTimes = 5;
+ while (RetryTimes != 0) {
+
+ Status = AtapiTestUnitReady (IdeDev, &SResult);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Test Unit Ready error without sense data.
+ // For some devices, this means there's extra data
+ // that has not been read, so we read these extra
+ // data out before going on.
+ //
+ CleanStateStatus = AtapiReadPendingData (IdeDev);
+ if (EFI_ERROR (CleanStateStatus)) {
+ //
+ // Busy wait failed, try again
+ //
+ RetryTimes--;
+ }
+ //
+ // Try again without counting down RetryTimes
+ //
+ continue;
+ } else {
+ switch (SResult) {
+ case SenseNoSenseKey:
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ goto Done;
+ } else {
+ //
+ // Media present but the internal structure need refreshed.
+ // Try Read Capacity
+ //
+ goto DoRC;
+ }
+ break;
+
+ case SenseDeviceNotReadyNeedRetry:
+ if (--RetryNotReady == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ gBS->Stall (1000 * STALL_1_MILLI_SECOND);
+ continue;
+ break;
+
+ case SenseNoMedia:
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNoRetry:
+ case SenseMediaError:
+ return EFI_DEVICE_ERROR;
+
+ case SenseMediaChange:
+ IdeDev->BlkIo.Media->MediaId++;
+ goto DoRC;
+ break;
+
+ default:
+ RetryTimes--;
+ break;
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ //
+ // Do Read Capacity
+ //
+ DoRC:
+ RetryTimes = 5;
+
+ while (RetryTimes != 0) {
+
+ Status = AtapiReadCapacity (IdeDev, &SResult);
+
+ if (EFI_ERROR (Status)) {
+ RetryTimes--;
+ continue;
+ } else {
+ switch (SResult) {
+ case SenseNoSenseKey:
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNeedRetry:
+ //
+ // We use Test Unit Ready to retry which
+ // is faster.
+ //
+ goto DoTUR;
+ break;
+
+ case SenseNoMedia:
+ IdeDev->BlkIo.Media->MediaPresent = FALSE;
+ IdeDev->BlkIo.Media->LastBlock = 0;
+ goto Done;
+ break;
+
+ case SenseDeviceNotReadyNoRetry:
+ case SenseMediaError:
+ return EFI_DEVICE_ERROR;
+
+ case SenseMediaChange:
+ IdeDev->BlkIo.Media->MediaId++;
+ continue;
+ break;
+
+ default:
+ RetryTimes--;
+ break;
+ }
+ }
+ }
+
+ return EFI_DEVICE_ERROR;
+
+ Done:
+ //
+ // the following code is to check the write-protected for LS120 media
+ //
+ if ((IdeDev->BlkIo.Media->MediaPresent) && (IdeDev->Type == IdeMagnetic)) {
+
+ Status = IsLS120orZipWriteProtected (IdeDev, &WriteProtected);
+ if (!EFI_ERROR (Status)) {
+
+ if (WriteProtected) {
+
+ IdeDev->BlkIo.Media->ReadOnly = TRUE;
+ } else {
+
+ IdeDev->BlkIo.Media->ReadOnly = FALSE;
+ }
+
+ }
+ }
+
+ if (IdeDev->BlkIo.Media->MediaId != OldMediaInfo.MediaId) {
+ //
+ // Media change information got from the device
+ //
+ *MediaChange = TRUE;
+ }
+
+ if (IdeDev->BlkIo.Media->ReadOnly != OldMediaInfo.ReadOnly) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->BlockSize != OldMediaInfo.BlockSize) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->LastBlock != OldMediaInfo.LastBlock) {
+ *MediaChange = TRUE;
+ IdeDev->BlkIo.Media->MediaId += 1;
+ }
+
+ if (IdeDev->BlkIo.Media->MediaPresent != OldMediaInfo.MediaPresent) {
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ //
+ // when change from no media to media present, reset the MediaId to 1.
+ //
+ IdeDev->BlkIo.Media->MediaId = 1;
+ } else {
+ //
+ // when no media, reset the MediaId to zero.
+ //
+ IdeDev->BlkIo.Media->MediaId = 0;
+ }
+
+ *MediaChange = TRUE;
+ }
+
+ //
+ // if any change on current existing media,
+ // the Block I/O protocol need to be reinstalled.
+ //
+ if (*MediaChange) {
+ gBS->ReinstallProtocolInterface (
+ IdeDev->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &IdeDev->BlkIo,
+ &IdeDev->BlkIo
+ );
+ }
+
+ if (IdeDev->BlkIo.Media->MediaPresent) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NO_MEDIA;
+ }
+}
+
+/**
+ This function is called by the AtapiBlkIoReadBlocks() to perform
+ read from media in block unit.
+
+ The main command used to access media here is READ(10) Command.
+ READ(10) Command requests that the ATAPI device media transfer
+ specified data to the host. Data is transferred in block(sector)
+ unit. The maximum number of blocks that can be transferred once is
+ 65536. This is the main difference between READ(10) and READ(12)
+ Command. The maximum number of blocks in READ(12) is 2 power 32.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Buffer A pointer to the destination buffer for the data.
+ @param Lba The starting logical block address to read from on the
+ device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtapiPacketCommandIn() function.
+
+**/
+EFI_STATUS
+AtapiReadSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ10_CMD *Read10Packet;
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT16 SectorCount;
+ VOID *PtrBuffer;
+ UINT16 MaxBlock;
+ UINTN TimeOut;
+
+ //
+ // fill command packet for Read(10) command
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+ Lba32 = (UINT32) Lba;
+ PtrBuffer = Buffer;
+
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) Command
+ //
+ MaxBlock = 65535;
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining <= MaxBlock) {
+
+ SectorCount = (UINT16) BlocksRemaining;
+ } else {
+
+ SectorCount = MaxBlock;
+ }
+
+ //
+ // fill the Packet data structure
+ //
+
+ Read10Packet->opcode = ATA_CMD_READ_10;
+
+ //
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
+ // Lba0 is MSB, Lba3 is LSB
+ //
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
+
+ //
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.
+ // TranLen0 is MSB, TranLen is LSB
+ //
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
+
+ ByteCount = SectorCount * BlockSize;
+
+ if (IdeDev->Type == IdeCdRom) {
+ TimeOut = CDROMLONGTIMEOUT;
+ } else {
+ TimeOut = ATAPILONGTIMEOUT;
+ }
+
+ Status = AtapiPacketCommandIn (
+ IdeDev,
+ &Packet,
+ (UINT16 *) PtrBuffer,
+ ByteCount,
+ TimeOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = (UINT8 *) PtrBuffer + SectorCount * BlockSize;
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+
+/**
+ This function is called by the AtapiBlkIoWriteBlocks() to perform
+ write onto media in block unit.
+ The main command used to access media here is Write(10) Command.
+ Write(10) Command requests that the ATAPI device media transfer
+ specified data to the host. Data is transferred in block (sector)
+ unit. The maximum number of blocks that can be transferred once is
+ 65536.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param Buffer A pointer to the source buffer for the data.
+ @param Lba The starting logical block address to write onto
+ the device media.
+ @param NumberOfBlocks The number of transfer data blocks.
+
+ @return status is fully dependent on the return status of AtapiPacketCommandOut() function.
+
+**/
+EFI_STATUS
+AtapiWriteSectors (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN EFI_LBA Lba,
+ IN UINTN NumberOfBlocks
+ )
+{
+
+ ATAPI_PACKET_COMMAND Packet;
+ ATAPI_READ10_CMD *Read10Packet;
+
+ EFI_STATUS Status;
+ UINTN BlocksRemaining;
+ UINT32 Lba32;
+ UINT32 BlockSize;
+ UINT32 ByteCount;
+ UINT16 SectorCount;
+ VOID *PtrBuffer;
+ UINT16 MaxBlock;
+
+ //
+ // fill command packet for Write(10) command
+ // Write(10) command packet has the same data structure as
+ // Read(10) command packet,
+ // so here use the Read10Packet data structure
+ // for the Write(10) command packet.
+ //
+ ZeroMem (&Packet, sizeof (ATAPI_PACKET_COMMAND));
+ Read10Packet = &Packet.Read10;
+
+ Lba32 = (UINT32) Lba;
+ PtrBuffer = Buffer;
+
+ BlockSize = IdeDev->BlkIo.Media->BlockSize;
+
+ //
+ // limit the data bytes that can be transferred by one Read(10) Command
+ //
+ MaxBlock = (UINT16) (65536 / BlockSize);
+
+ BlocksRemaining = NumberOfBlocks;
+
+ Status = EFI_SUCCESS;
+ while (BlocksRemaining > 0) {
+
+ if (BlocksRemaining >= MaxBlock) {
+ SectorCount = MaxBlock;
+ } else {
+ SectorCount = (UINT16) BlocksRemaining;
+ }
+
+ //
+ // Command code is WRITE_10.
+ //
+ Read10Packet->opcode = ATA_CMD_WRITE_10;
+
+ //
+ // Lba0 ~ Lba3 specify the start logical block address of the data transfer.
+ // Lba0 is MSB, Lba3 is LSB
+ //
+ Read10Packet->Lba3 = (UINT8) (Lba32 & 0xff);
+ Read10Packet->Lba2 = (UINT8) (Lba32 >> 8);
+ Read10Packet->Lba1 = (UINT8) (Lba32 >> 16);
+ Read10Packet->Lba0 = (UINT8) (Lba32 >> 24);
+
+ //
+ // TranLen0 ~ TranLen1 specify the transfer length in block unit.
+ // TranLen0 is MSB, TranLen is LSB
+ //
+ Read10Packet->TranLen1 = (UINT8) (SectorCount & 0xff);
+ Read10Packet->TranLen0 = (UINT8) (SectorCount >> 8);
+
+ ByteCount = SectorCount * BlockSize;
+
+ Status = AtapiPacketCommandOut (
+ IdeDev,
+ &Packet,
+ (UINT16 *) PtrBuffer,
+ ByteCount,
+ ATAPILONGTIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Lba32 += SectorCount;
+ PtrBuffer = ((UINT8 *) PtrBuffer + SectorCount * BlockSize);
+ BlocksRemaining -= SectorCount;
+ }
+
+ return Status;
+}
+/**
+ This function is used to implement the Soft Reset on the specified
+ ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
+ Soft Reset Command special for ATAPI device, and it only take effects
+ on the specified ATAPI device, not on the whole IDE bus.
+ Since the ATAPI soft reset is needed when device is in exceptional
+ condition (such as BSY bit is always set ), I think the Soft Reset
+ command should be sent without waiting for the BSY clear and DRDY
+ set.
+ This function is called by IdeBlkIoReset(),
+ a interface function of Block I/O protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Soft reset completes successfully.
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 Command;
+ UINT8 DeviceSelect;
+ EFI_STATUS Status;
+
+ //
+ // for ATAPI device, no need to wait DRDY ready after device selecting.
+ // (bit7 and bit5 are both set to 1 for backward compatibility)
+ //
+ DeviceSelect = (UINT8) (((BIT7 | BIT5) | (IdeDev->Device << 4)));
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Head, DeviceSelect);
+
+ Command = ATA_CMD_SOFT_RESET;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, Command);
+
+ //
+ // BSY cleared is the only status return to the host by the device
+ // when reset is completed.
+ // slave device needs at most 31s to clear BSY
+ //
+ Status = WaitForBSYClear (IdeDev, 31000);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // stall 5 seconds to make the device status stable
+ //
+ gBS->Stall (5000000);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the ATAPI implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit
+ ownership of the memory that data is read into.
+
+ @retval EFI_SUCCESS Read Blocks successfully.
+ @retval EFI_DEVICE_ERROR Read Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+**/
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+
+ BOOLEAN MediaChange;
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ATAPI device media is removable, so it is a must
+ // to detect media first before read operation
+ //
+ MediaChange = FALSE;
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+ if (EFI_ERROR (Status)) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ return Status;
+ }
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_NO_MEDIA;
+
+ }
+
+ if ((MediaId != Media->MediaId) || MediaChange) {
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if all the parameters are valid, then perform read sectors command
+ // to transfer data from device to host.
+ //
+ Status = AtapiReadSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Read blocks succeeded
+ //
+
+ //
+ // save the first block to the cache for performance
+ //
+ if (Lba == 0 && (IdeBlkIoDevice->Cache == NULL)) {
+ IdeBlkIoDevice->Cache = AllocatePool (BlockSize);
+ if (IdeBlkIoDevice->Cache!= NULL) {
+ CopyMem ((UINT8 *) IdeBlkIoDevice->Cache, (UINT8 *) Buffer, BlockSize);
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+/**
+ This function is the ATAPI implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the write request is for.
+ @param Lba The starting logical block address to write onto the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the source buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the memory that data is written from.
+
+ @retval EFI_SUCCESS Write Blocks successfully.
+ @retval EFI_DEVICE_ERROR Write Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @retval EFI_WRITE_PROTECTED The write protected is enabled or the media does not support write
+**/
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+
+ EFI_BLOCK_IO_MEDIA *Media;
+ UINTN BlockSize;
+ UINTN NumberOfBlocks;
+ EFI_STATUS Status;
+ BOOLEAN MediaChange;
+
+ if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // ATAPI device media is removable,
+ // so it is a must to detect media first before write operation
+ //
+ MediaChange = FALSE;
+ Status = AtapiDetectMedia (IdeBlkIoDevice, &MediaChange);
+ if (EFI_ERROR (Status)) {
+
+ if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return Status;
+ }
+
+ //
+ // Get the intrinsic block size
+ //
+ Media = IdeBlkIoDevice->BlkIo.Media;
+ BlockSize = Media->BlockSize;
+ NumberOfBlocks = BufferSize / BlockSize;
+
+ if (!(Media->MediaPresent)) {
+
+ if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_NO_MEDIA;
+ }
+
+ if ((MediaId != Media->MediaId) || MediaChange) {
+
+ if (Lba == 0 && IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Media->ReadOnly) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + NumberOfBlocks - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Media->IoAlign > 1) && (((UINTN) Buffer & (Media->IoAlign - 1)) != 0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // if all the parameters are valid,
+ // then perform write sectors command to transfer data from host to device.
+ //
+ Status = AtapiWriteSectors (IdeBlkIoDevice, Buffer, Lba, NumberOfBlocks);
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c
new file mode 100644
index 0000000000..5e376d72d7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.c
@@ -0,0 +1,278 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for ConPlatform driver.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IdeBus.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName = {
+ IDEBusComponentNameGetDriverName,
+ IDEBusComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gIDEBusComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) IDEBusComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) IDEBusComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIDEBusDriverNameTable[] = {
+ { "eng;en", (CHAR16 *) L"PCI IDE/ATAPI Bus Driver" },
+ { NULL , NULL }
+};
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mIDEBusControllerNameTable[] = {
+ { "eng;en", (CHAR16 *) L"PCI IDE/ATAPI Controller" },
+ { NULL , NULL }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIDEBusDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gIDEBusComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ //
+ // Make sure this driver is currently managing ControllHandle
+ //
+ Status = EfiTestManagedDevice (
+ ControllerHandle,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ &gEfiIdeControllerInitProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (ChildHandle == NULL) {
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mIDEBusControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gIDEBusComponentName)
+ );
+ }
+
+ Status = EfiTestChildHandle (
+ ControllerHandle,
+ ChildHandle,
+ &gEfiPciIoProtocolGuid
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the child context
+ //
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlockIo);
+
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ IdeBlkIoDevice->ControllerNameTable,
+ ControllerName,
+ (BOOLEAN)(This == &gIDEBusComponentName)
+ );
+}
+
+/**
+ Add the component name for the IDE/ATAPI device
+
+ @param IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ )
+{
+ UINTN StringIndex;
+ CHAR16 ModelName[41];
+
+ //
+ // Add Component Name for the IDE/ATAPI device that was discovered.
+ //
+ IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+ for (StringIndex = 0; StringIndex < 41; StringIndex++) {
+ ModelName[StringIndex] = IdeBlkIoDevicePtr->ModelName[StringIndex];
+ }
+
+ AddUnicodeString2 (
+ "eng",
+ gIDEBusComponentName.SupportedLanguages,
+ &IdeBlkIoDevicePtr->ControllerNameTable,
+ ModelName,
+ TRUE
+ );
+ AddUnicodeString2 (
+ "en",
+ gIDEBusComponentName2.SupportedLanguages,
+ &IdeBlkIoDevicePtr->ControllerNameTable,
+ ModelName,
+ FALSE
+ );
+
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h
new file mode 100644
index 0000000000..9a911a5ec9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/ComponentName.h
@@ -0,0 +1,166 @@
+/** @file
+
+ UEFI Component Name(2) protocol implementation header file for IDE Bus driver.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _IDE_BUS_COMPONENT_NAME_H_
+#define _IDE_BUS_COMPONENT_NAME_H_
+
+#define ADD_IDE_ATAPI_NAME(x) AddName ((x));
+
+extern EFI_COMPONENT_NAME_PROTOCOL gIDEBusComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gIDEBusComponentName2;
+
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+/**
+ Add the component name for the IDE/ATAPI device
+
+ @param IdeBlkIoDevicePtr A pointer to the IDE_BLK_IO_DEV instance.
+
+**/
+VOID
+AddName (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevicePtr
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c
new file mode 100644
index 0000000000..999e20e016
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverConfiguration.c
@@ -0,0 +1,292 @@
+/** @file
+ Implementation of UEFI Driver Configuration Protocol for IDE bus driver which
+ provides ability to set IDE bus controller specific options.
+
+ Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "IdeBus.h"
+
+CHAR16 *OptionString[4] = {
+ L"Enable Primary Master (Y/N)? -->",
+ L"Enable Primary Slave (Y/N)? -->",
+ L"Enable Secondary Master (Y/N)? -->",
+ L"Enable Secondary Slave (Y/N)? -->"
+};
+
+//
+// EFI Driver Configuration Protocol
+//
+EFI_DRIVER_CONFIGURATION_PROTOCOL gIDEBusDriverConfiguration = {
+ IDEBusDriverConfigurationSetOptions,
+ IDEBusDriverConfigurationOptionsValid,
+ IDEBusDriverConfigurationForceDefaults,
+ "eng"
+};
+
+/**
+ Interprete keyboard input.
+
+ @retval EFI_ABORTED Get an 'ESC' key inputed.
+ @retval EFI_SUCCESS Get an 'Y' or 'y' inputed.
+ @retval EFI_NOT_FOUND Get an 'N' or 'n' inputed..
+
+**/
+EFI_STATUS
+GetResponse (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+
+ while (TRUE) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (Status)) {
+ if (Key.ScanCode == SCAN_ESC) {
+ return EFI_ABORTED;
+ }
+
+ switch (Key.UnicodeChar) {
+
+ //
+ // fall through
+ //
+ case L'y':
+ case L'Y':
+ gST->ConOut->OutputString (gST->ConOut, L"Y\n");
+ return EFI_SUCCESS;
+
+ //
+ // fall through
+ //
+ case L'n':
+ case L'N':
+ gST->ConOut->OutputString (gST->ConOut, L"N\n");
+ return EFI_NOT_FOUND;
+ }
+
+ }
+ }
+}
+
+/**
+ Allows the user to set controller specific options for a controller that a
+ driver is currently managing.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to set options on.
+ @param ChildHandle The handle of the child controller to set options on.
+ This is an optional parameter that may be NULL.
+ It will be NULL for device drivers, and for a bus drivers
+ that wish to set options for the bus controller.
+ It will not be NULL for a bus driver that wishes to set
+ options for one of its child controllers.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the user interface that should be presented
+ to the user, and it must match one of the languages specified in
+ SupportedLanguages. The number of languages supported by a driver is up to
+ the driver writer.
+ @param ActionRequired A pointer to the action that the calling agent is required
+ to perform when this function returns.
+
+
+ @retval EFI_SUCCESS The driver specified by This successfully set the configuration
+ options for the controller specified by ControllerHandle..
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support setting configuration options for
+ the controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to set the configuration options for the
+ controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to set the configuration options for the
+ controller specified by ControllerHandle and ChildHandle
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+ UINT8 NewValue;
+ UINTN DataSize;
+ UINTN Index;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *ActionRequired = EfiDriverConfigurationActionNone;
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &Value
+ );
+
+ gST->ConOut->OutputString (gST->ConOut, L"IDE Bus Driver Configuration\n");
+ gST->ConOut->OutputString (gST->ConOut, L"===============================\n");
+
+ NewValue = 0;
+ for (Index = 0; Index < 4; Index++) {
+ gST->ConOut->OutputString (gST->ConOut, OptionString[Index]);
+
+ Status = GetResponse ();
+ if (Status == EFI_ABORTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (!EFI_ERROR (Status)) {
+ NewValue = (UINT8) (NewValue | (1 << Index));
+ }
+ }
+
+ if (EFI_ERROR (Status) || (NewValue != Value)) {
+ gRT->SetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (NewValue),
+ &NewValue
+ );
+
+ *ActionRequired = EfiDriverConfigurationActionRestartController;
+ } else {
+ *ActionRequired = EfiDriverConfigurationActionNone;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Tests to see if a controller's current configuration options are valid.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to test if it's current configuration options
+ are valid.
+ @param ChildHandle The handle of the child controller to test if it's current configuration
+ options are valid. This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a bus drivers that
+ wish to test the configuration options for the bus controller. It will
+ not be NULL for a bus driver that wishes to test configuration options for
+ one of its child controllers.
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and ChildHandle that is being
+ managed by the driver specified by This has a valid set of configuration
+ options.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing the controller
+ specified by ControllerHandle and ChildHandle.
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and ChildHandle that is being
+ managed by the driver specified by This has an invalid set of configuration
+ options.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINT8 Value;
+ UINTN DataSize;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ DataSize = sizeof (Value);
+ Status = gRT->GetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &Value
+ );
+ if (EFI_ERROR (Status) || Value > 0x0f) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Forces a driver to set the default configuration options for a controller.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to force default configuration options on.
+ @param ChildHandle The handle of the child controller to force default configuration
+ options on This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL for a bus
+ drivers that wish to force default configuration options for the bus
+ controller. It will not be NULL for a bus driver that wishes to force
+ default configuration options for one of its child controllers.
+ @param DefaultType The type of default configuration options to force on the controller
+ specified by ControllerHandle and ChildHandle.
+ @param ActionRequired A pointer to the action that the calling agent is required to perform
+ when this function returns.
+
+ @retval EFI_SUCCESS The driver specified by This successfully forced the
+ default configuration options on the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support forcing the default
+ configuration options on the controller specified by ControllerHandle
+ and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the configuration type
+ specified by DefaultType.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to force the default configuration
+ options on the controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to force the default configuration
+ options on the controller specified by ControllerHandle and ChildHandle.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ )
+{
+ UINT8 Value;
+
+ if (ChildHandle != NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Value = 0x0f;
+ gRT->SetVariable (
+ L"Configuration",
+ &gEfiCallerIdGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ sizeof (Value),
+ &Value
+ );
+ *ActionRequired = EfiDriverConfigurationActionRestartController;
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c
new file mode 100644
index 0000000000..73435dd7ac
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/DriverDiagnostics.c
@@ -0,0 +1,245 @@
+/** @file
+ Implementation of UEFI driver Dialnostics protocol which to perform diagnostic on the IDE
+ Bus controller.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "IdeBus.h"
+
+#define IDE_BUS_DIAGNOSTIC_ERROR L"PCI IDE/ATAPI Driver Diagnostics Failed"
+
+//
+// EFI Driver Diagnostics Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics = {
+ IDEBusDriverDiagnosticsRunDiagnostics,
+ "eng"
+};
+
+//
+// EFI Driver Diagnostics 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gIDEBusDriverDiagnostics2 = {
+ (EFI_DRIVER_DIAGNOSTICS2_RUN_DIAGNOSTICS) IDEBusDriverDiagnosticsRunDiagnostics,
+ "en"
+};
+
+/**
+ Runs diagnostics on a controller.
+
+ @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOLinstance.
+ @param ControllerHandle The handle of the controller to run diagnostics on.
+ @param ChildHandle The handle of the child controller to run diagnostics on
+ This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a
+ bus drivers that wish to run diagnostics on the bus controller.
+ It will not be NULL for a bus driver that wishes to run
+ diagnostics on one of its child controllers.
+ @param DiagnosticType Indicates type of diagnostics to perform on the controller
+ specified by ControllerHandle and ChildHandle.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language in which the optional error message should
+ be returned in Buffer, and it must match one of the languages
+ specified in SupportedLanguages. The number of languages supported by
+ a driver is up to the driver writer.
+ @param ErrorType A GUID that defines the format of the data returned in Buffer.
+ @param BufferSize The size, in bytes, of the data returned in Buffer.
+ @param Buffer A buffer that contains a Null-terminated Unicode string
+ plus some additional data whose format is defined by ErrorType.
+ Buffer is allocated by this function with AllocatePool(), and
+ it is the caller's responsibility to free it with a call to FreePool().
+
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and ChildHandle passed
+ the diagnostic.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ErrorType is NULL.
+ @retval EFI_INVALID_PARAMETER BufferType is NULL.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support running
+ diagnostics for the controller specified by ControllerHandle
+ and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the language
+ specified by Language.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to complete the
+ diagnostics.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to return the
+ status information in ErrorType, BufferSize,and Buffer.
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and ChildHandle
+ did not pass the diagnostic.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ UINT32 VendorDeviceId;
+ VOID *BlockBuffer;
+ CHAR8 *SupportedLanguages;
+ BOOLEAN Iso639Language;
+ BOOLEAN Found;
+ UINTN Index;
+
+ if (Language == NULL ||
+ ErrorType == NULL ||
+ Buffer == NULL ||
+ ControllerHandle == NULL ||
+ BufferSize == NULL) {
+
+ return EFI_INVALID_PARAMETER;
+ }
+
+ SupportedLanguages = This->SupportedLanguages;
+ Iso639Language = (BOOLEAN)(This == &gIDEBusDriverDiagnostics);
+ //
+ // Make sure Language is in the set of Supported Languages
+ //
+ Found = FALSE;
+ while (*SupportedLanguages != 0) {
+ if (Iso639Language) {
+ if (CompareMem (Language, SupportedLanguages, 3) == 0) {
+ Found = TRUE;
+ break;
+ }
+ SupportedLanguages += 3;
+ } else {
+ for (Index = 0; SupportedLanguages[Index] != 0 && SupportedLanguages[Index] != ';'; Index++);
+ if ((AsciiStrnCmp(SupportedLanguages, Language, Index) == 0) && (Language[Index] == 0)) {
+ Found = TRUE;
+ break;
+ }
+ SupportedLanguages += Index;
+ for (; *SupportedLanguages != 0 && *SupportedLanguages == ';'; SupportedLanguages++);
+ }
+ }
+ //
+ // If Language is not a member of SupportedLanguages, then return EFI_UNSUPPORTED
+ //
+ if (!Found) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *ErrorType = NULL;
+ *BufferSize = 0;
+
+ if (ChildHandle == NULL) {
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiCallerIdGuid,
+ NULL,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ControllerHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // Use services of PCI I/O Protocol to test the PCI IDE/ATAPI Controller
+ // The following test simply reads the Device ID and Vendor ID.
+ // It should never fail. A real test would perform more advanced
+ // diagnostics.
+ //
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, 1, &VendorDeviceId);
+ if (EFI_ERROR (Status) || VendorDeviceId == 0xffffffff) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ Status = gBS->OpenProtocol (
+ ChildHandle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ gIDEBusDriverBinding.DriverBindingHandle,
+ ChildHandle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+ //
+ // Use services available from IdeBlkIoDevice to test the IDE/ATAPI device
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ IdeBlkIoDevice->BlkMedia.BlockSize,
+ (VOID **) &BlockBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = IdeBlkIoDevice->BlkIo.ReadBlocks (
+ &IdeBlkIoDevice->BlkIo,
+ IdeBlkIoDevice->BlkMedia.MediaId,
+ 0,
+ IdeBlkIoDevice->BlkMedia.BlockSize,
+ BlockBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ *ErrorType = &gEfiCallerIdGuid;
+ *BufferSize = sizeof (IDE_BUS_DIAGNOSTIC_ERROR);
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ (UINTN) (*BufferSize),
+ (VOID **) Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ CopyMem (*Buffer, IDE_BUS_DIAGNOSTIC_ERROR, *BufferSize);
+
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ gBS->FreePool (BlockBuffer);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
new file mode 100644
index 0000000000..ffc818036a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.c
@@ -0,0 +1,1330 @@
+/** @file
+ The file ontaining the helper functions implement of the Ide Bus driver
+
+ Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "IdeBus.h"
+
+BOOLEAN ChannelDeviceDetected = FALSE;
+BOOLEAN SlaveDeviceExist = FALSE;
+UINT8 SlaveDeviceType = INVALID_DEVICE_TYPE;
+BOOLEAN MasterDeviceExist = FALSE;
+UINT8 MasterDeviceType = INVALID_DEVICE_TYPE;
+
+/**
+ read a one-byte data from a IDE port.
+
+ @param PciIo The PCI IO protocol instance
+ @param Port the IDE Port number
+
+ @return the one-byte data read from IDE port
+**/
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ )
+{
+ UINT8 Data;
+
+ Data = 0;
+ //
+ // perform 1-byte data read from register
+ //
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+ return Data;
+}
+/**
+ Reads multiple words of data from the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ UINT16 *AlignedBuffer;
+ UINT16 *WorkingBuffer;
+ UINTN Size;
+
+ //
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+ // not perform actual I/O operations if buffer pointer passed in is not at
+ // natural boundary. The "Buffer" argument is passed in by user and may not
+ // at 16-bit natural boundary.
+ //
+ Size = sizeof (UINT16) * Count;
+
+ gBS->AllocatePool (
+ EfiBootServicesData,
+ Size + 1,
+ (VOID**)&WorkingBuffer
+ );
+
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+ //
+ // Perform UINT16 data read from FIFO
+ //
+ PciIo->Io.Read (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16*)AlignedBuffer
+ );
+
+ //
+ // Copy data to user buffer
+ //
+ CopyMem (Buffer, (UINT16*)AlignedBuffer, Size);
+ gBS->FreePool (WorkingBuffer);
+}
+
+/**
+ write a 1-byte data to a specific IDE port.
+
+ @param PciIo PCI IO protocol instance
+ @param Port The IDE port to be writen
+ @param Data The data to write to the port
+**/
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ )
+{
+ //
+ // perform 1-byte data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+
+}
+
+/**
+ write a 1-word data to a specific IDE port.
+
+ @param PciIo PCI IO protocol instance
+ @param Port The IDE port to be writen
+ @param Data The data to write to the port
+**/
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ )
+{
+ //
+ // perform 1-word data write to register
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Write multiple words of data to the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT16 *AlignedBuffer;
+ UINT32 *WorkingBuffer;
+ UINTN Size;
+
+ //
+ // Prepare an 16-bit alligned working buffer. CpuIo will return failure and
+ // not perform actual I/O operations if buffer pointer passed in is not at
+ // natural boundary. The "Buffer" argument is passed in by user and may not
+ // at 16-bit natural boundary.
+ //
+ Size = sizeof (UINT16) * Count;
+
+ gBS->AllocatePool (
+ EfiBootServicesData,
+ Size + 1,
+ (VOID **) &WorkingBuffer
+ );
+
+ AlignedBuffer = (UINT16 *) ((UINTN)(((UINTN) WorkingBuffer + 0x1) & (~0x1)));
+
+ //
+ // Copy data from user buffer to working buffer
+ //
+ CopyMem ((UINT16 *) AlignedBuffer, Buffer, Size);
+
+ //
+ // perform UINT16 data write to the FIFO
+ //
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthFifoUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) Port,
+ Count,
+ (UINT16 *) AlignedBuffer
+ );
+
+ gBS->FreePool (WorkingBuffer);
+}
+/**
+ Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
+ use fixed addresses. In Native-PCI mode, get base addresses from BARs in
+ the PCI IDE controller's Configuration Space.
+
+ The steps to get IDE IO port registers' base addresses for each channel
+ as follows:
+
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+ controller's Configuration Space to determine the operating mode.
+
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+ <pre>
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+ </pre>
+
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+ <pre>
+ ___________________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|___________________|___________________|
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|
+ |___________|___________________|___________________|
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+ |___________|___________________|___________________|
+
+ Table 2. BARs for Register Mapping
+ </pre>
+ @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
+ primary, 0374h for secondary. So 2 bytes extra offset should be
+ added to the base addresses read from BARs.
+
+ For more details, please refer to PCI IDE Controller Specification and Intel
+ ICH4 Datasheet.
+
+ @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
+ receive IDE IO port registers' base addresses
+
+ @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval other read the pci configureation data error
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ )
+{
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_PRIMARY_OPERATING_MODE) == 0) {
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr = 0x1f0;
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr = 0x3f6;
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
+ (UINT16)((PciData.Device.Bar[4] & 0x0000fff0));
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[0] & BIT0) == 0 ||
+ (PciData.Device.Bar[1] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeRegsBaseAddr[IdePrimary].CommandBlockBaseAddr =
+ (UINT16) (PciData.Device.Bar[0] & 0x0000fff8);
+ IdeRegsBaseAddr[IdePrimary].ControlBlockBaseAddr =
+ (UINT16) ((PciData.Device.Bar[1] & 0x0000fffc) + 2);
+ IdeRegsBaseAddr[IdePrimary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ }
+
+ if ((PciData.Hdr.ClassCode[0] & IDE_SECONDARY_OPERATING_MODE) == 0) {
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr = 0x170;
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr = 0x376;
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ } else {
+ //
+ // The BARs should be of IO type
+ //
+ if ((PciData.Device.Bar[2] & BIT0) == 0 ||
+ (PciData.Device.Bar[3] & BIT0) == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ IdeRegsBaseAddr[IdeSecondary].CommandBlockBaseAddr =
+ (UINT16) (PciData.Device.Bar[2] & 0x0000fff8);
+ IdeRegsBaseAddr[IdeSecondary].ControlBlockBaseAddr =
+ (UINT16) ((PciData.Device.Bar[3] & 0x0000fffc) + 2);
+ IdeRegsBaseAddr[IdeSecondary].BusMasterBaseAddr =
+ (UINT16) ((PciData.Device.Bar[4] & 0x0000fff0));
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to requery IDE resources. The IDE controller will
+ probably switch between native and legacy modes during the EFI->CSM->OS
+ transfer. We do this everytime before an BlkIo operation to ensure its
+ succeess.
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device
+
+ @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
+ @retval EFI_SUCCESS reassign the IDE IO resource successfully
+ @retval other get the IDE current base address effor
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+
+ if (IdeDev->Channel >= IdeMaxChannel) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Requery IDE IO port registers' base addresses in case of the switch of
+ // native and legacy modes
+ //
+ Status = GetIdeRegistersBaseAddr (IdeDev->PciIo, IdeRegsBaseAddr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (IdeDev->IoPort, sizeof (IDE_BASE_REGISTERS));
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].CommandBlockBaseAddr;
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].ControlBlockBaseAddr;
+
+ IdeDev->IoPort->Data = CommandBlockBaseAddr;
+ (*(UINT16 *) &IdeDev->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeDev->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeDev->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeDev->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeDev->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeDev->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+
+ (*(UINT16 *) &IdeDev->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
+ (*(UINT16 *) &IdeDev->IoPort->Alt) = ControlBlockBaseAddr;
+ IdeDev->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
+ IdeDev->IoPort->MasterSlave = (UINT16) ((IdeDev->Device == IdeMaster) ? 1 : 0);
+
+ IdeDev->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeDev->Channel].BusMasterBaseAddr;
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is called by DiscoverIdeDevice(). It is used for detect
+ whether the IDE device exists in the specified Channel as the specified
+ Device Number.
+
+ There is two IDE channels: one is Primary Channel, the other is
+ Secondary Channel.(Channel is the logical name for the physical "Cable".)
+ Different channel has different register group.
+
+ On each IDE channel, at most two IDE devices attach,
+ one is called Device 0 (Master device), the other is called Device 1
+ (Slave device). The devices on the same channel co-use the same register
+ group, so before sending out a command for a specified device via command
+ register, it is a must to select the current device to accept the command
+ by set the device number in the Head/Device Register.
+
+ @param IdeDev pointer to IDE_BLK_IO_DEV data structure, used to record all the
+ information of the IDE device.
+
+ @retval EFI_SUCCESS successfully detects device.
+
+ @retval other any failure during detection process will return this value.
+
+**/
+EFI_STATUS
+DetectIDEController (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ UINT8 SectorCountReg;
+ UINT8 LBALowReg;
+ UINT8 LBAMidReg;
+ UINT8 LBAHighReg;
+ UINT8 InitStatusReg;
+ UINT8 StatusReg;
+
+ //
+ // Select slave device
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((1 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+
+ //
+ // Save the init slave status register
+ //
+ InitStatusReg = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // Select Master back
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((0 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+
+ //
+ // Send ATA Device Execut Diagnostic command.
+ // This command should work no matter DRDY is ready or not
+ //
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Command, 0x90);
+
+ Status = WaitForBSYClear (IdeDev, 3500);
+ if (EFI_ERROR (Status)) {
+ DEBUG((EFI_D_ERROR, "New detecting method: Send Execute Diagnostic Command: WaitForBSYClear: Status: %d\n", Status));
+ return Status;
+ }
+ //
+ // Read device signature
+ //
+ //
+ // Select Master
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((0 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+ SectorCountReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorCount
+ );
+ LBALowReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorNumber
+ );
+ LBAMidReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb
+ );
+ LBAHighReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb
+ );
+ if ((SectorCountReg == 0x1) &&
+ (LBALowReg == 0x1) &&
+ (LBAMidReg == 0x0) &&
+ (LBAHighReg == 0x0)) {
+ MasterDeviceExist = TRUE;
+ MasterDeviceType = ATA_DEVICE_TYPE;
+ } else {
+ if ((LBAMidReg == 0x14) &&
+ (LBAHighReg == 0xeb)) {
+ MasterDeviceExist = TRUE;
+ MasterDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+
+ //
+ // For some Hard Drive, it takes some time to get
+ // the right signature when operating in single slave mode.
+ // We stall 20ms to work around this.
+ //
+ if (!MasterDeviceExist) {
+ gBS->Stall (20000);
+ }
+
+ //
+ // Select Slave
+ //
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ (UINT8) ((1 << 4) | 0xe0)
+ );
+ gBS->Stall (100);
+ SectorCountReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorCount
+ );
+ LBALowReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->SectorNumber
+ );
+ LBAMidReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderLsb
+ );
+ LBAHighReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->CylinderMsb
+ );
+ StatusReg = IDEReadPortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Reg.Status
+ );
+ if ((SectorCountReg == 0x1) &&
+ (LBALowReg == 0x1) &&
+ (LBAMidReg == 0x0) &&
+ (LBAHighReg == 0x0)) {
+ SlaveDeviceExist = TRUE;
+ SlaveDeviceType = ATA_DEVICE_TYPE;
+ } else {
+ if ((LBAMidReg == 0x14) &&
+ (LBAHighReg == 0xeb)) {
+ SlaveDeviceExist = TRUE;
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+
+ //
+ // When single master is plugged, slave device
+ // will be wrongly detected. Here's the workaround
+ // for ATA devices by detecting DRY bit in status
+ // register.
+ // NOTE: This workaround doesn't apply to ATAPI.
+ //
+ if (MasterDeviceExist && SlaveDeviceExist &&
+ (StatusReg & ATA_STSREG_DRDY) == 0 &&
+ (InitStatusReg & ATA_STSREG_DRDY) == 0 &&
+ MasterDeviceType == SlaveDeviceType &&
+ SlaveDeviceType != ATAPI_DEVICE_TYPE) {
+ SlaveDeviceExist = FALSE;
+ }
+
+ //
+ // Indicate this channel has been detected
+ //
+ ChannelDeviceDetected = TRUE;
+ return EFI_SUCCESS;
+}
+/**
+ Detect if there is disk attached to this port
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device.
+
+ @retval EFI_NOT_FOUND The device or channel is not found
+ @retval EFI_SUCCESS The device is found
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS LongPhyStatus;
+
+ //
+ // If a channel has not been checked, check it now. Then set it to "checked" state
+ // After this step, all devices in this channel have been checked.
+ //
+ if (!ChannelDeviceDetected) {
+ Status = DetectIDEController (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ Status = EFI_NOT_FOUND;
+
+ //
+ // Device exists. test if it is an ATA device.
+ // Prefer the result from DetectIDEController,
+ // if failed, try another device type to handle
+ // devices that not follow the spec.
+ //
+ if ((IdeDev->Device == IdeMaster) && (MasterDeviceExist)) {
+ if (MasterDeviceType == ATA_DEVICE_TYPE) {
+ Status = ATAIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAPIIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ MasterDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+ } else {
+ Status = ATAPIIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ MasterDeviceType = ATA_DEVICE_TYPE;
+ }
+ }
+ }
+ }
+ if ((IdeDev->Device == IdeSlave) && (SlaveDeviceExist)) {
+ if (SlaveDeviceType == ATA_DEVICE_TYPE) {
+ Status = ATAIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAPIIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ SlaveDeviceType = ATAPI_DEVICE_TYPE;
+ }
+ }
+ } else {
+ Status = ATAPIIdentify (IdeDev);
+ if (EFI_ERROR (Status)) {
+ Status = ATAIdentify (IdeDev);
+ if (!EFI_ERROR (Status)) {
+ SlaveDeviceType = ATA_DEVICE_TYPE;
+ }
+ }
+ }
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Init Block I/O interface
+ //
+ LongPhyStatus = AtaEnableLongPhysicalSector (IdeDev);
+ if (!EFI_ERROR (LongPhyStatus)) {
+ IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION2;
+ } else {
+ IdeDev->BlkIo.Revision = EFI_BLOCK_IO_PROTOCOL_REVISION;
+ }
+ IdeDev->BlkIo.Reset = IDEBlkIoReset;
+ IdeDev->BlkIo.ReadBlocks = IDEBlkIoReadBlocks;
+ IdeDev->BlkIo.WriteBlocks = IDEBlkIoWriteBlocks;
+ IdeDev->BlkIo.FlushBlocks = IDEBlkIoFlushBlocks;
+
+ IdeDev->BlkMedia.LogicalPartition = FALSE;
+ IdeDev->BlkMedia.WriteCaching = FALSE;
+
+ //
+ // Init Disk Info interface
+ //
+ gBS->CopyMem (&IdeDev->DiskInfo.Interface, &gEfiDiskInfoIdeInterfaceGuid, sizeof (EFI_GUID));
+ IdeDev->DiskInfo.Inquiry = IDEDiskInfoInquiry;
+ IdeDev->DiskInfo.Identify = IDEDiskInfoIdentify;
+ IdeDev->DiskInfo.SenseData = IDEDiskInfoSenseData;
+ IdeDev->DiskInfo.WhichIde = IDEDiskInfoWhichIde;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This interface is used to initialize all state data related to the detection of one
+ channel.
+**/
+VOID
+InitializeIDEChannelData (
+ VOID
+ )
+{
+ ChannelDeviceDetected = FALSE;
+ MasterDeviceExist = FALSE;
+ MasterDeviceType = 0xff;
+ SlaveDeviceExist = FALSE;
+ SlaveDeviceType = 0xff;
+}
+/**
+ This function is used to poll for the DRQ bit clear in the Status
+ Register. DRQ is cleared when the device is finished transferring data.
+ So this function is called after data transfer is finished.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((StatusRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to poll for the DRQ bit clear in the Alternate
+ Status Register. DRQ is cleared when the device is finished
+ transferring data. So this function is called after data transfer
+ is finished.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+
+ //
+ // wait for BSY == 0 and DRQ == 0
+ //
+ if ((AltRegister & (ATA_STSREG_DRQ | ATA_STSREG_BSY)) == 0) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to poll for the DRQ bit set in the
+ Status Register.
+ DRQ is set when the device is ready to transfer data. So this function
+ is called after the command is sent to the device and before required
+ data is transferred.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to
+ record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRQ bit set within the time out.
+ @retval EFI_TIMEOUT DRQ bit not set within the time out.
+ @retval EFI_ABORTED DRQ bit not set caused by the command abort.
+
+ @note Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ //
+ // read Status Register will clear interrupt
+ //
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+
+ //
+ // BSY==0,DRQ==1
+ //
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to poll for the DRQ bit set in the Alternate Status Register.
+ DRQ is set when the device is ready to transfer data. So this function is called after
+ the command is sent to the device and before required data is transferred.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
+ record all the information of the IDE device.
+
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRQ bit set within the time out.
+ @retval EFI_TIMEOUT DRQ bit not set within the time out.
+ @retval EFI_ABORTED DRQ bit not set caused by the command abort.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+
+ do {
+ //
+ // Read Alternate Status Register will not clear interrupt status
+ //
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ //
+ // BSY == 0 , DRQ == 1
+ //
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_DRQ)) == ATA_STSREG_DRQ) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used to poll for the BSY bit clear in the Status Register. BSY
+ is clear when the device is not busy. Every command must be sent after device is not busy.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS BSY bit clear within the time out.
+ @retval EFI_TIMEOUT BSY bit not clear within the time out.
+
+ @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ if ((StatusRegister & ATA_STSREG_BSY) == 0x00) {
+ break;
+ }
+
+ //
+ // Stall for 30 us
+ //
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to poll for the BSY bit clear in the Alternate Status Register.
+ BSY is clear when the device is not busy. Every command must be sent after device is
+ not busy.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS BSY bit clear within the time out.
+ @retval EFI_TIMEOUT BSY bit not clear within the time out.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+
+ Delay = (UINT32) (((TimeoutInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ if ((AltRegister & ATA_STSREG_BSY) == 0x00) {
+ break;
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to poll for the DRDY bit set in the Status Register. DRDY
+ bit is set when the device is ready to accept command. Most ATA commands must be
+ sent after DRDY set except the ATAPI Packet Command.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRDY bit set within the time out.
+ @retval EFI_TIMEOUT DRDY bit not set within the time out.
+
+ @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 StatusRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ StatusRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg.Status);
+ //
+ // BSY == 0 , DRDY == 1
+ //
+ if ((StatusRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+ break;
+ }
+
+ if ((StatusRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ This function is used to poll for the DRDY bit set in the Alternate Status Register.
+ DRDY bit is set when the device is ready to accept command. Most ATA commands must
+ be sent after DRDY set except the ATAPI Packet Command.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRDY bit set within the time out.
+ @retval EFI_TIMEOUT DRDY bit not set within the time out.
+
+ @note Read Alternate Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ )
+{
+ UINT32 Delay;
+ UINT8 AltRegister;
+ UINT8 ErrorRegister;
+
+ Delay = (UINT32) (((DelayInMilliSeconds * STALL_1_MILLI_SECOND) / 30) + 1);
+ do {
+ AltRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Alt.AltStatus);
+ //
+ // BSY == 0 , DRDY == 1
+ //
+ if ((AltRegister & (ATA_STSREG_DRDY | ATA_STSREG_BSY)) == ATA_STSREG_DRDY) {
+ break;
+ }
+
+ if ((AltRegister & (ATA_STSREG_BSY | ATA_STSREG_ERR)) == ATA_STSREG_ERR) {
+
+ ErrorRegister = IDEReadPortB (IdeDev->PciIo, IdeDev->IoPort->Reg1.Error);
+ if ((ErrorRegister & ATA_ERRREG_ABRT) == ATA_ERRREG_ABRT) {
+ return EFI_ABORTED;
+ }
+ }
+
+ gBS->Stall (30);
+
+ Delay--;
+ } while (Delay > 0);
+
+ if (Delay == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Release resources of an IDE device before stopping it.
+
+ @param IdeBlkIoDevice Standard IDE device private data structure
+
+**/
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ )
+{
+ if (IdeBlkIoDevice == NULL) {
+ return ;
+ }
+
+ //
+ // Release all the resourses occupied by the IDE_BLK_IO_DEV
+ //
+
+ if (IdeBlkIoDevice->SenseData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->SenseData);
+ IdeBlkIoDevice->SenseData = NULL;
+ }
+
+ if (IdeBlkIoDevice->Cache != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->Cache);
+ IdeBlkIoDevice->Cache = NULL;
+ }
+
+ if (IdeBlkIoDevice->IdData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->IdData);
+ IdeBlkIoDevice->IdData = NULL;
+ }
+
+ if (IdeBlkIoDevice->InquiryData != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->InquiryData);
+ IdeBlkIoDevice->InquiryData = NULL;
+ }
+
+ if (IdeBlkIoDevice->ControllerNameTable != NULL) {
+ FreeUnicodeStringTable (IdeBlkIoDevice->ControllerNameTable);
+ IdeBlkIoDevice->ControllerNameTable = NULL;
+ }
+
+ if (IdeBlkIoDevice->IoPort != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->IoPort);
+ }
+
+ if (IdeBlkIoDevice->DevicePath != NULL) {
+ gBS->FreePool (IdeBlkIoDevice->DevicePath);
+ }
+
+ if (IdeBlkIoDevice->ExitBootServiceEvent != NULL) {
+ gBS->CloseEvent (IdeBlkIoDevice->ExitBootServiceEvent);
+ IdeBlkIoDevice->ExitBootServiceEvent = NULL;
+ }
+
+ gBS->FreePool (IdeBlkIoDevice);
+ IdeBlkIoDevice = NULL;
+
+ return ;
+}
+/**
+ Set the calculated Best transfer mode to a detected device.
+
+ @param IdeDev Standard IDE device private data structure
+ @param TransferMode The device transfer mode to be set
+ @return Set transfer mode Command execute status.
+
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceSelect;
+ UINT8 SectorCount;
+
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+ SectorCount = *((UINT8 *) TransferMode);
+
+ //
+ // Send SET FEATURE command (sub command 0x03) to set pio mode.
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_SET_FEATURES,
+ DeviceSelect,
+ 0x03,
+ SectorCount,
+ 0,
+ 0,
+ 0
+ );
+
+ return Status;
+}
+/**
+ Set drive parameters for devices not support PACKETS command.
+
+ @param IdeDev Standard IDE device private data structure
+ @param DriveParameters The device parameters to be set into the disk
+ @return SetParameters Command execute status.
+
+**/
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ )
+{
+ EFI_STATUS Status;
+ UINT8 DeviceSelect;
+
+ DeviceSelect = 0;
+ DeviceSelect = (UINT8) ((IdeDev->Device) << 4);
+
+ //
+ // Send Init drive parameters
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_INIT_DRIVE_PARAM,
+ (UINT8) (DeviceSelect + DriveParameters->Heads),
+ 0,
+ DriveParameters->Sector,
+ 0,
+ 0,
+ 0
+ );
+
+ //
+ // Send Set Multiple parameters
+ //
+ Status = AtaNonDataCommandIn (
+ IdeDev,
+ ATA_CMD_SET_MULTIPLE_MODE,
+ DeviceSelect,
+ 0,
+ DriveParameters->MultipleSector,
+ 0,
+ 0,
+ 0
+ );
+ return Status;
+}
+
+/**
+ Enable Interrupt on IDE controller.
+
+ @param IdeDev Standard IDE device private data structure
+
+ @retval EFI_SUCCESS Enable Interrupt successfully
+**/
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ )
+{
+ UINT8 DeviceControl;
+
+ //
+ // Enable interrupt for DMA operation
+ //
+ DeviceControl = 0;
+ IDEWritePortB (IdeDev->PciIo, IdeDev->IoPort->Alt.DeviceControl, DeviceControl);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.h b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.h
new file mode 100644
index 0000000000..2b7e6ea5eb
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/Ide.h
@@ -0,0 +1,835 @@
+/** @file
+ Header file for IDE Bus Driver, containing the helper functions'
+ prototype.
+
+ Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ 2002-6: Add Atapi6 enhancement, support >120GB hard disk, including
+ Add - IDEBlkIoReadBlocksExt() func definition
+ Add - IDEBlkIoWriteBlocksExt() func definition
+
+**/
+
+#ifndef _IDE_H_
+#define _IDE_H_
+
+//
+// Helper functions Prototype
+//
+/**
+ read a one-byte data from a IDE port.
+
+ @param PciIo The PCI IO protocol instance
+ @param Port the IDE Port number
+
+ return the one-byte data read from IDE port
+**/
+UINT8
+IDEReadPortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port
+ );
+
+/**
+ Reads multiple words of data from the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time.
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEReadPortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ write a 1-byte data to a specific IDE port.
+
+ @param PciIo PCI IO protocol instance
+ @param Port The IDE port to be writen
+ @param Data The data to write to the port
+**/
+VOID
+IDEWritePortB (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT8 Data
+ );
+
+/**
+ write a 1-word data to a specific IDE port.
+
+ @param PciIo PCI IO protocol instance
+ @param Port The IDE port to be writen
+ @param Data The data to write to the port
+**/
+VOID
+IDEWritePortW (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINT16 Data
+ );
+
+/**
+ Write multiple words of data to the IDE data port.
+ Call the IO abstraction once to do the complete read,
+ not one word at a time.
+
+ @param PciIo Pointer to the EFI_PCI_IO instance
+ @param Port IO port to read
+ @param Count No. of UINT16's to read
+ @param Buffer Pointer to the data buffer for read
+
+**/
+VOID
+IDEWritePortWMultiple (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT16 Port,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Get IDE IO port registers' base addresses by mode. In 'Compatibility' mode,
+ use fixed addresses. In Native-PCI mode, get base addresses from BARs in
+ the PCI IDE controller's Configuration Space.
+
+ The steps to get IDE IO port registers' base addresses for each channel
+ as follows:
+
+ 1. Examine the Programming Interface byte of the Class Code fields in PCI IDE
+ controller's Configuration Space to determine the operating mode.
+
+ 2. a) In 'Compatibility' mode, use fixed addresses shown in the Table 1 below.
+ <pre>
+ ___________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|_______________|_______________|
+ | Primary | 1F0h - 1F7h | 3F6h - 3F7h |
+ |___________|_______________|_______________|
+ | Secondary | 170h - 177h | 376h - 377h |
+ |___________|_______________|_______________|
+
+ Table 1. Compatibility resource mappings
+ </pre>
+
+ b) In Native-PCI mode, IDE registers are mapped into IO space using the BARs
+ in IDE controller's PCI Configuration Space, shown in the Table 2 below.
+ <pre>
+ ___________________________________________________
+ | | Command Block | Control Block |
+ | Channel | Registers | Registers |
+ |___________|___________________|___________________|
+ | Primary | BAR at offset 0x10| BAR at offset 0x14|
+ |___________|___________________|___________________|
+ | Secondary | BAR at offset 0x18| BAR at offset 0x1C|
+ |___________|___________________|___________________|
+
+ Table 2. BARs for Register Mapping
+ </pre>
+ @note Refer to Intel ICH4 datasheet, Control Block Offset: 03F4h for
+ primary, 0374h for secondary. So 2 bytes extra offset should be
+ added to the base addresses read from BARs.
+
+ For more details, please refer to PCI IDE Controller Specification and Intel
+ ICH4 Datasheet.
+
+ @param PciIo Pointer to the EFI_PCI_IO_PROTOCOL instance
+ @param IdeRegsBaseAddr Pointer to IDE_REGISTERS_BASE_ADDR to
+ receive IDE IO port registers' base addresses
+
+ @retval EFI_UNSUPPORTED return this value when the BARs is not IO type
+ @retval EFI_SUCCESS Get the Base address successfully
+ @retval other read the pci configureation data error
+
+**/
+EFI_STATUS
+GetIdeRegistersBaseAddr (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ OUT IDE_REGISTERS_BASE_ADDR *IdeRegsBaseAddr
+ );
+
+/**
+ This function is used to requery IDE resources. The IDE controller will
+ probably switch between native and legacy modes during the EFI->CSM->OS
+ transfer. We do this everytime before an BlkIo operation to ensure its
+ succeess.
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device
+
+ @retval EFI_INVALID_PARAMETER return this value when the channel is invalid
+ @retval EFI_SUCCESS reassign the IDE IO resource successfully
+ @retval other get the IDE current base address effor
+
+**/
+EFI_STATUS
+ReassignIdeResources (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ Detect if there is disk attached to this port.
+
+ @param IdeDev The BLK_IO private data which specifies the IDE device.
+
+ @retval EFI_NOT_FOUND The device or channel is not found
+ @retval EFI_SUCCESS The device is found
+
+**/
+EFI_STATUS
+DiscoverIdeDevice (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This interface is used to initialize all state data related to the
+ detection of one channel.
+
+**/
+VOID
+InitializeIDEChannelData (
+ VOID
+ );
+
+/**
+ This function is used to poll for the DRQ bit clear in the Status
+ Register. DRQ is cleared when the device is finished transferring data.
+ So this function is called after data transfer is finished.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+
+ @note
+ Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the DRQ bit clear in the Alternate
+ Status Register. DRQ is cleared when the device is finished
+ transferring data. So this function is called after data transfer
+ is finished.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ clear.
+
+ @retval EFI_SUCCESS DRQ bit clear within the time out.
+
+ @retval EFI_TIMEOUT DRQ bit not clear within the time out.
+ @note
+ Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the DRQ bit set in the
+ Status Register.
+ DRQ is set when the device is ready to transfer data. So this function
+ is called after the command is sent to the device and before required
+ data is transferred.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to
+ record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRQ bit set within the time out.
+ @retval EFI_TIMEOUT DRQ bit not set within the time out.
+ @retval EFI_ABORTED DRQ bit not set caused by the command abort.
+
+ @note Read Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the DRQ bit set in the Alternate Status Register.
+ DRQ is set when the device is ready to transfer data. So this function is called after
+ the command is sent to the device and before required data is transferred.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
+ record all the information of the IDE device.
+
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRQ bit set within the time out.
+ @retval EFI_TIMEOUT DRQ bit not set within the time out.
+ @retval EFI_ABORTED DRQ bit not set caused by the command abort.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+DRQReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the BSY bit clear in the Status Register. BSY
+ is clear when the device is not busy. Every command must be sent after device is not busy.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS BSY bit clear within the time out.
+ @retval EFI_TIMEOUT BSY bit not clear within the time out.
+
+ @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+WaitForBSYClear (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the BSY bit clear in the Alternate Status Register.
+ BSY is clear when the device is not busy. Every command must be sent after device is
+ not busy.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param TimeoutInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS BSY bit clear within the time out.
+ @retval EFI_TIMEOUT BSY bit not clear within the time out.
+ @note Read Alternate Status Register will not clear interrupt status.
+
+**/
+EFI_STATUS
+WaitForBSYClear2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN TimeoutInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the DRDY bit set in the Status Register. DRDY
+ bit is set when the device is ready to accept command. Most ATA commands must be
+ sent after DRDY set except the ATAPI Packet Command.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRDY bit set within the time out.
+ @retval EFI_TIMEOUT DRDY bit not set within the time out.
+
+ @note Read Status Register will clear interrupt status.
+**/
+EFI_STATUS
+DRDYReady (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ );
+
+/**
+ This function is used to poll for the DRDY bit set in the Alternate Status Register.
+ DRDY bit is set when the device is ready to accept command. Most ATA commands must
+ be sent after DRDY set except the ATAPI Packet Command.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param DelayInMilliSeconds used to designate the timeout for the DRQ ready.
+
+ @retval EFI_SUCCESS DRDY bit set within the time out.
+ @retval EFI_TIMEOUT DRDY bit not set within the time out.
+
+ @note Read Alternate Status Register will clear interrupt status.
+
+**/
+EFI_STATUS
+DRDYReady2 (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINTN DelayInMilliSeconds
+ );
+
+//
+// ATA device functions' prototype
+//
+/**
+ Sends out an ATA Identify Command to the specified device.
+
+ This function is called by DiscoverIdeDevice() during its device
+ identification. It sends out the ATA Identify Command to the
+ specified device. Only ATA device responses to this command. If
+ the command succeeds, it returns the Identify data structure which
+ contains information about the device. This function extracts the
+ information it needs to fill the IDE_BLK_IO_DEV data structure,
+ including device type, media block size, media capacity, and etc.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure,used to record
+ all the information of the IDE device.
+
+ @retval EFI_SUCCESS Identify ATA device successfully.
+ @retval EFI_DEVICE_ERROR ATA Identify Device Command failed or device is not ATA device.
+ @note parameter IdeDev will be updated in this function.
+
+**/
+EFI_STATUS
+ATAIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This function is called by ATAIdentify() or ATAPIIdentify() to print device's module name.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+**/
+VOID
+PrintAtaModuleName (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+/**
+ This function is used to send out ATA commands conforms to the PIO Data In Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @param Buffer buffer contained data transferred from device to host.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param Head value of the Head/Device Register
+ @param SectorCount value of the Sector Count Register
+ @param SectorNumber value of the Sector Number Register
+ @param CylinderLsb value of the low byte of the Cylinder Register
+ @param CylinderMsb value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device send required data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ );
+
+/**
+ This function is used to send out ATA commands conforms to the
+ PIO Data Out Protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+ @param *Buffer buffer contained data transferred from host to device.
+ @param ByteCount data size in byte unit of the buffer.
+ @param AtaCommand value of the Command Register
+ @param Head value of the Head/Device Register
+ @param SectorCount value of the Sector Count Register
+ @param SectorNumber value of the Sector Number Register
+ @param CylinderLsb value of the low byte of the Cylinder Register
+ @param CylinderMsb value of the high byte of the Cylinder Register
+
+ @retval EFI_SUCCESS send out the ATA command and device received required
+ data successfully.
+ @retval EFI_DEVICE_ERROR command sent failed.
+
+**/
+EFI_STATUS
+AtaPioDataOut (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN VOID *Buffer,
+ IN UINT32 ByteCount,
+ IN UINT8 AtaCommand,
+ IN UINT8 Head,
+ IN UINT8 SectorCount,
+ IN UINT8 SectorNumber,
+ IN UINT8 CylinderLsb,
+ IN UINT8 CylinderMsb
+ );
+
+/**
+ This function is used to analyze the Status Register and print out
+ some debug information and if there is ERR bit set in the Status
+ Register, the Error Register's value is also be parsed and print out.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to
+ record all the information of the IDE device.
+
+ @retval EFI_SUCCESS No err information in the Status Register.
+ @retval EFI_DEVICE_ERROR Any err information in the Status Register.
+
+**/
+EFI_STATUS
+CheckErrorStatus (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This function is used to implement the Soft Reset on the specified device. But,
+ the ATA Soft Reset mechanism is so strong a reset method that it will force
+ resetting on both devices connected to the same cable.
+
+ It is called by IdeBlkIoReset(), a interface function of Block
+ I/O protocol.
+
+ This function can also be used by the ATAPI device to perform reset when
+ ATAPI Reset command is failed.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used to record
+ all the information of the IDE device.
+ @retval EFI_SUCCESS Soft reset completes successfully.
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+ @note The registers initial values after ATA soft reset are different
+ to the ATA device and ATAPI device.
+**/
+EFI_STATUS
+AtaSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This function is the ATA implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the memory that data is read into.
+
+ @retval EFI_SUCCESS Read Blocks successfully.
+ @retval EFI_DEVICE_ERROR Read Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note If Read Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+
+**/
+EFI_STATUS
+AtaBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ This function is the ATA implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the write request is for.
+ @param Lba The starting logical block address to write onto the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the source buffer for the data.The caller
+ is responsible for either having implicit or explicit
+ ownership of the memory that data is written from.
+
+ @retval EFI_SUCCESS Write Blocks successfully.
+ @retval EFI_DEVICE_ERROR Write Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @note If Write Block error because of device error, this function will call
+ AtaSoftReset() function to reset device.
+**/
+EFI_STATUS
+AtaBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ This function is called by DiscoverIdeDevice() during its device
+ identification.
+ Its main purpose is to get enough information for the device media
+ to fill in the Media data structure of the Block I/O Protocol interface.
+
+ There are 5 steps to reach such objective:
+ 1. Sends out the ATAPI Identify Command to the specified device.
+ Only ATAPI device responses to this command. If the command succeeds,
+ it returns the Identify data structure which filled with information
+ about the device. Since the ATAPI device contains removable media,
+ the only meaningful information is the device module name.
+ 2. Sends out ATAPI Inquiry Packet Command to the specified device.
+ This command will return inquiry data of the device, which contains
+ the device type information.
+ 3. Allocate sense data space for future use. We don't detect the media
+ presence here to improvement boot performance, especially when CD
+ media is present. The media detection will be performed just before
+ each BLK_IO read/write
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Identify ATAPI device successfully.
+ @retval EFI_DEVICE_ERROR ATAPI Identify Device Command failed or device type
+ is not supported by this IDE driver.
+ @retval EFI_OUT_OF_RESOURCES Allocate memory for sense data failed
+
+ @note Parameter "IdeDev" will be updated in this function.
+**/
+EFI_STATUS
+ATAPIIdentify (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This function is used to implement the Soft Reset on the specified
+ ATAPI device. Different from the AtaSoftReset(), here reset is a ATA
+ Soft Reset Command special for ATAPI device, and it only take effects
+ on the specified ATAPI device, not on the whole IDE bus.
+ Since the ATAPI soft reset is needed when device is in exceptional
+ condition (such as BSY bit is always set ), I think the Soft Reset
+ command should be sent without waiting for the BSY clear and DRDY
+ set.
+ This function is called by IdeBlkIoReset(),
+ a interface function of Block I/O protocol.
+
+ @param IdeDev pointer pointing to IDE_BLK_IO_DEV data structure, used
+ to record all the information of the IDE device.
+
+ @retval EFI_SUCCESS Soft reset completes successfully.
+ @retval EFI_DEVICE_ERROR Any step during the reset process is failed.
+
+**/
+EFI_STATUS
+AtapiSoftReset (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ This function is the ATAPI implementation for ReadBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the read request is for.
+ @param Lba The starting logical block address to read from on the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the destination buffer for the data. The caller
+ is responsible for either having implicit or explicit
+ ownership of the memory that data is read into.
+
+ @retval EFI_SUCCESS Read Blocks successfully.
+ @retval EFI_DEVICE_ERROR Read Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the data buffer is not valid.
+**/
+EFI_STATUS
+AtapiBlkIoReadBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ This function is the ATAPI implementation for WriteBlocks in the
+ Block I/O Protocol interface.
+
+ @param IdeBlkIoDevice Indicates the calling context.
+ @param MediaId The media id that the write request is for.
+ @param Lba The starting logical block address to write onto the device.
+ @param BufferSize The size of the Buffer in bytes. This must be a multiple
+ of the intrinsic block size of the device.
+ @param Buffer A pointer to the source buffer for the data. The caller
+ is responsible for either having implicit or explicit ownership
+ of the memory that data is written from.
+
+ @retval EFI_SUCCESS Write Blocks successfully.
+ @retval EFI_DEVICE_ERROR Write Blocks failed.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGE The MediaId is not for the current media.
+ @retval EFI_BAD_BUFFER_SIZE The BufferSize parameter is not a multiple of the
+ intrinsic block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the data buffer is not valid.
+
+ @retval EFI_WRITE_PROTECTED The write protected is enabled or the media does not support write
+**/
+EFI_STATUS
+AtapiBlkIoWriteBlocks (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Release resources of an IDE device before stopping it.
+
+ @param IdeBlkIoDevice Standard IDE device private data structure
+
+**/
+VOID
+ReleaseIdeResources (
+ IN IDE_BLK_IO_DEV *IdeBlkIoDevice
+ );
+
+/**
+ Set the calculated Best transfer mode to a detected device
+
+ @param IdeDev Standard IDE device private data structure
+ @param TransferMode The device transfer mode to be set
+ @return Set transfer mode Command execute status.
+**/
+EFI_STATUS
+SetDeviceTransferMode (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_TRANSFER_MODE *TransferMode
+ );
+/**
+ Send ATA command into device with NON_DATA protocol.
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaLow The value in LBA_LOW register
+ @param LbaMiddle The value in LBA_MIDDLE register
+ @param LbaHigh The value in LBA_HIGH register
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandIn (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT8 Feature,
+ IN UINT8 SectorCount,
+ IN UINT8 LbaLow,
+ IN UINT8 LbaMiddle,
+ IN UINT8 LbaHigh
+ );
+
+/**
+ Send ATA Ext command into device with NON_DATA protocol.
+
+ @param IdeDev Standard IDE device private data structure
+ @param AtaCommand The ATA command to be sent
+ @param Device The value in Device register
+ @param Feature The value in Feature register
+ @param SectorCount The value in SectorCount register
+ @param LbaAddress The Lba address in 48-bit mode
+
+ @retval EFI_SUCCESS Reading succeed
+ @retval EFI_ABORTED Command failed
+ @retval EFI_DEVICE_ERROR Device status error.
+
+**/
+EFI_STATUS
+AtaNonDataCommandInExt (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN UINT8 AtaCommand,
+ IN UINT8 Device,
+ IN UINT16 Feature,
+ IN UINT16 SectorCount,
+ IN EFI_LBA LbaAddress
+ );
+/**
+ Enable Long Physical Sector Feature for ATA device.
+
+ @param IdeDev The IDE device data
+
+ @retval EFI_SUCCESS The ATA device supports Long Physical Sector feature
+ and corresponding fields in BlockIo structure is updated.
+ @retval EFI_UNSUPPORTED The device is not ATA device or Long Physical Sector
+ feature is not supported.
+**/
+EFI_STATUS
+AtaEnableLongPhysicalSector (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+
+/**
+ Set drive parameters for devices not support PACKETS command.
+
+ @param IdeDev Standard IDE device private data structure
+ @param DriveParameters The device parameters to be set into the disk
+ @return SetParameters Command execute status.
+
+**/
+EFI_STATUS
+SetDriveParameters (
+ IN IDE_BLK_IO_DEV *IdeDev,
+ IN ATA_DRIVE_PARMS *DriveParameters
+ );
+
+/**
+ Enable Interrupt on IDE controller.
+
+ @param IdeDev Standard IDE device private data structure
+
+ @retval EFI_SUCCESS Enable Interrupt successfully
+**/
+EFI_STATUS
+EnableInterrupt (
+ IN IDE_BLK_IO_DEV *IdeDev
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.c b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.c
new file mode 100644
index 0000000000..82fd44f17d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.c
@@ -0,0 +1,1571 @@
+/** @file
+ This file implement UEFI driver for IDE Bus which includes device identification,
+ Child device(Disk, CDROM, etc) enumeration and child handler installation, and
+ driver stop.
+
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+ @par Revision Reference:
+ This module is modified from DXE\IDE module for Ide Contriller Init support
+
+**/
+
+#include "IdeBus.h"
+
+#define PCI_CLASS_MASS_STORAGE 0x01
+#define PCI_SUB_CLASS_IDE 0x01
+
+
+//
+// IDE Bus Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding = {
+ IDEBusDriverBindingSupported,
+ IDEBusDriverBindingStart,
+ IDEBusDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+/**
+ Deregister an IDE device and free resources
+
+ @param This Protocol instance pointer.
+ @param Controller Ide device handle
+ @param Handle Handle of device to deregister driver on
+
+ @retval EFI_SUCCESS Deregiter a specific IDE device successfully
+
+
+**/
+EFI_STATUS
+DeRegisterIdeDevice (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (BlkIo);
+
+ //
+ // Report Status code: Device disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_DISABLE),
+ IdeBlkIoDevice->DevicePath
+ );
+
+ //
+ // Close the child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ IdeBlkIoDevice->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &IdeBlkIoDevice->BlkIo,
+ &gEfiDiskInfoProtocolGuid,
+ &IdeBlkIoDevice->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ //
+ // Release allocated resources
+ //
+ Index = IdeBlkIoDevice->Channel * 2 + IdeBlkIoDevice->Device;
+ if (Index < MAX_IDE_DEVICE) {
+ IdeBlkIoDevice->IdeBusDriverPrivateData->HaveScannedDevice[Index] = FALSE;
+ }
+ ReleaseIdeResources (IdeBlkIoDevice);
+
+ return EFI_SUCCESS;
+}
+/**
+ Supported function of Driver Binding protocol for this driver.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEV_PATH *Node;
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciData;
+
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, go on checking other conditions
+ //
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ if (Node->DevPath.Type != MESSAGING_DEVICE_PATH ||
+ Node->DevPath.SubType != MSG_ATAPI_DP ||
+ DevicePathNodeLength(&Node->DevPath) != sizeof(ATAPI_DEVICE_PATH)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ }
+
+ //
+ // Verify the Ide Controller Init Protocol, which installed by the
+ // IdeController module.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Close the I/O Abstraction(s) used to perform the supported test
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the EFI Device Path protocol needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Close protocol, don't use device path protocol in the Support() function
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Get the EfiPciIoProtocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Now further check the PCI header: Base class (offset 0x0B) and
+ // Sub Class (offset 0x0A). This controller should be an IDE controller
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0,
+ sizeof (PciData),
+ &PciData
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Examine if it is IDE mode by class code
+ //
+ if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) || (PciData.Hdr.ClassCode[1] != PCI_SUB_CLASS_IDE)) {
+ Status = EFI_UNSUPPORTED;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Start function of Driver binding protocol which start this driver on Controller
+ by detecting all disks and installing BlockIo protocol on them.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS SavedStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_DEV_PATH *Node;
+ UINT8 IdeChannel;
+ UINT8 BeginningIdeChannel;
+ UINT8 EndIdeChannel;
+ UINT8 IdeDevice;
+ UINT8 BeginningIdeDevice;
+ UINT8 EndIdeDevice;
+ IDE_BLK_IO_DEV *IdeBlkIoDevice[IdeMaxChannel][IdeMaxDevice];
+ IDE_BLK_IO_DEV *IdeBlkIoDevicePtr;
+ IDE_REGISTERS_BASE_ADDR IdeRegsBaseAddr[IdeMaxChannel];
+ ATA_TRANSFER_MODE TransferMode;
+ ATA_DRIVE_PARMS DriveParameters;
+ EFI_DEV_PATH NewNode;
+ UINT8 ConfigurationOptions;
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINTN DataSize;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+ UINT64 Supports;
+
+ //
+ // Local variables declaration for IdeControllerInit support
+ //
+ EFI_IDE_CONTROLLER_INIT_PROTOCOL *IdeInit;
+ BOOLEAN EnumAll;
+ BOOLEAN ChannelEnabled;
+ UINT8 MaxDevices;
+ EFI_IDENTIFY_DATA IdentifyData;
+ EFI_ATA_COLLECTIVE_MODE *SupportedModes;
+
+ IdeBusDriverPrivateData = NULL;
+ SupportedModes = NULL;
+
+ //
+ // Perform IdeBus initialization
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Now open the IDE_CONTROLLER_INIT protocol. Step7.1
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ (VOID **) &IdeInit,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ //
+ // The following OpenProtocol function with _GET_PROTOCOL attribute and
+ // will not return EFI_ALREADY_STARTED, so save it for now
+ //
+ SavedStatus = Status;
+
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ DEBUG ((EFI_D_ERROR, "Open Init, Status=%x", Status));
+ //
+ // open protocol is not SUCCESS or not ALREADY_STARTED, error exit
+ //
+ goto ErrorExit;
+ }
+
+ //
+ // Save Enumall. Step7.2
+ //
+ EnumAll = IdeInit->EnumAll;
+
+ //
+ // Consume PCI I/O protocol. Note that the OpenProtocol with _GET_PROTOCOL
+ // attribute will not return EFI_ALREADY_STARTED
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Open PciIo, Status=%x", Status));
+ goto ErrorExit;
+ }
+
+ //
+ // We must check EFI_ALREADY_STARTED because many ATAPI devices are removable
+ //
+ if (SavedStatus != EFI_ALREADY_STARTED) {
+ IdeBusDriverPrivateData = AllocatePool (sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+ if (IdeBusDriverPrivateData == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto ErrorExit;
+ }
+
+ ZeroMem (IdeBusDriverPrivateData, sizeof (IDE_BUS_DRIVER_PRIVATE_DATA));
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ } else {
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &IdeBusDriverPrivateData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData = NULL;
+ goto ErrorExit;
+ }
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Read the environment variable that contains the IDEBus Driver's
+ // Config options that were set by the Driver Configuration Protocol
+ //
+ DataSize = sizeof (ConfigurationOptions);
+ Status = gRT->GetVariable (
+ (CHAR16 *) L"Configuration",
+ &gEfiCallerIdGuid,
+ NULL,
+ &DataSize,
+ &ConfigurationOptions
+ );
+ if (EFI_ERROR (Status)) {
+ ConfigurationOptions = 0x0f;
+ }
+
+ if (EnumAll || RemainingDevicePath == NULL) {
+ //
+ // If IdeInit->EnumAll is TRUE or RemainingDevicePath is NULL,
+ // must enumerate all IDE devices anyway
+ //
+ BeginningIdeChannel = IdePrimary;
+ EndIdeChannel = IdeSecondary;
+ BeginningIdeDevice = IdeMaster;
+ EndIdeDevice = IdeSlave;
+
+ } else if (!IsDevicePathEnd (RemainingDevicePath)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // only scan the specified device by RemainingDevicePath
+ //
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ BeginningIdeChannel = Node->Atapi.PrimarySecondary;
+ EndIdeChannel = BeginningIdeChannel;
+ BeginningIdeDevice = Node->Atapi.SlaveMaster;
+ EndIdeDevice = BeginningIdeDevice;
+ if (BeginningIdeChannel >= IdeMaxChannel || EndIdeChannel >= IdeMaxChannel) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ErrorExit;
+ }
+ if (BeginningIdeDevice >= IdeMaxDevice|| EndIdeDevice >= IdeMaxDevice) {
+ Status = EFI_INVALID_PARAMETER;
+ goto ErrorExit;
+ }
+
+ } else {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // skip enumerate any device and return EFI_SUCESSS
+ //
+ BeginningIdeChannel = IdeMaxChannel;
+ EndIdeChannel = IdeMaxChannel - 1;
+ BeginningIdeDevice = IdeMaxDevice;
+ EndIdeDevice = IdeMaxDevice - 1;
+ }
+
+ //
+ // Obtain IDE IO port registers' base addresses
+ //
+ Status = GetIdeRegistersBaseAddr (PciIo, IdeRegsBaseAddr);
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ //
+ // Report status code: begin IdeBus initialization
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_PC_RESET),
+ ParentDevicePath
+ );
+
+ //
+ // Strictly follow the enumeration based on IDE_CONTROLLER_INIT protocol
+ //
+ for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelEnumeration, IdeChannel);
+
+ //
+ // now obtain channel information fron IdeControllerInit protocol. Step9
+ //
+ Status = IdeInit->GetChannelInfo (
+ IdeInit,
+ IdeChannel,
+ &ChannelEnabled,
+ &MaxDevices
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[GetChannel, Status=%x]", Status));
+ continue;
+ }
+
+ if (!ChannelEnabled) {
+ continue;
+ }
+
+ EndIdeDevice = (UINT8) MIN ((MaxDevices - 1), EndIdeDevice);
+ ASSERT (EndIdeDevice < IdeMaxDevice);
+ //
+ // Now inform the IDE Controller Init Module. Sept10
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBeforeChannelReset, IdeChannel);
+
+ //
+ // No reset channel function implemented. Sept11
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeAfterChannelReset, IdeChannel);
+
+ //
+ // Step13
+ //
+ IdeInit->NotifyPhase (
+ IdeInit,
+ EfiIdeBusBeforeDevicePresenceDetection,
+ IdeChannel
+ );
+
+ //
+ // Prepare to detect IDE device of this channel
+ //
+ InitializeIDEChannelData ();
+
+ //
+ // -- 1st inner loop --- Master/Slave ------------ Step14
+ //
+ for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+ //
+ // Check whether the configuration options allow this device
+ //
+ if ((ConfigurationOptions & (1 << (IdeChannel * 2 + IdeDevice))) == 0) {
+ continue;
+ }
+
+ //
+ // The device has been scanned in another Start(), No need to scan it again
+ // for perf optimization.
+ //
+ if (IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ //
+ // create child handle for the detected device.
+ //
+ IdeBlkIoDevice[IdeChannel][IdeDevice] = AllocatePool (sizeof (IDE_BLK_IO_DEV));
+ if (IdeBlkIoDevice[IdeChannel][IdeDevice] == NULL) {
+ continue;
+ }
+
+ IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+ ZeroMem (IdeBlkIoDevicePtr, sizeof (IDE_BLK_IO_DEV));
+
+ IdeBlkIoDevicePtr->Signature = IDE_BLK_IO_DEV_SIGNATURE;
+ IdeBlkIoDevicePtr->Channel = (EFI_IDE_CHANNEL) IdeChannel;
+ IdeBlkIoDevicePtr->Device = (EFI_IDE_DEVICE) IdeDevice;
+
+ //
+ // initialize Block IO interface's Media pointer
+ //
+ IdeBlkIoDevicePtr->BlkIo.Media = &IdeBlkIoDevicePtr->BlkMedia;
+
+ //
+ // Initialize IDE IO port addresses, including Command Block registers
+ // and Control Block registers
+ //
+ IdeBlkIoDevicePtr->IoPort = AllocatePool (sizeof (IDE_BASE_REGISTERS));
+ if (IdeBlkIoDevicePtr->IoPort == NULL) {
+ continue;
+ }
+
+ ZeroMem (IdeBlkIoDevicePtr->IoPort, sizeof (IDE_BASE_REGISTERS));
+ CommandBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].CommandBlockBaseAddr;
+ ControlBlockBaseAddr = IdeRegsBaseAddr[IdeChannel].ControlBlockBaseAddr;
+
+ IdeBlkIoDevicePtr->IoPort->Data = CommandBlockBaseAddr;
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg1) = (UINT16) (CommandBlockBaseAddr + 0x01);
+ IdeBlkIoDevicePtr->IoPort->SectorCount = (UINT16) (CommandBlockBaseAddr + 0x02);
+ IdeBlkIoDevicePtr->IoPort->SectorNumber = (UINT16) (CommandBlockBaseAddr + 0x03);
+ IdeBlkIoDevicePtr->IoPort->CylinderLsb = (UINT16) (CommandBlockBaseAddr + 0x04);
+ IdeBlkIoDevicePtr->IoPort->CylinderMsb = (UINT16) (CommandBlockBaseAddr + 0x05);
+ IdeBlkIoDevicePtr->IoPort->Head = (UINT16) (CommandBlockBaseAddr + 0x06);
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Reg) = (UINT16) (CommandBlockBaseAddr + 0x07);
+
+ (*(UINT16 *) &IdeBlkIoDevicePtr->IoPort->Alt) = ControlBlockBaseAddr;
+ IdeBlkIoDevicePtr->IoPort->DriveAddress = (UINT16) (ControlBlockBaseAddr + 0x01);
+
+ IdeBlkIoDevicePtr->IoPort->MasterSlave = (UINT16) ((IdeDevice == IdeMaster) ? 1 : 0);
+
+ IdeBlkIoDevicePtr->PciIo = PciIo;
+ IdeBlkIoDevicePtr->IdeBusDriverPrivateData = IdeBusDriverPrivateData;
+ IdeBlkIoDevicePtr->IoPort->BusMasterBaseAddr = IdeRegsBaseAddr[IdeChannel].BusMasterBaseAddr;
+
+ //
+ // Report Status code: is about to detect IDE drive
+ //
+ REPORT_STATUS_CODE_EX (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_PRESENCE_DETECT),
+ 0,
+ &gEfiCallerIdGuid,
+ NULL,
+ NULL,
+ 0
+ );
+
+ //
+ // Discover device, now!
+ //
+ PERF_START (NULL, "DiscoverIdeDevice", "IDE", 0);
+ Status = DiscoverIdeDevice (IdeBlkIoDevicePtr);
+ PERF_END (NULL, "DiscoverIdeDevice", "IDE", 0);
+
+ IdeBusDriverPrivateData->HaveScannedDevice[IdeChannel * 2 + IdeDevice] = TRUE;
+ IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = FALSE;
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set Device Path
+ //
+ ZeroMem (&NewNode, sizeof (NewNode));
+ NewNode.DevPath.Type = MESSAGING_DEVICE_PATH;
+ NewNode.DevPath.SubType = MSG_ATAPI_DP;
+ SetDevicePathNodeLength (&NewNode.DevPath, sizeof (ATAPI_DEVICE_PATH));
+
+ NewNode.Atapi.PrimarySecondary = (UINT8) IdeBlkIoDevicePtr->Channel;
+ NewNode.Atapi.SlaveMaster = (UINT8) IdeBlkIoDevicePtr->Device;
+ NewNode.Atapi.Lun = IdeBlkIoDevicePtr->Lun;
+ IdeBlkIoDevicePtr->DevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ &NewNode.DevPath
+ );
+ if (IdeBlkIoDevicePtr->DevicePath == NULL) {
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ continue;
+ }
+
+ //
+ // Submit identify data to IDE controller init driver
+ //
+ CopyMem (&IdentifyData, IdeBlkIoDevicePtr->IdData, sizeof (IdentifyData));
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = TRUE;
+ IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, &IdentifyData);
+ } else {
+ //
+ // Device detection failed
+ //
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ IdeInit->SubmitData (IdeInit, IdeChannel, IdeDevice, NULL);
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ }
+ //
+ // end of 1st inner loop ---
+ //
+ }
+ //
+ // end of 1st outer loop =========
+ //
+ }
+
+ //
+ // = 2nd outer loop == Primary/Secondary =================
+ //
+ for (IdeChannel = BeginningIdeChannel; IdeChannel <= EndIdeChannel; IdeChannel++) {
+
+ //
+ // -- 2nd inner loop --- Master/Slave --------
+ //
+ for (IdeDevice = BeginningIdeDevice; IdeDevice <= EndIdeDevice; IdeDevice++) {
+
+ ASSERT (IdeChannel * 2 + IdeDevice < MAX_IDE_DEVICE);
+ if (IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ if (!IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice]) {
+ continue;
+ }
+
+ Status = IdeInit->CalculateMode (
+ IdeInit,
+ IdeChannel,
+ IdeDevice,
+ &SupportedModes
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[bStStp20S=%x]", Status));
+ continue;
+ }
+
+ ASSERT (IdeChannel < IdeMaxChannel && IdeDevice < IdeMaxDevice);
+ IdeBlkIoDevicePtr = IdeBlkIoDevice[IdeChannel][IdeDevice];
+
+ //
+ // Set best supported PIO mode on this IDE device
+ //
+ if (SupportedModes->PioMode.Mode <= AtaPioMode2) {
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_DEFAULT_PIO;
+ } else {
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_FLOW_PIO;
+ }
+
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->PioMode.Mode);
+
+ if (SupportedModes->ExtModeCount == 0){
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+ }
+
+ //
+ // Set supported DMA mode on this IDE device. Note that UDMA & MDMA cann't
+ // be set together. Only one DMA mode can be set to a device. If setting
+ // DMA mode operation fails, we can continue moving on because we only use
+ // PIO mode at boot time. DMA modes are used by certain kind of OS booting
+ //
+ if (SupportedModes->UdmaMode.Valid) {
+
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_UDMA;
+ TransferMode.ModeNumber = (UINT8) (SupportedModes->UdmaMode.Mode);
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+ //
+ // Record Udma Mode
+ //
+ IdeBlkIoDevicePtr->UdmaMode.Valid = TRUE;
+ IdeBlkIoDevicePtr->UdmaMode.Mode = SupportedModes->UdmaMode.Mode;
+ EnableInterrupt (IdeBlkIoDevicePtr);
+ } else if (SupportedModes->MultiWordDmaMode.Valid) {
+
+ TransferMode.ModeCategory = ATA_MODE_CATEGORY_MDMA;
+ TransferMode.ModeNumber = (UINT8) SupportedModes->MultiWordDmaMode.Mode;
+ Status = SetDeviceTransferMode (IdeBlkIoDevicePtr, &TransferMode);
+
+ if (EFI_ERROR (Status)) {
+ IdeBusDriverPrivateData->DeviceFound[IdeChannel * 2 + IdeDevice] = FALSE;
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ IdeBlkIoDevicePtr = NULL;
+ continue;
+ }
+
+ EnableInterrupt (IdeBlkIoDevicePtr);
+ }
+ //
+ // Init driver parameters
+ //
+ DriveParameters.Sector = (UINT8) ((ATA5_IDENTIFY_DATA *) IdeBlkIoDevicePtr->IdData)->sectors_per_track;
+ DriveParameters.Heads = (UINT8) (((ATA5_IDENTIFY_DATA *) IdeBlkIoDevicePtr->IdData)->heads - 1);
+ DriveParameters.MultipleSector = (UINT8) IdeBlkIoDevicePtr->IdData->AtaData.multi_sector_cmd_max_sct_cnt;
+ //
+ // Set Parameters for the device:
+ // 1) Init
+ // 2) Establish the block count for READ/WRITE MULTIPLE (EXT) command
+ //
+ if ((IdeBlkIoDevicePtr->Type == IdeHardDisk) || (IdeBlkIoDevicePtr->Type == Ide48bitAddressingHardDisk)) {
+ Status = SetDriveParameters (IdeBlkIoDevicePtr, &DriveParameters);
+ }
+
+ //
+ // Record PIO mode used in private data
+ //
+ IdeBlkIoDevicePtr->PioMode = (ATA_PIO_MODE) SupportedModes->PioMode.Mode;
+
+ //
+ // Set IDE controller Timing Blocks in the PCI Configuration Space
+ //
+ IdeInit->SetTiming (IdeInit, IdeChannel, IdeDevice, SupportedModes);
+
+ //
+ // Add Component Name for the IDE/ATAPI device that was discovered.
+ //
+ IdeBlkIoDevicePtr->ControllerNameTable = NULL;
+ ADD_IDE_ATAPI_NAME (IdeBlkIoDevicePtr);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &IdeBlkIoDevicePtr->Handle,
+ &gEfiDevicePathProtocolGuid,
+ IdeBlkIoDevicePtr->DevicePath,
+ &gEfiBlockIoProtocolGuid,
+ &IdeBlkIoDevicePtr->BlkIo,
+ &gEfiDiskInfoProtocolGuid,
+ &IdeBlkIoDevicePtr->DiskInfo,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ ReleaseIdeResources (IdeBlkIoDevicePtr);
+ }
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ IdeBlkIoDevicePtr->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ IdeBusDriverPrivateData->DeviceProcessed[IdeChannel * 2 + IdeDevice] = TRUE;
+
+ //
+ // Report status code: device eanbled!
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_P_PC_ENABLE),
+ IdeBlkIoDevicePtr->DevicePath
+ );
+
+ //
+ // Create event to clear pending IDE interrupt
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ClearInterrupt,
+ IdeBlkIoDevicePtr,
+ &gEfiEventExitBootServicesGuid,
+ &IdeBlkIoDevicePtr->ExitBootServiceEvent
+ );
+
+ //
+ // end of 2nd inner loop ----
+ //
+ }
+ //
+ // end of 2nd outer loop ==========
+ //
+ }
+
+ //
+ // All configurations done! Notify IdeController to do post initialization
+ // work such as saving IDE controller PCI settings for S3 resume
+ //
+ IdeInit->NotifyPhase (IdeInit, EfiIdeBusPhaseMaximum, 0);
+
+ if (SupportedModes != NULL) {
+ FreePool (SupportedModes);
+ }
+
+ PERF_START (NULL, "Finish IDE detection", "IDE", 1);
+ PERF_END (NULL, "Finish IDE detection", "IDE", 0);
+
+ return EFI_SUCCESS;
+
+ErrorExit:
+
+ //
+ // Report error code: controller error
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_IO_BUS_ATA_ATAPI | EFI_IOB_EC_CONTROLLER_ERROR),
+ ParentDevicePath
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+
+ if (IdeBusDriverPrivateData != NULL) {
+ gBS->FreePool (IdeBusDriverPrivateData);
+ }
+
+ if (SupportedModes != NULL) {
+ gBS->FreePool (SupportedModes);
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+
+}
+/**
+ Stop function of Driver Binding Protocol which is to stop the driver on Controller Handle and all
+ child handle attached to the controller handle if there are.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Not used
+ @param ChildHandleBuffer Not used
+
+ @retval EFI_SUCCESS This driver is removed DeviceHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+ UINT64 Supports;
+
+ IdeBusDriverPrivateData = NULL;
+
+ if (NumberOfChildren == 0) {
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_IDE_PRIMARY_IO | EFI_PCI_IO_ATTRIBUTE_IDE_SECONDARY_IO | EFI_PCI_DEVICE_ENABLE);
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Supports,
+ NULL
+ );
+ }
+ }
+
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiCallerIdGuid,
+ (VOID **) &IdeBusDriverPrivateData,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+
+ gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiCallerIdGuid,
+ IdeBusDriverPrivateData,
+ NULL
+ );
+
+ if (IdeBusDriverPrivateData != NULL) {
+ gBS->FreePool (IdeBusDriverPrivateData);
+ }
+ //
+ // Close the bus driver
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIdeControllerInitProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = DeRegisterIdeDevice (This, Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ issue ATA or ATAPI command to reset a block IO device.
+ @param This Block IO protocol instance pointer.
+ @param ExtendedVerification If FALSE,for ATAPI device, driver will only invoke ATAPI reset method
+ If TRUE, for ATAPI device, driver need invoke ATA reset method after
+ invoke ATAPI reset method
+
+ @retval EFI_DEVICE_ERROR When the device is neighther ATA device or ATAPI device.
+ @retval EFI_SUCCESS The device reset successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // for ATA device, using ATA reset method
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ Status = AtaSoftReset (IdeBlkIoDevice);
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI reset method
+ //
+ Status = AtapiSoftReset (IdeBlkIoDevice);
+ if (ExtendedVerification) {
+ Status = AtaSoftReset (IdeBlkIoDevice);
+ }
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Read data from a block IO device
+
+ @param This Block IO protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param Lba Starting LBA address to read data
+ @param BufferSize The size of data to be read
+ @param Buffer Caller supplied buffer to save data
+
+ @retval EFI_DEVICE_ERROR unknown device type
+ @retval other read data status.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // For ATA compatible device, use ATA read block's mechanism
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+ Status = AtaBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI read block's mechanism
+ //
+ Status = AtapiBlkIoReadBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+}
+
+/**
+ Write data to block io device.
+
+ @param This Protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param Lba Starting LBA address to write data
+ @param BufferSize The size of data to be written
+ @param Buffer Caller supplied buffer to save data
+
+ @retval EFI_DEVICE_ERROR unknown device type
+ @retval other write data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_THIS (This);
+ //
+ // Requery IDE IO resources in case of the switch of native and legacy modes
+ //
+ ReassignIdeResources (IdeBlkIoDevice);
+
+ //
+ // for ATA device, using ATA write block's mechanism
+ //
+ if (IdeBlkIoDevice->Type == IdeHardDisk ||
+ IdeBlkIoDevice->Type == Ide48bitAddressingHardDisk) {
+
+ Status = AtaBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+ goto Done;
+ }
+
+ if (IdeBlkIoDevice->Type == IdeUnknown) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // for ATAPI device, using ATAPI write block's mechanism
+ //
+ Status = AtapiBlkIoWriteBlocks (
+ IdeBlkIoDevice,
+ MediaId,
+ Lba,
+ BufferSize,
+ Buffer
+ );
+
+Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+/**
+ Flushes all modified data to a physical block devices
+
+ @param This Indicates a pointer to the calling context which to sepcify a
+ sepcific block device
+
+ @retval EFI_SUCCESS Always return success.
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ //
+ // return directly
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used by the IDE bus driver to get inquiry data.
+ Data format of Identify data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param InquiryData Pointer to a buffer for the inquiry data.
+ @param InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL IntquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+ if (*InquiryDataSize < sizeof (ATAPI_INQUIRY_DATA)) {
+ *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (IdeBlkIoDevice->InquiryData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ gBS->CopyMem (InquiryData, IdeBlkIoDevice->InquiryData, sizeof (ATAPI_INQUIRY_DATA));
+ *InquiryDataSize = sizeof (ATAPI_INQUIRY_DATA);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used by the IDE bus driver to get identify data.
+ Data format of Identify data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param IdentifyData Pointer to a buffer for the identify data.
+ @param IdentifyDataSize Pointer to the value for the identify data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+
+ if (*IdentifyDataSize < sizeof (EFI_IDENTIFY_DATA)) {
+ *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (IdeBlkIoDevice->IdData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ gBS->CopyMem (IdentifyData, IdeBlkIoDevice->IdData, sizeof (EFI_IDENTIFY_DATA));
+ *IdentifyDataSize = sizeof (EFI_IDENTIFY_DATA);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is used by the IDE bus driver to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param SenseData Pointer to the SenseData.
+ @param SenseDataSize Size of SenseData in bytes.
+ @param SenseDataNumber Pointer to the value for the identify data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ )
+{
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function is used by the IDE bus driver to get controller information.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid
+ @retval EFI_UNSUPPORTED This is not an IDE device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ )
+{
+ IDE_BLK_IO_DEV *IdeBlkIoDevice;
+
+ IdeBlkIoDevice = IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS (This);
+ *IdeChannel = IdeBlkIoDevice->Channel;
+ *IdeDevice = IdeBlkIoDevice->Device;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The is an event(generally the event is exitBootService event) call back function.
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT64 IoPortForBmis;
+ UINT8 RegisterValue;
+ IDE_BLK_IO_DEV *IdeDev;
+
+ //
+ // Get our context
+ //
+ IdeDev = (IDE_BLK_IO_DEV *) Context;
+
+ //
+ // Obtain IDE IO port registers' base addresses
+ //
+ Status = ReassignIdeResources (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Check whether interrupt is pending
+ //
+
+ //
+ // Reset IDE device to force it de-assert interrupt pin
+ // Note: this will reset all devices on this IDE channel
+ //
+ Status = AtaSoftReset (IdeDev);
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ //
+ // Get base address of IDE Bus Master Status Regsiter
+ //
+ if (IdePrimary == IdeDev->Channel) {
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISP_OFFSET;
+ } else {
+ if (IdeSecondary == IdeDev->Channel) {
+ IoPortForBmis = IdeDev->IoPort->BusMasterBaseAddr + BMISS_OFFSET;
+ } else {
+ return;
+ }
+ }
+ //
+ // Read BMIS register and clear ERROR and INTR bit
+ //
+ IdeDev->PciIo->Io.Read (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ RegisterValue |= (BMIS_INTERRUPT | BMIS_ERROR);
+
+ IdeDev->PciIo->Io.Write (
+ IdeDev->PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ IoPortForBmis,
+ 1,
+ &RegisterValue
+ );
+
+ //
+ // Select the other device on this channel to ensure this device to release the interrupt pin
+ //
+ if (IdeDev->Device == 0) {
+ RegisterValue = (1 << 4) | 0xe0;
+ } else {
+ RegisterValue = (0 << 4) | 0xe0;
+ }
+ IDEWritePortB (
+ IdeDev->PciIo,
+ IdeDev->IoPort->Head,
+ RegisterValue
+ );
+
+}
+
+/**
+ The user Entry Point for module IdeBus. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeIdeBus(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallAllDriverProtocols2 (
+ ImageHandle,
+ SystemTable,
+ &gIDEBusDriverBinding,
+ ImageHandle,
+ &gIDEBusComponentName,
+ &gIDEBusComponentName2,
+ NULL,
+ NULL,
+ &gIDEBusDriverDiagnostics,
+ &gIDEBusDriverDiagnostics2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.h b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.h
new file mode 100644
index 0000000000..a3db16ca85
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBus.h
@@ -0,0 +1,540 @@
+/** @file
+ Header file for IDE Bus Driver.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _IDE_BUS_H_
+#define _IDE_BUS_H_
+
+
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/IdeControllerInit.h>
+#include <Protocol/BlockIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <IndustryStandard/Pci.h>
+#include "IdeData.h"
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gIDEBusDriverBinding;
+extern EFI_DRIVER_DIAGNOSTICS_PROTOCOL gIDEBusDriverDiagnostics;
+extern EFI_DRIVER_DIAGNOSTICS2_PROTOCOL gIDEBusDriverDiagnostics2;
+
+//
+// Extra Definition to porting
+//
+#define MAX_IDE_DEVICE 4
+#define MAX_IDE_CHANNELS 2
+#define MAX_IDE_DRIVES 2
+
+#define INVALID_DEVICE_TYPE 0xff
+#define ATA_DEVICE_TYPE 0x00
+#define ATAPI_DEVICE_TYPE 0x01
+
+typedef struct {
+ BOOLEAN HaveScannedDevice[MAX_IDE_DEVICE];
+ BOOLEAN DeviceFound[MAX_IDE_DEVICE];
+ BOOLEAN DeviceProcessed[MAX_IDE_DEVICE];
+} IDE_BUS_DRIVER_PRIVATE_DATA;
+
+#define IDE_BLK_IO_DEV_SIGNATURE SIGNATURE_32 ('i', 'b', 'i', 'd')
+
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL BlkIo;
+ EFI_BLOCK_IO_MEDIA BlkMedia;
+ EFI_DISK_INFO_PROTOCOL DiskInfo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ IDE_BUS_DRIVER_PRIVATE_DATA *IdeBusDriverPrivateData;
+
+ //
+ // Local Data for IDE interface goes here
+ //
+ EFI_IDE_CHANNEL Channel;
+ EFI_IDE_DEVICE Device;
+ UINT16 Lun;
+ IDE_DEVICE_TYPE Type;
+
+ IDE_BASE_REGISTERS *IoPort;
+ UINT16 AtapiError;
+
+ ATAPI_INQUIRY_DATA *InquiryData;
+ EFI_IDENTIFY_DATA *IdData;
+ ATA_PIO_MODE PioMode;
+ EFI_ATA_MODE UdmaMode;
+ CHAR8 ModelName[41];
+ ATAPI_REQUEST_SENSE_DATA *SenseData;
+ UINT8 SenseDataNumber;
+ UINT8 *Cache;
+
+ //
+ // ExitBootService Event, it is used to clear pending IDE interrupt
+ //
+ EFI_EVENT ExitBootServiceEvent;
+
+ EFI_UNICODE_STRING_TABLE *ControllerNameTable;
+} IDE_BLK_IO_DEV;
+
+#include "ComponentName.h"
+
+#define IDE_BLOCK_IO_DEV_FROM_THIS(a) CR (a, IDE_BLK_IO_DEV, BlkIo, IDE_BLK_IO_DEV_SIGNATURE)
+#define IDE_BLOCK_IO_DEV_FROM_DISK_INFO_THIS(a) CR (a, IDE_BLK_IO_DEV, DiskInfo, IDE_BLK_IO_DEV_SIGNATURE)
+
+#include "Ide.h"
+
+
+/**
+ Supported function of Driver Binding protocol for this driver.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS Driver loaded.
+ @retval other Driver not loaded.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Start function of Driver binding protocol which start this driver on Controller
+ by detecting all disks and installing BlockIo protocol on them.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath produce all possible children.
+
+ @retval EFI_SUCCESS This driver is added to ControllerHandle.
+ @retval EFI_ALREADY_STARTED This driver is already running on ControllerHandle.
+ @retval other This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop function of Driver Binding Protocol which is to stop the driver on Controller Handle and all
+ child handle attached to the controller handle if there are.
+
+ @param This Protocol instance pointer.
+ @param Controller Handle of device to stop driver on
+ @param NumberOfChildren Not used
+ @param ChildHandleBuffer Not used
+
+ @retval EFI_SUCCESS This driver is removed DeviceHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Driver Configuration Functions
+//
+/**
+ Allows the user to set controller specific options for a controller that a
+ driver is currently managing.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to set options on.
+ @param ChildHandle The handle of the child controller to set options on.
+ This is an optional parameter that may be NULL.
+ It will be NULL for device drivers, and for a bus drivers
+ that wish to set options for the bus controller.
+ It will not be NULL for a bus driver that wishes to set
+ options for one of its child controllers.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language of the user interface that should be presented
+ to the user, and it must match one of the languages specified in
+ SupportedLanguages. The number of languages supported by a driver is up to
+ the driver writer.
+ @param ActionRequired A pointer to the action that the calling agent is required
+ to perform when this function returns.
+
+
+ @retval EFI_SUCCESS The driver specified by This successfully set the configuration
+ options for the controller specified by ControllerHandle..
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support setting configuration options for
+ the controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the language specified by Language.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to set the configuration options for the
+ controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to set the configuration options for the
+ controller specified by ControllerHandle and ChildHandle
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationSetOptions (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+/**
+ Tests to see if a controller's current configuration options are valid.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to test if it's current configuration options
+ are valid.
+ @param ChildHandle The handle of the child controller to test if it's current configuration
+ options are valid. This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a bus drivers that
+ wish to test the configuration options for the bus controller. It will
+ not be NULL for a bus driver that wishes to test configuration options for
+ one of its child controllers.
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and ChildHandle that is being
+ managed by the driver specified by This has a valid set of configuration
+ options.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently managing the controller
+ specified by ControllerHandle and ChildHandle.
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and ChildHandle that is being
+ managed by the driver specified by This has an invalid set of configuration
+ options.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationOptionsValid (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL
+ );
+
+/**
+ Forces a driver to set the default configuration options for a controller.
+
+ @param This A pointer to the EFI_DRIVER_CONFIGURATION_ PROTOCOL instance.
+ @param ControllerHandle The handle of the controller to force default configuration options on.
+ @param ChildHandle The handle of the child controller to force default configuration
+ options on This is an optional parameter that may be NULL. It
+ will be NULL for device drivers. It will also be NULL for a bus
+ drivers that wish to force default configuration options for the bus
+ controller. It will not be NULL for a bus driver that wishes to force
+ default configuration options for one of its child controllers.
+ @param DefaultType The type of default configuration options to force on the controller
+ specified by ControllerHandle and ChildHandle.
+ @param ActionRequired A pointer to the action that the calling agent is required to perform
+ when this function returns.
+
+ @retval EFI_SUCCESS The driver specified by This successfully forced the
+ default configuration options on the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER ActionRequired is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support forcing the default
+ configuration options on the controller specified by ControllerHandle
+ and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the configuration type
+ specified by DefaultType.
+ @retval EFI_DEVICE_ERROR A device error occurred while attempt to force the default configuration
+ options on the controller specified by ControllerHandle and ChildHandle.
+ @retval EFI_OUT_RESOURCES There are not enough resources available to force the default configuration
+ options on the controller specified by ControllerHandle and ChildHandle.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverConfigurationForceDefaults (
+ IN EFI_DRIVER_CONFIGURATION_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN UINT32 DefaultType,
+ OUT EFI_DRIVER_CONFIGURATION_ACTION_REQUIRED *ActionRequired
+ );
+
+//
+// EFI Driver Diagnostics Functions
+//
+/**
+ Runs diagnostics on a controller.
+
+ @param This A pointer to the EFI_DRIVER_DIAGNOSTICS_PROTOCOLinstance.
+ @param ControllerHandle The handle of the controller to run diagnostics on.
+ @param ChildHandle The handle of the child controller to run diagnostics on
+ This is an optional parameter that may be NULL. It will
+ be NULL for device drivers. It will also be NULL for a
+ bus drivers that wish to run diagnostics on the bus controller.
+ It will not be NULL for a bus driver that wishes to run
+ diagnostics on one of its child controllers.
+ @param DiagnosticType Indicates type of diagnostics to perform on the controller
+ specified by ControllerHandle and ChildHandle.
+ @param Language A pointer to a three character ISO 639-2 language identifier.
+ This is the language in which the optional error message should
+ be returned in Buffer, and it must match one of the languages
+ specified in SupportedLanguages. The number of languages supported by
+ a driver is up to the driver writer.
+ @param ErrorType A GUID that defines the format of the data returned in Buffer.
+ @param BufferSize The size, in bytes, of the data returned in Buffer.
+ @param Buffer A buffer that contains a Null-terminated Unicode string
+ plus some additional data whose format is defined by ErrorType.
+ Buffer is allocated by this function with AllocatePool(), and
+ it is the caller's responsibility to free it with a call to FreePool().
+
+ @retval EFI_SUCCESS The controller specified by ControllerHandle and ChildHandle passed
+ the diagnostic.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ErrorType is NULL.
+ @retval EFI_INVALID_PARAMETER BufferType is NULL.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support running
+ diagnostics for the controller specified by ControllerHandle
+ and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the
+ type of diagnostic specified by DiagnosticType.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support the language
+ specified by Language.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to complete the
+ diagnostics.
+ @retval EFI_OUT_OF_RESOURCES There are not enough resources available to return the
+ status information in ErrorType, BufferSize,and Buffer.
+ @retval EFI_DEVICE_ERROR The controller specified by ControllerHandle and ChildHandle
+ did not pass the diagnostic.
+**/
+EFI_STATUS
+EFIAPI
+IDEBusDriverDiagnosticsRunDiagnostics (
+ IN EFI_DRIVER_DIAGNOSTICS_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN EFI_DRIVER_DIAGNOSTIC_TYPE DiagnosticType,
+ IN CHAR8 *Language,
+ OUT EFI_GUID **ErrorType,
+ OUT UINTN *BufferSize,
+ OUT CHAR16 **Buffer
+ );
+
+/**
+ issue ATA or ATAPI command to reset a block IO device.
+ @param This Block IO protocol instance pointer.
+ @param ExtendedVerification If FALSE,for ATAPI device, driver will only invoke ATAPI reset method
+ If TRUE, for ATAPI device, driver need invoke ATA reset method after
+ invoke ATAPI reset method
+
+ @retval EFI_DEVICE_ERROR When the device is neighther ATA device or ATAPI device.
+ @retval EFI_SUCCESS The device reset successfully
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read data from a block IO device.
+
+ @param This Block IO protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param Lba Starting LBA address to read data
+ @param BufferSize The size of data to be read
+ @param Buffer Caller supplied buffer to save data
+
+ @retval EFI_DEVICE_ERROR unknown device type
+ @retval EFI_SUCCESS read the data successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write data to block io device
+
+ @param This Protocol instance pointer.
+ @param MediaId The media ID of the device
+ @param Lba Starting LBA address to write data
+ @param BufferSize The size of data to be written
+ @param Buffer Caller supplied buffer to save data
+
+ @retval EFI_DEVICE_ERROR unknown device type
+ @retval other write data status
+
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ IN VOID *Buffer
+ );
+
+/**
+ Flushes all modified data to a physical block devices
+
+ @param This Indicates a pointer to the calling context which to sepcify a
+ sepcific block device
+
+ @retval EFI_SUCCESS Always return success.
+**/
+EFI_STATUS
+EFIAPI
+IDEBlkIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+/**
+ This function is used by the IDE bus driver to get inquiry data.
+ Data format of Identify data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param InquiryData Pointer to a buffer for the inquiry data.
+ @param InquiryDataSize Pointer to the value for the inquiry data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL IntquiryDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoInquiry (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *InquiryData,
+ IN OUT UINT32 *InquiryDataSize
+ );
+
+/**
+ This function is used by the IDE bus driver to get identify data.
+ Data format of Identify data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param IdentifyData Pointer to a buffer for the identify data.
+ @param IdentifyDataSize Pointer to the value for the identify data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading IdentifyData from device
+ @retval EFI_BUFFER_TOO_SMALL IdentifyDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoIdentify (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *IdentifyData,
+ IN OUT UINT32 *IdentifyDataSize
+ );
+
+/**
+ This function is used by the IDE bus driver to get sense data.
+ Data format of Sense data is defined by the Interface GUID.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param SenseData Pointer to the SenseData.
+ @param SenseDataSize Size of SenseData in bytes.
+ @param SenseDataNumber Pointer to the value for the identify data size.
+
+ @retval EFI_SUCCESS The command was accepted without any errors.
+ @retval EFI_NOT_FOUND Device does not support this data class
+ @retval EFI_DEVICE_ERROR Error reading InquiryData from device
+ @retval EFI_BUFFER_TOO_SMALL SenseDataSize not big enough
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoSenseData (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ IN OUT VOID *SenseData,
+ IN OUT UINT32 *SenseDataSize,
+ OUT UINT8 *SenseDataNumber
+ );
+
+/**
+ This function is used by the IDE bus driver to get controller information.
+
+ @param This Pointer to the EFI_DISK_INFO_PROTOCOL instance.
+ @param IdeChannel Pointer to the Ide Channel number. Primary or secondary.
+ @param IdeDevice Pointer to the Ide Device number. Master or slave.
+
+ @retval EFI_SUCCESS IdeChannel and IdeDevice are valid
+ @retval EFI_UNSUPPORTED This is not an IDE device
+
+**/
+EFI_STATUS
+EFIAPI
+IDEDiskInfoWhichIde (
+ IN EFI_DISK_INFO_PROTOCOL *This,
+ OUT UINT32 *IdeChannel,
+ OUT UINT32 *IdeDevice
+ );
+/**
+ The is an event(generally the event is exitBootService event) call back function.
+ Clear pending IDE interrupt before OS loader/kernel take control of the IDE device.
+
+ @param Event Pointer to this event
+ @param Context Event handler private data
+
+**/
+VOID
+EFIAPI
+ClearInterrupt (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf
new file mode 100644
index 0000000000..8beea2d9ca
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf
@@ -0,0 +1,88 @@
+## @file
+# IDE bus driver.
+#
+# This driver will enumerate IDE device and export the blockIo protocol for every device.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = IdeBusDxe
+ MODULE_UNI_FILE = IdeBusDxe.uni
+ FILE_GUID = 69FD8E47-A161-4550-B01A-5594CEB2B2B2
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeIdeBus
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gIDEBusDriverBinding
+# COMPONENT_NAME = gIDEBusComponentName
+# COMPONENT_NAME2 = gIDEBusComponentName2
+# Variable Guid C Name: gConfigurationGuid Variable Name: L"Configuration"
+#
+#
+
+[Sources]
+ DriverDiagnostics.c
+ DriverConfiguration.c
+ ComponentName.h
+ ComponentName.c
+ Atapi.c
+ Ata.c
+ Ide.c
+ IdeBus.c
+ IdeData.h
+ Ide.h
+ IdeBus.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ PerformanceLib
+ MemoryAllocationLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ BaseLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_PRODUCES ## UNDEFINED # DiskInfo Interface Guid
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+
+
+[Protocols]
+ gEfiDiskInfoProtocolGuid ## BY_START
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiIdeControllerInitProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ ## TO_START
+ ## BY_START
+ gEfiDevicePathProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IdeBusDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.uni b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.uni
new file mode 100644
index 0000000000..ebe7f19e75
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxeExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxeExtra.uni
new file mode 100644
index 0000000000..24ad99a10e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeData.h b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeData.h
new file mode 100644
index 0000000000..487fe6f3ea
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeData.h
@@ -0,0 +1,311 @@
+/** @file
+ Header file for IDE Bus Driver's Data Structures
+
+ Copyright (c) 2006 - 2007, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _IDE_DATA_H_
+#define _IDE_DATA_H_
+
+#include <IndustryStandard/Atapi.h>
+
+//
+// common constants
+//
+#define STALL_1_MILLI_SECOND 1000 // stall 1 ms
+#define STALL_1_SECOND 1000000 // stall 1 second
+typedef enum {
+ IdePrimary = 0,
+ IdeSecondary = 1,
+ IdeMaxChannel = 2
+} EFI_IDE_CHANNEL;
+
+typedef enum {
+ IdeMaster = 0,
+ IdeSlave = 1,
+ IdeMaxDevice = 2
+} EFI_IDE_DEVICE;
+
+typedef enum {
+ IdeMagnetic, /* ZIP Drive or LS120 Floppy Drive */
+ IdeCdRom, /* ATAPI CDROM */
+ IdeHardDisk, /* Hard Disk */
+ Ide48bitAddressingHardDisk, /* Hard Disk larger than 120GB */
+ IdeUnknown
+} IDE_DEVICE_TYPE;
+
+typedef enum {
+ SenseNoSenseKey,
+ SenseDeviceNotReadyNoRetry,
+ SenseDeviceNotReadyNeedRetry,
+ SenseNoMedia,
+ SenseMediaChange,
+ SenseMediaError,
+ SenseOtherSense
+} SENSE_RESULT;
+
+typedef enum {
+ AtaUdmaReadOp,
+ AtaUdmaReadExtOp,
+ AtaUdmaWriteOp,
+ AtaUdmaWriteExtOp
+} ATA_UDMA_OPERATION;
+
+//
+// IDE Registers
+//
+typedef union {
+ UINT16 Command; /* when write */
+ UINT16 Status; /* when read */
+} IDE_CMD_OR_STATUS;
+
+typedef union {
+ UINT16 Error; /* when read */
+ UINT16 Feature; /* when write */
+} IDE_ERROR_OR_FEATURE;
+
+typedef union {
+ UINT16 AltStatus; /* when read */
+ UINT16 DeviceControl; /* when write */
+} IDE_ALTSTATUS_OR_DEVICECONTROL;
+
+//
+// IDE registers set
+//
+typedef struct {
+ UINT16 Data;
+ IDE_ERROR_OR_FEATURE Reg1;
+ UINT16 SectorCount;
+ UINT16 SectorNumber;
+ UINT16 CylinderLsb;
+ UINT16 CylinderMsb;
+ UINT16 Head;
+ IDE_CMD_OR_STATUS Reg;
+
+ IDE_ALTSTATUS_OR_DEVICECONTROL Alt;
+ UINT16 DriveAddress;
+
+ UINT16 MasterSlave;
+ UINT16 BusMasterBaseAddr;
+} IDE_BASE_REGISTERS;
+
+//
+// IDE registers' base addresses
+//
+typedef struct {
+ UINT16 CommandBlockBaseAddr;
+ UINT16 ControlBlockBaseAddr;
+ UINT16 BusMasterBaseAddr;
+} IDE_REGISTERS_BASE_ADDR;
+
+//
+// Bit definitions in Programming Interface byte of the Class Code field
+// in PCI IDE controller's Configuration Space
+//
+#define IDE_PRIMARY_OPERATING_MODE BIT0
+#define IDE_PRIMARY_PROGRAMMABLE_INDICATOR BIT1
+#define IDE_SECONDARY_OPERATING_MODE BIT2
+#define IDE_SECONDARY_PROGRAMMABLE_INDICATOR BIT3
+
+
+//
+// Bus Master Reg
+//
+#define BMIC_NREAD BIT3
+#define BMIC_START BIT0
+#define BMIS_INTERRUPT BIT2
+#define BMIS_ERROR BIT1
+
+#define BMICP_OFFSET 0x00
+#define BMISP_OFFSET 0x02
+#define BMIDP_OFFSET 0x04
+#define BMICS_OFFSET 0x08
+#define BMISS_OFFSET 0x0A
+#define BMIDS_OFFSET 0x0C
+
+//
+// Time Out Value For IDE Device Polling
+//
+
+//
+// ATATIMEOUT is used for waiting time out for ATA device
+//
+
+//
+// 1 second
+//
+#define ATATIMEOUT 1000
+
+//
+// ATAPITIMEOUT is used for waiting operation
+// except read and write time out for ATAPI device
+//
+
+//
+// 1 second
+//
+#define ATAPITIMEOUT 1000
+
+//
+// ATAPILONGTIMEOUT is used for waiting read and
+// write operation timeout for ATAPI device
+//
+
+//
+// 2 seconds
+//
+#define CDROMLONGTIMEOUT 2000
+
+//
+// 5 seconds
+//
+#define ATAPILONGTIMEOUT 5000
+
+//
+// 10 seconds
+//
+#define ATASMARTTIMEOUT 10000
+
+
+//
+// ATAPI6 related data structure definition
+//
+
+//
+// The maximum sectors count in 28 bit addressing mode
+//
+#define MAX_28BIT_ADDRESSING_CAPACITY 0xfffffff
+
+#pragma pack(1)
+
+typedef struct {
+ UINT32 RegionBaseAddr;
+ UINT16 ByteCount;
+ UINT16 EndOfTable;
+} IDE_DMA_PRD;
+
+#pragma pack()
+
+#define SETFEATURE TRUE
+#define CLEARFEATURE FALSE
+
+///
+/// PIO mode definition
+///
+typedef enum _ATA_PIO_MODE_ {
+ AtaPioModeBelow2,
+ AtaPioMode2,
+ AtaPioMode3,
+ AtaPioMode4
+} ATA_PIO_MODE;
+
+//
+// Multi word DMA definition
+//
+typedef enum _ATA_MDMA_MODE_ {
+ AtaMdmaMode0,
+ AtaMdmaMode1,
+ AtaMdmaMode2
+} ATA_MDMA_MODE;
+
+//
+// UDMA mode definition
+//
+typedef enum _ATA_UDMA_MODE_ {
+ AtaUdmaMode0,
+ AtaUdmaMode1,
+ AtaUdmaMode2,
+ AtaUdmaMode3,
+ AtaUdmaMode4,
+ AtaUdmaMode5
+} ATA_UDMA_MODE;
+
+#define ATA_MODE_CATEGORY_DEFAULT_PIO 0x00
+#define ATA_MODE_CATEGORY_FLOW_PIO 0x01
+#define ATA_MODE_CATEGORY_MDMA 0x04
+#define ATA_MODE_CATEGORY_UDMA 0x08
+
+#pragma pack(1)
+
+typedef struct {
+ UINT8 ModeNumber : 3;
+ UINT8 ModeCategory : 5;
+} ATA_TRANSFER_MODE;
+
+typedef struct {
+ UINT8 Sector;
+ UINT8 Heads;
+ UINT8 MultipleSector;
+} ATA_DRIVE_PARMS;
+
+#pragma pack()
+//
+// IORDY Sample Point field value
+//
+#define ISP_5_CLK 0
+#define ISP_4_CLK 1
+#define ISP_3_CLK 2
+#define ISP_2_CLK 3
+
+//
+// Recovery Time field value
+//
+#define RECVY_4_CLK 0
+#define RECVY_3_CLK 1
+#define RECVY_2_CLK 2
+#define RECVY_1_CLK 3
+
+//
+// Slave IDE Timing Register Enable
+//
+#define SITRE BIT14
+
+//
+// DMA Timing Enable Only Select 1
+//
+#define DTE1 BIT7
+
+//
+// Pre-fetch and Posting Enable Select 1
+//
+#define PPE1 BIT6
+
+//
+// IORDY Sample Point Enable Select 1
+//
+#define IE1 BIT5
+
+//
+// Fast Timing Bank Drive Select 1
+//
+#define TIME1 BIT4
+
+//
+// DMA Timing Enable Only Select 0
+//
+#define DTE0 BIT3
+
+//
+// Pre-fetch and Posting Enable Select 0
+//
+#define PPE0 BIT2
+
+//
+// IOREY Sample Point Enable Select 0
+//
+#define IE0 BIT1
+
+//
+// Fast Timing Bank Drive Select 0
+//
+#define TIME0 BIT0
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/ComponentName.c
new file mode 100644
index 0000000000..e495d96af8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/ComponentName.c
@@ -0,0 +1,168 @@
+/** @file
+ Implements EFI Component Name Protocol for VGA Mini Port Driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VgaMiniPort.h"
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gPciVgaMiniPortComponentName = {
+ PciVgaMiniPortComponentNameGetDriverName,
+ PciVgaMiniPortComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gPciVgaMiniPortComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) PciVgaMiniPortComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) PciVgaMiniPortComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mPciVgaMiniPortDriverNameTable[] = {
+ {
+ "eng;en",
+ L"PCI VGA Mini Port Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mPciVgaMiniPortDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gPciVgaMiniPortComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.c b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.c
new file mode 100644
index 0000000000..25d1e3beb7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.c
@@ -0,0 +1,331 @@
+/** @file
+ Implements EFI Driver Binding Protocol and VGA Mini Port Protocol for VGA Mini Port Driver.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VgaMiniPort.h"
+
+//
+// EFI Driver Binding Protocol Instance
+//
+// This driver has a version value of 0x00000000. This is the
+// lowest possible priority for a driver. This is done on purpose to help
+// the developers of UGA drivers. This driver can bind if no UGA driver
+// is present, so a console is available. Then, when a UGA driver is loaded
+// this driver can be disconnected, and the UGA driver can be connected.
+// As long as the UGA driver has a version value greater than 0x00000000, it
+// will be connected first and will block this driver from connecting.
+//
+EFI_DRIVER_BINDING_PROTOCOL gPciVgaMiniPortDriverBinding = {
+ PciVgaMiniPortDriverBindingSupported,
+ PciVgaMiniPortDriverBindingStart,
+ PciVgaMiniPortDriverBindingStop,
+ 0x00000000,
+ NULL,
+ NULL
+};
+
+/**
+ Entrypoint of VGA Mini Port Driver.
+
+ This function is the entrypoint of UVGA Mini Port Driver. It installs Driver Binding
+ Protocols together with Component Name Protocols.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gPciVgaMiniPortDriverBinding,
+ ImageHandle,
+ &gPciVgaMiniPortComponentName,
+ &gPciVgaMiniPortComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether VGA Mini Port driver supports this device.
+
+ @param This The driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval EFI_UNSUPPORTED This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI VGA Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ //
+ // See if the device is an enabled VGA device.
+ // Most systems can only have on VGA device on at a time.
+ //
+ if (((Pci.Hdr.Command & 0x03) == 0x03) && IS_PCI_VGA (&Pci)) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Starts the VGA device with this driver.
+
+ This function consumes PCI I/O Protocol, and installs VGA Mini Port Protocol
+ onto the VGA device handle.
+
+ @param This The driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the driver.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_VGA_MINI_PORT_DEV *PciVgaMiniPortPrivate;
+
+ PciVgaMiniPortPrivate = NULL;
+ PciIo = NULL;
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Allocate the private device structure
+ //
+ PciVgaMiniPortPrivate = AllocateZeroPool (sizeof (PCI_VGA_MINI_PORT_DEV));
+ ASSERT (PciVgaMiniPortPrivate != NULL);
+
+ //
+ // Initialize the private device structure
+ //
+ PciVgaMiniPortPrivate->Signature = PCI_VGA_MINI_PORT_DEV_SIGNATURE;
+ PciVgaMiniPortPrivate->Handle = Controller;
+ PciVgaMiniPortPrivate->PciIo = PciIo;
+
+ PciVgaMiniPortPrivate->VgaMiniPort.SetMode = PciVgaMiniPortSetMode;
+ PciVgaMiniPortPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
+ PciVgaMiniPortPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
+ PciVgaMiniPortPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
+ PciVgaMiniPortPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ PciVgaMiniPortPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ PciVgaMiniPortPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ PciVgaMiniPortPrivate->VgaMiniPort.MaxMode = 1;
+
+ //
+ // Install VGA Mini Port Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ &PciVgaMiniPortPrivate->VgaMiniPort,
+ NULL
+ );
+Done:
+ if (EFI_ERROR (Status)) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (PciVgaMiniPortPrivate != NULL) {
+ FreePool (PciVgaMiniPortPrivate);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop the VGA device with this driver.
+
+ This function uninstalls VGA Mini Port Protocol from the VGA device handle,
+ and closes PCI I/O Protocol.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The child number that opened controller
+ BY_CHILD.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The controller or children are stopped.
+ @retval EFI_DEVICE_ERROR Failed to stop the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
+ PCI_VGA_MINI_PORT_DEV *PciVgaMiniPortPrivate;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ (VOID **) &VgaMiniPort,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ PciVgaMiniPortPrivate = PCI_VGA_MINI_PORT_DEV_FROM_THIS (VgaMiniPort);
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ &PciVgaMiniPortPrivate->VgaMiniPort
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (PciVgaMiniPortPrivate);
+
+ return EFI_SUCCESS;
+}
+//
+// VGA Mini Port Protocol Functions
+//
+
+/**
+ Sets the text display mode of a VGA controller.
+
+ This function implements EFI_VGA_MINI_PORT_PROTOCOL.SetMode().
+ If ModeNumber exceeds the valid range, then EFI_UNSUPPORTED is returned.
+ Otherwise, EFI_SUCCESS is directly returned without real operation.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber Mode number. 0 - 80x25 1-80x50
+
+ @retval EFI_SUCCESS The mode was set
+ @retval EFI_UNSUPPORTED ModeNumber is not supported.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ if (ModeNumber > This->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.h b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.h
new file mode 100644
index 0000000000..f39c00364b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.h
@@ -0,0 +1,271 @@
+/** @file
+ Internal include file for VGA Mini Port Driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VGA_MINIPORT_H_
+#define _VGA_MINIPORT_H_
+
+//
+// The package level header files this module uses
+//
+#include <PiDxe.h>
+//
+// The protocols, PPI and GUID defintions for this module
+//
+#include <Protocol/PciIo.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Protocol/ComponentName2.h>
+
+
+//
+// The Library classes this module consumes
+//
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gPciVgaMiniPortDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gPciVgaMiniPortComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gPciVgaMiniPortComponentName2;
+
+//
+// PCI VGA MiniPort Device Structure
+//
+#define PCI_VGA_MINI_PORT_DEV_SIGNATURE SIGNATURE_32('P','V','M','P')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+} PCI_VGA_MINI_PORT_DEV;
+
+#define PCI_VGA_MINI_PORT_DEV_FROM_THIS(a) CR(a, PCI_VGA_MINI_PORT_DEV, VgaMiniPort, PCI_VGA_MINI_PORT_DEV_SIGNATURE)
+
+//
+// Driver Binding Protocol functions
+//
+/**
+ Check whether VGA Mini Port driver supports this device.
+
+ @param This The driver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval EFI_UNSUPPORTED This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the VGA device with this driver.
+
+ This function consumes PCI I/O Protocol, and installs VGA Mini Port Protocol
+ onto the VGA device handle.
+
+ @param This The driver binding instance.
+ @param Controller The controller to check.
+ @param RemainingDevicePath The remaining device patch.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval EFI_ALREADY_STARTED The controller is already controlled by the driver.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate resources.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the VGA device with this driver.
+
+ This function uninstalls VGA Mini Port Protocol from the VGA device handle,
+ and closes PCI I/O Protocol.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The child number that opened controller
+ BY_CHILD.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The controller or children are stopped.
+ @retval EFI_DEVICE_ERROR Failed to stop the driver.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// VGA Mini Port Protocol functions
+//
+/**
+ Sets the text display mode of a VGA controller.
+
+ This function implements EFI_VGA_MINI_PORT_PROTOCOL.SetMode().
+ If ModeNumber exceeds the valid range, then EFI_UNSUPPORTED is returned.
+ Otherwise, EFI_SUCCESS is directly returned without real operation.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber Mode number. 0 - 80x25 1-80x50
+
+ @retval EFI_SUCCESS The mode was set
+ @retval EFI_UNSUPPORTED ModeNumber is not supported.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+EFI_STATUS
+EFIAPI
+PciVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.uni b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.uni
new file mode 100644
index 0000000000..ca9d2446d6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPort.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf
new file mode 100644
index 0000000000..d3c35faa6c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf
@@ -0,0 +1,57 @@
+## @file
+# VGA Mini Port Driver that manages VGA device and produces VGA Mini Port Protocol.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VgaMiniPort
+ MODULE_UNI_FILE = VgaMiniPort.uni
+ FILE_GUID = 15C5E761-58D8-461a-9173-CAB020916264
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PciVgaMiniPortDriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+# DRIVER_BINDING = gPciVgaMiniPortDriverBinding;
+# COMPONENT_NAME = gPciVgaMiniPortComponentName;
+# COMPONENT_NAME2 = gPciVgaMiniPortComponentName2;
+#
+
+[Sources]
+ ComponentName.c
+ VgaMiniPort.c
+ VgaMiniPort.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ UefiLib
+ DebugLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ MemoryAllocationLib
+
+[Protocols]
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiVgaMiniPortProtocolGuid ## BY_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VgaMiniPortExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortExtra.uni b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortExtra.uni
new file mode 100644
index 0000000000..731713fbc6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Contributions.txt b/Core/IntelFrameworkModulePkg/Contributions.txt
new file mode 100644
index 0000000000..f87cbd73c6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Contributions.txt
@@ -0,0 +1,218 @@
+
+======================
+= Code Contributions =
+======================
+
+To make a contribution to a TianoCore project, follow these steps.
+1. Create a change description in the format specified below to
+ use in the source control commit log.
+2. Your commit message must include your "Signed-off-by" signature,
+ and "Contributed-under" message.
+3. Your "Contributed-under" message explicitly states that the
+ contribution is made under the terms of the specified
+ contribution agreement. Your "Contributed-under" message
+ must include the name of contribution agreement and version.
+ For example: Contributed-under: TianoCore Contribution Agreement 1.0
+ The "TianoCore Contribution Agreement" is included below in
+ this document.
+4. Submit your code to the TianoCore project using the process
+ that the project documents on its web page. If the process is
+ not documented, then submit the code on development email list
+ for the project.
+5. It is preferred that contributions are submitted using the same
+ copyright license as the base project. When that is not possible,
+ then contributions using the following licenses can be accepted:
+ * BSD (2-clause): http://opensource.org/licenses/BSD-2-Clause
+ * BSD (3-clause): http://opensource.org/licenses/BSD-3-Clause
+ * MIT: http://opensource.org/licenses/MIT
+ * Python-2.0: http://opensource.org/licenses/Python-2.0
+ * Zlib: http://opensource.org/licenses/Zlib
+
+ Contributions of code put into the public domain can also be
+ accepted.
+
+ Contributions using other licenses might be accepted, but further
+ review will be required.
+
+=====================================================
+= Change Description / Commit Message / Patch Email =
+=====================================================
+
+Your change description should use the standard format for a
+commit message, and must include your "Signed-off-by" signature
+and the "Contributed-under" message.
+
+== Sample Change Description / Commit Message =
+
+=== Start of sample patch email message ===
+
+From: Contributor Name <contributor@example.com>
+Subject: [PATCH] CodeModule: Brief-single-line-summary
+
+Full-commit-message
+
+Contributed-under: TianoCore Contribution Agreement 1.0
+Signed-off-by: Contributor Name <contributor@example.com>
+---
+
+An extra message for the patch email which will not be considered part
+of the commit message can be added here.
+
+Patch content inline or attached
+
+=== End of sample patch email message ===
+
+=== Notes for sample patch email ===
+
+* The first line of commit message is taken from the email's subject
+ line following [PATCH]. The remaining portion of the commit message
+ is the email's content until the '---' line.
+* git format-patch is one way to create this format
+
+=== Definitions for sample patch email ===
+
+* "CodeModule" is a short idenfier for the affected code. For
+ example MdePkg, or MdeModulePkg UsbBusDxe.
+* "Brief-single-line-summary" is a short summary of the change.
+* The entire first line should be less than ~70 characters.
+* "Full-commit-message" a verbose multiple line comment describing
+ the change. Each line should be less than ~70 characters.
+* "Contributed-under" explicitely states that the contribution is
+ made under the terms of the contribtion agreement. This
+ agreement is included below in this document.
+* "Signed-off-by" is the contributor's signature identifying them
+ by their real/legal name and their email address.
+
+========================================
+= TianoCore Contribution Agreement 1.0 =
+========================================
+
+INTEL CORPORATION ("INTEL") MAKES AVAILABLE SOFTWARE, DOCUMENTATION,
+INFORMATION AND/OR OTHER MATERIALS FOR USE IN THE TIANOCORE OPEN SOURCE
+PROJECT (COLLECTIVELY "CONTENT"). USE OF THE CONTENT IS GOVERNED BY THE
+TERMS AND CONDITIONS OF THIS AGREEMENT BETWEEN YOU AND INTEL AND/OR THE
+TERMS AND CONDITIONS OF LICENSE AGREEMENTS OR NOTICES INDICATED OR
+REFERENCED BELOW. BY USING THE CONTENT, YOU AGREE THAT YOUR USE OF THE
+CONTENT IS GOVERNED BY THIS AGREEMENT AND/OR THE TERMS AND CONDITIONS
+OF ANY APPLICABLE LICENSE AGREEMENTS OR NOTICES INDICATED OR REFERENCED
+BELOW. IF YOU DO NOT AGREE TO THE TERMS AND CONDITIONS OF THIS
+AGREEMENT AND THE TERMS AND CONDITIONS OF ANY APPLICABLE LICENSE
+AGREEMENTS OR NOTICES INDICATED OR REFERENCED BELOW, THEN YOU MAY NOT
+USE THE CONTENT.
+
+Unless otherwise indicated, all Content made available on the TianoCore
+site is provided to you under the terms and conditions of the BSD
+License ("BSD"). A copy of the BSD License is available at
+http://opensource.org/licenses/bsd-license.php
+or when applicable, in the associated License.txt file.
+
+Certain other content may be made available under other licenses as
+indicated in or with such Content. (For example, in a License.txt file.)
+
+You accept and agree to the following terms and conditions for Your
+present and future Contributions submitted to TianoCore site. Except
+for the license granted to Intel hereunder, You reserve all right,
+title, and interest in and to Your Contributions.
+
+== SECTION 1: Definitions ==
+* "You" or "Contributor" shall mean the copyright owner or legal
+ entity authorized by the copyright owner that is making a
+ Contribution hereunder. All other entities that control, are
+ controlled by, or are under common control with that entity are
+ considered to be a single Contributor. For the purposes of this
+ definition, "control" means (i) the power, direct or indirect, to
+ cause the direction or management of such entity, whether by
+ contract or otherwise, or (ii) ownership of fifty percent (50%)
+ or more of the outstanding shares, or (iii) beneficial ownership
+ of such entity.
+* "Contribution" shall mean any original work of authorship,
+ including any modifications or additions to an existing work,
+ that is intentionally submitted by You to the TinaoCore site for
+ inclusion in, or documentation of, any of the Content. For the
+ purposes of this definition, "submitted" means any form of
+ electronic, verbal, or written communication sent to the
+ TianoCore site or its representatives, including but not limited
+ to communication on electronic mailing lists, source code
+ control systems, and issue tracking systems that are managed by,
+ or on behalf of, the TianoCore site for the purpose of
+ discussing and improving the Content, but excluding
+ communication that is conspicuously marked or otherwise
+ designated in writing by You as "Not a Contribution."
+
+== SECTION 2: License for Contributions ==
+* Contributor hereby agrees that redistribution and use of the
+ Contribution in source and binary forms, with or without
+ modification, are permitted provided that the following
+ conditions are met:
+** Redistributions of source code must retain the Contributor's
+ copyright notice, this list of conditions and the following
+ disclaimer.
+** Redistributions in binary form must reproduce the Contributor's
+ copyright notice, this list of conditions and the following
+ disclaimer in the documentation and/or other materials provided
+ with the distribution.
+* Disclaimer. None of the names of Contributor, Intel, or the names
+ of their respective contributors may be used to endorse or
+ promote products derived from this software without specific
+ prior written permission.
+* Contributor grants a license (with the right to sublicense) under
+ claims of Contributor's patents that Contributor can license that
+ are infringed by the Contribution (as delivered by Contributor) to
+ make, use, distribute, sell, offer for sale, and import the
+ Contribution and derivative works thereof solely to the minimum
+ extent necessary for licensee to exercise the granted copyright
+ license; this patent license applies solely to those portions of
+ the Contribution that are unmodified. No hardware per se is
+ licensed.
+* EXCEPT AS EXPRESSLY SET FORTH IN SECTION 3 BELOW, THE
+ CONTRIBUTION IS PROVIDED BY THE CONTRIBUTOR "AS IS" AND ANY
+ EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
+ PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+ CONTRIBUTOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THE
+ CONTRIBUTION, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ DAMAGE.
+
+== SECTION 3: Representations ==
+* You represent that You are legally entitled to grant the above
+ license. If your employer(s) has rights to intellectual property
+ that You create that includes Your Contributions, You represent
+ that You have received permission to make Contributions on behalf
+ of that employer, that Your employer has waived such rights for
+ Your Contributions.
+* You represent that each of Your Contributions is Your original
+ creation (see Section 4 for submissions on behalf of others).
+ You represent that Your Contribution submissions include complete
+ details of any third-party license or other restriction
+ (including, but not limited to, related patents and trademarks)
+ of which You are personally aware and which are associated with
+ any part of Your Contributions.
+
+== SECTION 4: Third Party Contributions ==
+* Should You wish to submit work that is not Your original creation,
+ You may submit it to TianoCore site separately from any
+ Contribution, identifying the complete details of its source
+ and of any license or other restriction (including, but not
+ limited to, related patents, trademarks, and license agreements)
+ of which You are personally aware, and conspicuously marking the
+ work as "Submitted on behalf of a third-party: [named here]".
+
+== SECTION 5: Miscellaneous ==
+* Applicable Laws. Any claims arising under or relating to this
+ Agreement shall be governed by the internal substantive laws of
+ the State of Delaware or federal courts located in Delaware,
+ without regard to principles of conflict of laws.
+* Language. This Agreement is in the English language only, which
+ language shall be controlling in all respects, and all versions
+ of this Agreement in any other language shall be for accommodation
+ only and shall not be binding. All communications and notices made
+ or given pursuant to this Agreement, and all documentation and
+ support to be provided, unless otherwise noted, shall be in the
+ English language.
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
new file mode 100644
index 0000000000..e8ea11c4f8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.c
@@ -0,0 +1,780 @@
+/** @file
+ EFI glue for BIOS INT 13h block devices.
+
+ This file is coded to EDD 3.0 as defined by T13 D1386 Revision 4
+ Availible on http://www.t13.org/#Project drafts
+ Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r4.pdf
+
+Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+//
+// Global data declaration
+//
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosBlockIoDriverBinding = {
+ BiosBlockIoDriverBindingSupported,
+ BiosBlockIoDriverBindingStart,
+ BiosBlockIoDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+//
+// Semaphore to control access to global variables mActiveInstances and mBufferUnder1Mb
+//
+EFI_LOCK mGlobalDataLock = EFI_INITIALIZE_LOCK_VARIABLE(TPL_APPLICATION);
+
+//
+// Number of active instances of this protocol. This is used to allocate/free
+// the shared buffer. You must acquire the semaphore to modify.
+//
+UINTN mActiveInstances = 0;
+
+//
+// Pointer to the beginning of the buffer used for real mode thunk
+// You must acquire the semaphore to modify.
+//
+EFI_PHYSICAL_ADDRESS mBufferUnder1Mb = 0;
+
+//
+// Address packet is a buffer under 1 MB for all version EDD calls
+//
+EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb;
+
+//
+// This is a buffer for INT 13h func 48 information
+//
+BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb;
+
+//
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
+// 0xFE00 bytes is the max transfer size supported.
+//
+VOID *mEdd11Buffer;
+
+/**
+ Driver entry point.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Entrypoint successfully executed.
+ @retval Others Fail to execute entrypoint.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install protocols
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosBlockIoDriverBinding,
+ ImageHandle,
+ &gBiosBlockIoComponentName,
+ &gBiosBlockIoComponentName2
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ //
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ NULL
+ );
+}
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ PCI_TYPE00 Pci;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI VGA Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE ||
+ (Pci.Hdr.ClassCode[2] == PCI_BASE_CLASS_INTELLIGENT && Pci.Hdr.ClassCode[1] == PCI_SUB_CLASS_INTELLIGENT)
+ ) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *PciDevPath;
+ UINTN Index;
+ UINTN Flags;
+ UINTN TmpAddress;
+ BOOLEAN DeviceEnable;
+
+ //
+ // Initialize variables
+ //
+ PciIo = NULL;
+ PciDevPath = NULL;
+
+ DeviceEnable = FALSE;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &PciDevPath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+
+ DeviceEnable = TRUE;
+
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ &DiskStart,
+ &DiskEnd,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // All instances share a buffer under 1MB to put real mode thunk code in
+ // If it has not been allocated, then we allocate it.
+ //
+ if (mBufferUnder1Mb == 0) {
+ //
+ // Should only be here if there are no active instances
+ //
+ ASSERT (mActiveInstances == 0);
+
+ //
+ // Acquire the lock
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+
+ //
+ // Allocate below 1MB
+ //
+ mBufferUnder1Mb = 0x00000000000FFFFF;
+ Status = gBS->AllocatePages (AllocateMaxAddress, EfiBootServicesData, BLOCK_IO_BUFFER_PAGE_SIZE, &mBufferUnder1Mb);
+
+ //
+ // Release the lock
+ //
+ EfiReleaseLock (&mGlobalDataLock);
+
+ //
+ // Check memory allocation success
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // In checked builds we want to assert if the allocate failed.
+ //
+ ASSERT_EFI_ERROR (Status);
+ Status = EFI_OUT_OF_RESOURCES;
+ mBufferUnder1Mb = 0;
+ goto Error;
+ }
+
+ TmpAddress = (UINTN) mBufferUnder1Mb;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEdd11Buffer = (VOID *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mEdd11Buffer + MAX_EDD11_XFER;
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mLegacyDriverUnder1Mb = (BIOS_LEGACY_DRIVE *) ALIGN_VARIABLE (TmpAddress);
+
+ TmpAddress = (UINTN) mLegacyDriverUnder1Mb + sizeof (BIOS_LEGACY_DRIVE);
+ //
+ // Adjusting the value to be on proper boundary
+ //
+ mEddBufferUnder1Mb = (EDD_DEVICE_ADDRESS_PACKET *) ALIGN_VARIABLE (TmpAddress);
+ }
+ //
+ // Allocate the private device structure for each disk
+ //
+ for (Index = DiskStart; Index < DiskEnd; Index++) {
+
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (BIOS_BLOCK_IO_DEV),
+ (VOID **) &BiosBlockIoPrivate
+ );
+ if (EFI_ERROR (Status)) {
+ goto Error;
+ }
+ //
+ // Zero the private device structure
+ //
+ ZeroMem (BiosBlockIoPrivate, sizeof (BIOS_BLOCK_IO_DEV));
+
+ //
+ // Initialize the private device structure
+ //
+ BiosBlockIoPrivate->Signature = BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE;
+ BiosBlockIoPrivate->ControllerHandle = Controller;
+ BiosBlockIoPrivate->LegacyBios = LegacyBios;
+ BiosBlockIoPrivate->PciIo = PciIo;
+
+ BiosBlockIoPrivate->Bios.Floppy = FALSE;
+ BiosBlockIoPrivate->Bios.Number = (UINT8) Index;
+ BiosBlockIoPrivate->Bios.Letter = (UINT8) (Index - 0x80 + 'C');
+ BiosBlockIoPrivate->BlockMedia.RemovableMedia = FALSE;
+
+ if (BiosInitBlockIo (BiosBlockIoPrivate)) {
+ SetBiosInitBlockIoDevicePath (PciDevPath, &BiosBlockIoPrivate->Bios, &BiosBlockIoPrivate->DevicePath);
+
+ //
+ // Install the Block Io Protocol onto a new child handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosBlockIoPrivate->Handle,
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ //
+ // Open For Child Device
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &BiosBlockIoPrivate->PciIo,
+ This->DriverBindingHandle,
+ BiosBlockIoPrivate->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ } else {
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+ }
+
+Error:
+ if (EFI_ERROR (Status)) {
+ if (PciIo != NULL) {
+ if (DeviceEnable) {
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+ }
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (PciDevPath != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ if (mBufferUnder1Mb != 0 && mActiveInstances == 0) {
+ gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+
+ //
+ // Clear the buffer back to 0
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+ }
+ } else {
+ //
+ // Successfully installed, so increment the number of active instances
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances++;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoPrivate;
+ UINTN Index;
+
+ //
+ // Decrement the number of active instances
+ //
+ if (mActiveInstances != 0) {
+ //
+ // Add a check since the stop function will be called 2 times for each handle
+ //
+ EfiAcquireLock (&mGlobalDataLock);
+ mActiveInstances--;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ if ((mActiveInstances == 0) && (mBufferUnder1Mb != 0)) {
+ //
+ // Free our global buffer
+ //
+ Status = gBS->FreePages (mBufferUnder1Mb, BLOCK_IO_BUFFER_PAGE_SIZE);
+ ASSERT_EFI_ERROR (Status);
+
+ EfiAcquireLock (&mGlobalDataLock);
+ mBufferUnder1Mb = 0;
+ EfiReleaseLock (&mGlobalDataLock);
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlockIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BiosBlockIoPrivate = BIOS_BLOCK_IO_FROM_THIS (BlockIo);
+
+ //
+ // Release PCI I/O and Block IO Protocols on the clild handle.
+ //
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ ChildHandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ &BiosBlockIoPrivate->BlockIo,
+ &gEfiDevicePathProtocolGuid,
+ BiosBlockIoPrivate->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ //
+ // Shutdown the hardware
+ //
+ BiosBlockIoPrivate->PciIo->Attributes (
+ BiosBlockIoPrivate->PciIo,
+ EfiPciIoAttributeOperationDisable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ gBS->FreePool (BiosBlockIoPrivate);
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build device path for device.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+**/
+VOID
+SetBiosInitBlockIoDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ EFI_STATUS Status;
+ BLOCKIO_VENDOR_DEVICE_PATH VendorNode;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // BugBug: Check for memory leaks!
+ //
+ if (Drive->EddVersion == EDD_VERSION_30) {
+ //
+ // EDD 3.0 case.
+ //
+ Status = BuildEdd30DevicePath (BaseDevicePath, Drive, DevicePath);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // EDD 1.1 device case or it is unrecognized EDD 3.0 device
+ //
+ ZeroMem (&VendorNode, sizeof (VendorNode));
+ VendorNode.DevicePath.Header.Type = HARDWARE_DEVICE_PATH;
+ VendorNode.DevicePath.Header.SubType = HW_VENDOR_DP;
+ SetDevicePathNodeLength (&VendorNode.DevicePath.Header, sizeof (VendorNode));
+ CopyMem (&VendorNode.DevicePath.Guid, &gBlockIoVendorGuid, sizeof (EFI_GUID));
+ VendorNode.LegacyDriveLetter = Drive->Number;
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &VendorNode.DevicePath.Header);
+ }
+}
+
+/**
+ Build device path for EDD 3.0.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+ @retval EFI_UNSUPPORTED It is failed to built device path.
+
+**/
+EFI_STATUS
+BuildEdd30DevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ )
+{
+ //
+ // AVL UINT64 Address;
+ // AVL EFI_HANDLE Handle;
+ //
+ EFI_DEV_PATH Node;
+ UINT32 Controller;
+
+ Controller = (UINT32) Drive->Parameters.InterfacePath.Pci.Controller;
+
+ ZeroMem (&Node, sizeof (Node));
+ if ((AsciiStrnCmp ("ATAPI", Drive->Parameters.InterfaceType, 5) == 0) ||
+ (AsciiStrnCmp ("ATA", Drive->Parameters.InterfaceType, 3) == 0)
+ ) {
+ //
+ // ATA or ATAPI drive found
+ //
+ Node.Atapi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Atapi.Header.SubType = MSG_ATAPI_DP;
+ SetDevicePathNodeLength (&Node.Atapi.Header, sizeof (ATAPI_DEVICE_PATH));
+ Node.Atapi.SlaveMaster = Drive->Parameters.DevicePath.Atapi.Master;
+ Node.Atapi.Lun = Drive->Parameters.DevicePath.Atapi.Lun;
+ Node.Atapi.PrimarySecondary = (UINT8) Controller;
+ } else {
+ //
+ // Not an ATA/ATAPI drive
+ //
+ if (Controller != 0) {
+ ZeroMem (&Node, sizeof (Node));
+ Node.Controller.Header.Type = HARDWARE_DEVICE_PATH;
+ Node.Controller.Header.SubType = HW_CONTROLLER_DP;
+ SetDevicePathNodeLength (&Node.Controller.Header, sizeof (CONTROLLER_DEVICE_PATH));
+ Node.Controller.ControllerNumber = Controller;
+ *DevicePath = AppendDevicePathNode (*DevicePath, &Node.DevPath);
+ }
+
+ ZeroMem (&Node, sizeof (Node));
+
+ if (AsciiStrnCmp ("SCSI", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // SCSI drive
+ //
+ Node.Scsi.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Scsi.Header.SubType = MSG_SCSI_DP;
+ SetDevicePathNodeLength (&Node.Scsi.Header, sizeof (SCSI_DEVICE_PATH));
+
+ //
+ // Lun is miss aligned in both EDD and Device Path data structures.
+ // thus we do a byte copy, to prevent alignment traps on IA-64.
+ //
+ CopyMem (&Node.Scsi.Lun, &Drive->Parameters.DevicePath.Scsi.Lun, sizeof (UINT16));
+ Node.Scsi.Pun = Drive->Parameters.DevicePath.Scsi.Pun;
+
+ } else if (AsciiStrnCmp ("USB", Drive->Parameters.InterfaceType, 3) == 0) {
+ //
+ // USB drive
+ //
+ Node.Usb.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.Usb.Header.SubType = MSG_USB_DP;
+ SetDevicePathNodeLength (&Node.Usb.Header, sizeof (USB_DEVICE_PATH));
+ Node.Usb.ParentPortNumber = (UINT8) Drive->Parameters.DevicePath.Usb.Reserved;
+
+ } else if (AsciiStrnCmp ("1394", Drive->Parameters.InterfaceType, 4) == 0) {
+ //
+ // 1394 drive
+ //
+ Node.F1394.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.F1394.Header.SubType = MSG_1394_DP;
+ SetDevicePathNodeLength (&Node.F1394.Header, sizeof (F1394_DEVICE_PATH));
+ Node.F1394.Guid = Drive->Parameters.DevicePath.FireWire.Guid;
+
+ } else if (AsciiStrnCmp ("FIBRE", Drive->Parameters.InterfaceType, 5) == 0) {
+ //
+ // Fibre drive
+ //
+ Node.FibreChannel.Header.Type = MESSAGING_DEVICE_PATH;
+ Node.FibreChannel.Header.SubType = MSG_FIBRECHANNEL_DP;
+ SetDevicePathNodeLength (&Node.FibreChannel.Header, sizeof (FIBRECHANNEL_DEVICE_PATH));
+ Node.FibreChannel.WWN = Drive->Parameters.DevicePath.FibreChannel.Wwn;
+ Node.FibreChannel.Lun = Drive->Parameters.DevicePath.FibreChannel.Lun;
+
+ } else {
+ DEBUG (
+ (
+ DEBUG_BLKIO, "It is unrecognized EDD 3.0 device, Drive Number = %x, InterfaceType = %s\n",
+ Drive->Number,
+ Drive->Parameters.InterfaceType
+ )
+ );
+ }
+ }
+
+ if (Node.DevPath.Type == 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *DevicePath = AppendDevicePathNode (BaseDevicePath, &Node.DevPath);
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h
new file mode 100644
index 0000000000..91617b79d9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosBlkIo.h
@@ -0,0 +1,432 @@
+/** @file
+
+Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BIOS_BLOCK_IO_H_
+#define _BIOS_BLOCK_IO_H_
+
+#include <Uefi.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DevicePath.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/BlockIoVendor.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "Edd.h"
+
+//
+// Global Variables
+//
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosBlockIoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosBlockIoComponentName2;
+
+
+//
+// Define the I2O class code
+//
+#define PCI_BASE_CLASS_INTELLIGENT 0x0e
+#define PCI_SUB_CLASS_INTELLIGENT 0x00
+
+//
+// Number of pages needed for our buffer under 1MB
+//
+#define BLOCK_IO_BUFFER_PAGE_SIZE (((sizeof (EDD_DEVICE_ADDRESS_PACKET) + sizeof (BIOS_LEGACY_DRIVE) + MAX_EDD11_XFER) / EFI_PAGE_SIZE) + 1 \
+ )
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Other internal functions
+//
+
+/**
+ Build device path for EDD 3.0.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+ @retval EFI_SUCCESS The device path is built successfully.
+ @retval EFI_UNSUPPORTED It is failed to built device path.
+
+**/
+EFI_STATUS
+BuildEdd30DevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ IN EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+/**
+ Initialize block I/O device instance
+
+ @param Dev Instance of block I/O device instance
+
+ @retval TRUE Initialization succeeds.
+ @retval FALSE Initialization fails.
+
+**/
+BOOLEAN
+BiosInitBlockIo (
+ IN BIOS_BLOCK_IO_DEV *Dev
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ );
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosReadLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosWriteLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ );
+
+/**
+ Gets parameters of block I/O device.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of device parameter retrieval.
+
+**/
+UINTN
+Int13GetDeviceParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Extension of INT13 call.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of this extension.
+
+**/
+UINTN
+Int13Extensions (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Gets parameters of legacy drive.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of drive parameter retrieval.
+
+**/
+UINTN
+GetDriveParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ );
+
+/**
+ Build device path for device.
+
+ @param BaseDevicePath Base device path.
+ @param Drive Legacy drive.
+ @param DevicePath Device path for output.
+
+**/
+VOID
+SetBiosInitBlockIoDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath,
+ IN BIOS_LEGACY_DRIVE *Drive,
+ OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
new file mode 100644
index 0000000000..698bb620e8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BiosInt13.c
@@ -0,0 +1,1495 @@
+/** @file
+ Routines that use BIOS to support INT 13 devices.
+
+Copyright (c) 1999 - 2015, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+//
+// Module global variables
+//
+//
+// Address packet is a buffer under 1 MB for all version EDD calls
+//
+extern EDD_DEVICE_ADDRESS_PACKET *mEddBufferUnder1Mb;
+
+//
+// This is a buffer for INT 13h func 48 information
+//
+extern BIOS_LEGACY_DRIVE *mLegacyDriverUnder1Mb;
+
+//
+// Buffer of 0xFE00 bytes for EDD 1.1 transfer must be under 1 MB
+// 0xFE00 bytes is the max transfer size supported.
+//
+extern VOID *mEdd11Buffer;
+
+
+/**
+ Initialize block I/O device instance
+
+ @param Dev Instance of block I/O device instance
+
+ @retval TRUE Initialization succeeds.
+ @retval FALSE Initialization fails.
+
+**/
+BOOLEAN
+BiosInitBlockIo (
+ IN BIOS_BLOCK_IO_DEV *Dev
+ )
+{
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ EFI_BLOCK_IO_MEDIA *BlockMedia;
+ BIOS_LEGACY_DRIVE *Bios;
+
+ BlockIo = &Dev->BlockIo;
+ BlockIo->Media = &Dev->BlockMedia;
+ BlockMedia = BlockIo->Media;
+ Bios = &Dev->Bios;
+
+ if (Int13GetDeviceParameters (Dev, Bios) != 0) {
+ if (Int13Extensions (Dev, Bios) != 0) {
+ BlockMedia->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ BlockMedia->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+
+ if ((Bios->Parameters.Flags & EDD_DEVICE_REMOVABLE) == EDD_DEVICE_REMOVABLE) {
+ BlockMedia->RemovableMedia = TRUE;
+ }
+
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ BlockMedia->BlockSize = 512;
+ BlockMedia->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ }
+
+ DEBUG ((DEBUG_INIT, "BlockSize = %d LastBlock = %d\n", BlockMedia->BlockSize, BlockMedia->LastBlock));
+
+ BlockMedia->LogicalPartition = FALSE;
+ BlockMedia->WriteCaching = FALSE;
+
+ //
+ // BugBug: Need to set this for removable media devices if they do not
+ // have media present
+ //
+ BlockMedia->ReadOnly = FALSE;
+ BlockMedia->MediaPresent = TRUE;
+
+ BlockIo->Reset = BiosBlockIoReset;
+ BlockIo->FlushBlocks = BiosBlockIoFlushBlocks;
+
+ if (!Bios->ExtendedInt13) {
+ //
+ // Legacy interfaces
+ //
+ BlockIo->ReadBlocks = BiosReadLegacyDrive;
+ BlockIo->WriteBlocks = BiosWriteLegacyDrive;
+ } else if ((Bios->EddVersion == EDD_VERSION_30) && (Bios->Extensions64Bit)) {
+ //
+ // EDD 3.0 Required for Device path, but extended reads are not required.
+ //
+ BlockIo->ReadBlocks = Edd30BiosReadBlocks;
+ BlockIo->WriteBlocks = Edd30BiosWriteBlocks;
+ } else {
+ //
+ // Assume EDD 1.1 - Read and Write functions.
+ // This could be EDD 3.0 without Extensions64Bit being set.
+ // If it's EDD 1.1 this will work, but the device path will not
+ // be correct. This will cause confusion to EFI OS installation.
+ //
+ BlockIo->ReadBlocks = Edd11BiosReadBlocks;
+ BlockIo->WriteBlocks = Edd11BiosWriteBlocks;
+ }
+
+ BlockMedia->LogicalPartition = FALSE;
+ BlockMedia->WriteCaching = FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Gets parameters of block I/O device.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of device parameter retrieval.
+
+**/
+UINTN
+Int13GetDeviceParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ UINTN CarryFlag;
+ UINT16 Cylinder;
+ EFI_IA32_REGISTER_SET Regs;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x08;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "Int13GetDeviceParameters: INT 13 08 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
+ if (CarryFlag != 0 || Regs.H.AH != 0x00) {
+ Drive->ErrorCode = Regs.H.AH;
+ return FALSE;
+ }
+
+ if (Drive->Floppy) {
+ if (Regs.H.BL == 0x10) {
+ Drive->AtapiFloppy = TRUE;
+ } else {
+ Drive->MaxHead = Regs.H.DH;
+ Drive->MaxSector = Regs.H.CL;
+ Drive->MaxCylinder = Regs.H.CH;
+ if (Drive->MaxSector == 0) {
+ //
+ // BugBug: You can not trust the Carry flag.
+ //
+ return FALSE;
+ }
+ }
+ } else {
+ Drive->MaxHead = (UINT8) (Regs.H.DH & 0x3f);
+ Cylinder = (UINT16) (((UINT16) Regs.H.DH & 0xc0) << 4);
+ Cylinder = (UINT16) (Cylinder | ((UINT16) Regs.H.CL & 0xc0) << 2);
+ Drive->MaxCylinder = (UINT16) (Cylinder + Regs.H.CH);
+ Drive->MaxSector = (UINT8) (Regs.H.CL & 0x3f);
+ }
+
+ return TRUE;
+}
+
+/**
+ Extension of INT13 call.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of this extension.
+
+**/
+UINTN
+Int13Extensions (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ INTN CarryFlag;
+ EFI_IA32_REGISTER_SET Regs;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x41;
+ Regs.X.BX = 0x55aa;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "Int13Extensions: INT 13 41 DL=%02x : CF=%d BX=%04x\n", Drive->Number, CarryFlag, Regs.X.BX));
+ if (CarryFlag != 0 || Regs.X.BX != 0xaa55) {
+ Drive->ExtendedInt13 = FALSE;
+ Drive->DriveLockingAndEjecting = FALSE;
+ Drive->Edd = FALSE;
+ return FALSE;
+ }
+
+ Drive->EddVersion = Regs.H.AH;
+ Drive->ExtendedInt13 = (BOOLEAN) ((Regs.X.CX & 0x01) == 0x01);
+ Drive->DriveLockingAndEjecting = (BOOLEAN) ((Regs.X.CX & 0x02) == 0x02);
+ Drive->Edd = (BOOLEAN) ((Regs.X.CX & 0x04) == 0x04);
+ Drive->Extensions64Bit = (BOOLEAN) (Regs.X.CX & 0x08);
+
+ Drive->ParametersValid = (UINT8) GetDriveParameters (BiosBlockIoDev, Drive);
+ return TRUE;
+}
+
+/**
+ Gets parameters of legacy drive.
+
+ @param BiosBlockIoDev Instance of block I/O device.
+ @param Drive Legacy drive.
+
+ @return Result of drive parameter retrieval.
+
+**/
+UINTN
+GetDriveParameters (
+ IN BIOS_BLOCK_IO_DEV *BiosBlockIoDev,
+ IN BIOS_LEGACY_DRIVE *Drive
+ )
+{
+ INTN CarryFlag;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN PointerMath;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x48;
+ Regs.H.DL = Drive->Number;
+
+ //
+ // EDD Buffer must be passed in with max buffer size as first entry in the buffer
+ //
+ mLegacyDriverUnder1Mb->Parameters.StructureSize = (UINT16) sizeof (EDD_DRIVE_PARAMETERS);
+ Regs.X.DS = EFI_SEGMENT ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
+ Regs.X.SI = EFI_OFFSET ((UINTN)(&mLegacyDriverUnder1Mb->Parameters));
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 48 DL=%02x : CF=%d AH=%02x\n", Drive->Number, CarryFlag, Regs.H.AH));
+ if (CarryFlag != 0 || Regs.H.AH != 0x00) {
+ Drive->ErrorCode = Regs.H.AH;
+ SetMem (&Drive->Parameters, sizeof (Drive->Parameters), 0xaf);
+ return FALSE;
+ }
+ //
+ // We only have one buffer < 1MB, so copy into our instance data
+ //
+ CopyMem (
+ &Drive->Parameters,
+ &mLegacyDriverUnder1Mb->Parameters,
+ sizeof (Drive->Parameters)
+ );
+
+ if (Drive->AtapiFloppy) {
+ //
+ // Sense Media Type
+ //
+ Regs.H.AH = 0x20;
+ Regs.H.DL = Drive->Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG ((DEBUG_INIT, "GetDriveParameters: INT 13 20 DL=%02x : CF=%d AL=%02x\n", Drive->Number, CarryFlag, Regs.H.AL));
+ if (CarryFlag != 0) {
+ //
+ // Media not present or unknown media present
+ //
+ if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
+ Drive->MaxHead = (UINT8) (Drive->Parameters.MaxHeads - 1);
+ Drive->MaxSector = (UINT8) Drive->Parameters.SectorsPerTrack;
+ ASSERT (Drive->MaxSector != 0);
+ Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
+ } else {
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ }
+
+ } else {
+ //
+ // Media Present
+ //
+ switch (Regs.H.AL) {
+ case 0x03:
+ //
+ // 720 KB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 9;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x04:
+ //
+ // 1.44MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 18;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x06:
+ //
+ // 2.88MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 36;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x0C:
+ //
+ // 360 KB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 9;
+ Drive->MaxCylinder = 39;
+ break;
+
+ case 0x0D:
+ //
+ // 1.2 MB
+ //
+ Drive->MaxHead = 1;
+ Drive->MaxSector = 15;
+ Drive->MaxCylinder = 79;
+ break;
+
+ case 0x0E:
+ //
+ // Toshiba 3 mode
+ //
+ case 0x0F:
+ //
+ // NEC 3 mode
+ //
+ case 0x10:
+ //
+ // Default Media
+ //
+ if ((Drive->Parameters.Flags & EDD_GEOMETRY_VALID) == EDD_GEOMETRY_VALID) {
+ Drive->MaxHead = (UINT8) (Drive->Parameters.MaxHeads - 1);
+ Drive->MaxSector = (UINT8) Drive->Parameters.SectorsPerTrack;
+ ASSERT (Drive->MaxSector != 0);
+ Drive->MaxCylinder = (UINT16) (Drive->Parameters.MaxCylinders - 1);
+ } else {
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ }
+ break;
+
+ default:
+ //
+ // Unknown media type.
+ //
+ Drive->MaxHead = 0;
+ Drive->MaxSector = 1;
+ Drive->MaxCylinder = 0;
+ break;
+ }
+ }
+
+ Drive->Parameters.PhysicalSectors = (Drive->MaxHead + 1) * Drive->MaxSector * (Drive->MaxCylinder + 1);
+ Drive->Parameters.BytesPerSector = 512;
+ }
+ //
+ // This data comes from the BIOS so it may not allways be valid
+ // since the BIOS may reuse this buffer for future accesses
+ //
+ PointerMath = EFI_SEGMENT (Drive->Parameters.Fdpt) << 4;
+ PointerMath += EFI_OFFSET (Drive->Parameters.Fdpt);
+ Drive->FdptPointer = (VOID *) PointerMath;
+
+ return TRUE;
+}
+//
+// Block IO Routines
+//
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = 0xffffffff;
+ AddressPacket->Lba = (UINT64) Lba;
+ AddressPacket->TransferBuffer = TransferBuffer;
+
+ Regs.H.AH = 0x42;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd30BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ BufferSize = BufferSize - TransferByteSize;
+ TransferBuffer += TransferByteSize;
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd30BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ AddressPacket->SegOffset = 0xffffffff;
+ AddressPacket->Lba = (UINT64) Lba;
+ AddressPacket->TransferBuffer = TransferBuffer;
+
+ Regs.H.AH = 0x43;
+ Regs.H.AL = 0x00;
+ //
+ // Write Verify Off
+ //
+ Regs.H.DL = (UINT8) (BiosBlockIoDev->Bios.Number);
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd30BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ BufferSize = BufferSize - TransferByteSize;
+ TransferBuffer += TransferByteSize;
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Flush the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+
+ @retval EFI_SUCCESS All outstanding data was written to the device
+ @retval EFI_DEVICE_ERROR The device reported an error while writting back the data
+ @retval EFI_NO_MEDIA There is no media in the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoFlushBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Reset the Block Device.
+
+ @param This Indicates a pointer to the calling context.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoReset (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN CarryFlag;
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.H.AH = 0x00;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
+ Regs.H.AH
+ )
+ );
+ if (CarryFlag != 0) {
+ if (Regs.H.AL == BIOS_RESET_FAILED) {
+ Regs.H.AH = 0x00;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_INIT, "BiosBlockIoReset: INT 13 00 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number, CarryFlag,
+ Regs.H.AH
+ )
+ );
+ if (CarryFlag != 0) {
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+//
+//
+// These functions need to double buffer all data under 1MB!
+//
+//
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosReadBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) mEdd11Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ //
+ // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
+ // format to transfer maximum 127 blocks of data.
+ // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
+ // INT13 function 42H will return data boundary error 09H.
+ //
+ AddressPacket->SegOffset = (UINT32) LShiftU64 (RShiftU64(TransferBuffer, 4), 16);
+ AddressPacket->Lba = (UINT64) Lba;
+
+ Regs.H.AH = 0x42;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd11BiosReadBlocks: INT 13 42 DL=%02x : CF=%d AH=%02x : LBA 0x%lx Block(s) %0d \n",
+ BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
+ )
+ );
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (Buffer, (VOID *) (UINTN) TransferBuffer, TransferByteSize);
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+Edd11BiosWriteBlocks (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EDD_DEVICE_ADDRESS_PACKET *AddressPacket;
+ //
+ // I exist only for readability
+ //
+ EFI_IA32_REGISTER_SET Regs;
+ UINT64 TransferBuffer;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN MaxTransferBlocks;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ AddressPacket = mEddBufferUnder1Mb;
+
+ MaxTransferBlocks = MAX_EDD11_XFER / BlockSize;
+
+ TransferBuffer = (UINT64)(UINTN) mEdd11Buffer;
+ for (; BufferSize > 0;) {
+ NumberOfBlocks = BufferSize / BlockSize;
+ NumberOfBlocks = NumberOfBlocks > MaxTransferBlocks ? MaxTransferBlocks : NumberOfBlocks;
+ //
+ // Max transfer MaxTransferBlocks
+ //
+ AddressPacket->PacketSizeInBytes = (UINT8) sizeof (EDD_DEVICE_ADDRESS_PACKET);
+ AddressPacket->Zero = 0;
+ AddressPacket->NumberOfBlocks = (UINT8) NumberOfBlocks;
+ AddressPacket->Zero2 = 0;
+ //
+ // TransferBuffer has been 4KB alignment. Normalize TransferBuffer to make offset as 0 in seg:offset
+ // format to transfer maximum 127 blocks of data.
+ // Otherwise when offset adding data size exceeds 0xFFFF, if OpROM does not normalize TransferBuffer,
+ // INT13 function 42H will return data boundary error 09H.
+ //
+ AddressPacket->SegOffset = (UINT32) LShiftU64 (RShiftU64(TransferBuffer, 4), 16);
+ AddressPacket->Lba = (UINT64) Lba;
+
+ Regs.H.AH = 0x43;
+ Regs.H.AL = 0x00;
+ //
+ // Write Verify disable
+ //
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+ Regs.X.SI = EFI_OFFSET (AddressPacket);
+ Regs.X.DS = EFI_SEGMENT (AddressPacket);
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem ((VOID *) (UINTN) TransferBuffer, Buffer, TransferByteSize);
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "Edd11BiosWriteBlocks: INT 13 43 DL=%02x : CF=%d AH=%02x\n: LBA 0x%lx Block(s) %0d \n",
+ BiosBlockIoDev->Bios.Number, CarryFlag, Regs.H.AH, Lba, NumberOfBlocks
+ )
+ );
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ ASSERT (FALSE);
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ Lba += NumberOfBlocks;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId Id of the media, changes every time the media is replaced.
+ @param Lba The starting Logical Block Address to read from
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the destination buffer for the data. The caller is
+ responsible for either having implicit or explicit ownership of the buffer.
+
+ @retval EFI_SUCCESS The data was read correctly from the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the read.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHANGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The read request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosReadLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN UpperCylinder;
+ UINTN Temp;
+ UINTN Cylinder;
+ UINTN Head;
+ UINTN Sector;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN ShortLba;
+ UINTN CheckLba;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN Retry;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ ShortLba = (UINTN) Lba;
+
+ while (BufferSize != 0) {
+ //
+ // Compute I/O location in Sector, Head, Cylinder format
+ //
+ Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
+ Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
+ Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
+ Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
+
+ //
+ // Limit transfer to this Head & Cylinder
+ //
+ NumberOfBlocks = BufferSize / BlockSize;
+ Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
+ NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
+
+ Retry = 3;
+ do {
+ //
+ // Perform the IO
+ //
+ Regs.H.AH = 2;
+ Regs.H.AL = (UINT8) NumberOfBlocks;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+
+ UpperCylinder = (Cylinder & 0x0f00) >> 2;
+
+ CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
+ CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
+ ShortLba,
+ CheckLba,
+ Sector,
+ BiosBlockIoDev->Bios.MaxSector,
+ Head,
+ BiosBlockIoDev->Bios.MaxHead,
+ Cylinder,
+ UpperCylinder)
+ );
+ ASSERT (CheckLba == ShortLba);
+
+ Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
+ Regs.H.DH = (UINT8) (Head & 0x3f);
+ Regs.H.CH = (UINT8) (Cylinder & 0xff);
+
+ Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
+ Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "INT 13h: AX:(02%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
+ Regs.H.AL,
+ (UINT8) (Head & 0x3f),
+ Regs.H.DL,
+ (UINT8) (Cylinder & 0xff),
+ (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
+ EFI_OFFSET (mEdd11Buffer),
+ EFI_SEGMENT (mEdd11Buffer))
+ );
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "BiosReadLegacyDrive: INT 13 02 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+ Retry--;
+ } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ //
+ // If the size of the media changed we need to reset the disk geometry
+ //
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ Media->BlockSize = 512;
+ }
+
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (Buffer, mEdd11Buffer, TransferByteSize);
+
+ ShortLba = ShortLba + NumberOfBlocks;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write BufferSize bytes from Lba into Buffer.
+
+ @param This Indicates a pointer to the calling context.
+ @param MediaId The media ID that the write request is for.
+ @param Lba The starting logical block address to be written. The caller is
+ responsible for writing to only legitimate locations.
+ @param BufferSize Size of Buffer, must be a multiple of device block size.
+ @param Buffer A pointer to the source buffer for the data.
+
+ @retval EFI_SUCCESS The data was written correctly to the device.
+ @retval EFI_WRITE_PROTECTED The device can not be written to.
+ @retval EFI_DEVICE_ERROR The device reported an error while performing the write.
+ @retval EFI_NO_MEDIA There is no media in the device.
+ @retval EFI_MEDIA_CHNAGED The MediaId does not matched the current device.
+ @retval EFI_BAD_BUFFER_SIZE The Buffer was not a multiple of the block size of the device.
+ @retval EFI_INVALID_PARAMETER The write request contains LBAs that are not valid,
+ or the buffer is not on proper alignment.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosWriteLegacyDrive (
+ IN EFI_BLOCK_IO_PROTOCOL *This,
+ IN UINT32 MediaId,
+ IN EFI_LBA Lba,
+ IN UINTN BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ EFI_BLOCK_IO_MEDIA *Media;
+ BIOS_BLOCK_IO_DEV *BiosBlockIoDev;
+ EFI_IA32_REGISTER_SET Regs;
+ UINTN UpperCylinder;
+ UINTN Temp;
+ UINTN Cylinder;
+ UINTN Head;
+ UINTN Sector;
+ UINTN NumberOfBlocks;
+ UINTN TransferByteSize;
+ UINTN ShortLba;
+ UINTN CheckLba;
+ UINTN BlockSize;
+ BIOS_LEGACY_DRIVE *Bios;
+ UINTN CarryFlag;
+ UINTN Retry;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ Media = This->Media;
+ BlockSize = Media->BlockSize;
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ if (MediaId != Media->MediaId) {
+ return EFI_MEDIA_CHANGED;
+ }
+
+ if (Lba > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((Lba + (BufferSize / BlockSize) - 1) > Media->LastBlock) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize % BlockSize != 0) {
+ return EFI_BAD_BUFFER_SIZE;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize == 0) {
+ return EFI_SUCCESS;
+ }
+
+ BiosBlockIoDev = BIOS_BLOCK_IO_FROM_THIS (This);
+ ShortLba = (UINTN) Lba;
+
+ while (BufferSize != 0) {
+ //
+ // Compute I/O location in Sector, Head, Cylinder format
+ //
+ Sector = (ShortLba % BiosBlockIoDev->Bios.MaxSector) + 1;
+ Temp = ShortLba / BiosBlockIoDev->Bios.MaxSector;
+ Head = Temp % (BiosBlockIoDev->Bios.MaxHead + 1);
+ Cylinder = Temp / (BiosBlockIoDev->Bios.MaxHead + 1);
+
+ //
+ // Limit transfer to this Head & Cylinder
+ //
+ NumberOfBlocks = BufferSize / BlockSize;
+ Temp = BiosBlockIoDev->Bios.MaxSector - Sector + 1;
+ NumberOfBlocks = NumberOfBlocks > Temp ? Temp : NumberOfBlocks;
+
+ Retry = 3;
+ do {
+ //
+ // Perform the IO
+ //
+ Regs.H.AH = 3;
+ Regs.H.AL = (UINT8) NumberOfBlocks;
+ Regs.H.DL = BiosBlockIoDev->Bios.Number;
+
+ UpperCylinder = (Cylinder & 0x0f00) >> 2;
+
+ CheckLba = Cylinder * (BiosBlockIoDev->Bios.MaxHead + 1) + Head;
+ CheckLba = CheckLba * BiosBlockIoDev->Bios.MaxSector + Sector - 1;
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "RLD: LBA %x (%x), Sector %x (%x), Head %x (%x), Cyl %x, UCyl %x\n",
+ ShortLba,
+ CheckLba,
+ Sector,
+ BiosBlockIoDev->Bios.MaxSector,
+ Head,
+ BiosBlockIoDev->Bios.MaxHead,
+ Cylinder,
+ UpperCylinder)
+ );
+ ASSERT (CheckLba == ShortLba);
+
+ Regs.H.CL = (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff));
+ Regs.H.DH = (UINT8) (Head & 0x3f);
+ Regs.H.CH = (UINT8) (Cylinder & 0xff);
+
+ Regs.X.BX = EFI_OFFSET (mEdd11Buffer);
+ Regs.X.ES = EFI_SEGMENT (mEdd11Buffer);
+
+ TransferByteSize = NumberOfBlocks * BlockSize;
+ CopyMem (mEdd11Buffer, Buffer, TransferByteSize);
+
+ DEBUG (
+ (DEBUG_BLKIO,
+ "INT 13h: AX:(03%02x) DX:(%02x%02x) CX:(%02x%02x) BX:(%04x) ES:(%04x)\n",
+ Regs.H.AL,
+ (UINT8) (Head & 0x3f),
+ Regs.H.DL,
+ (UINT8) (Cylinder & 0xff),
+ (UINT8) ((Sector & 0x3f) + (UpperCylinder & 0xff)),
+ EFI_OFFSET (mEdd11Buffer),
+ EFI_SEGMENT (mEdd11Buffer))
+ );
+
+ CarryFlag = BiosBlockIoDev->LegacyBios->Int86 (BiosBlockIoDev->LegacyBios, 0x13, &Regs);
+ DEBUG (
+ (
+ DEBUG_BLKIO, "BiosWriteLegacyDrive: INT 13 03 DL=%02x : CF=%d AH=%02x\n", BiosBlockIoDev->Bios.Number,
+ CarryFlag, Regs.H.AH
+ )
+ );
+ Retry--;
+ } while (CarryFlag != 0 && Retry != 0 && Regs.H.AH != BIOS_DISK_CHANGED);
+
+ Media->MediaPresent = TRUE;
+ if (CarryFlag != 0) {
+ //
+ // Return Error Status
+ //
+ BiosBlockIoDev->Bios.ErrorCode = Regs.H.AH;
+ if (BiosBlockIoDev->Bios.ErrorCode == BIOS_DISK_CHANGED) {
+ Media->MediaId++;
+ Bios = &BiosBlockIoDev->Bios;
+ if (Int13GetDeviceParameters (BiosBlockIoDev, Bios) != 0) {
+ if (Int13Extensions (BiosBlockIoDev, Bios) != 0) {
+ Media->LastBlock = (EFI_LBA) Bios->Parameters.PhysicalSectors - 1;
+ Media->BlockSize = (UINT32) Bios->Parameters.BytesPerSector;
+ } else {
+ //
+ // Legacy Interfaces
+ //
+ Media->LastBlock = (Bios->MaxHead + 1) * Bios->MaxSector * (Bios->MaxCylinder + 1) - 1;
+ Media->BlockSize = 512;
+ }
+ //
+ // If the size of the media changed we need to reset the disk geometry
+ //
+ Media->ReadOnly = FALSE;
+ gBS->HandleProtocol (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ gBS->ReinstallProtocolInterface (BiosBlockIoDev->Handle, &gEfiBlockIoProtocolGuid, BlockIo, BlockIo);
+ return EFI_MEDIA_CHANGED;
+ }
+ } else if (BiosBlockIoDev->Bios.ErrorCode == BIOS_WRITE_PROTECTED) {
+ Media->ReadOnly = TRUE;
+ return EFI_WRITE_PROTECTED;
+ }
+
+ if (Media->RemovableMedia) {
+ Media->MediaPresent = FALSE;
+ }
+
+ return EFI_DEVICE_ERROR;
+ }
+
+ Media->ReadOnly = FALSE;
+ ShortLba = ShortLba + NumberOfBlocks;
+ BufferSize = BufferSize - TransferByteSize;
+ Buffer = (VOID *) ((UINT8 *) Buffer + TransferByteSize);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
new file mode 100644
index 0000000000..86dd325d23
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
@@ -0,0 +1,65 @@
+## @file
+# BIOS Block IO module.
+#
+# This is the UEFI driver to thunk legacy BIOS int13 interface into UEFI block IO interface.
+# Once connected it installs EfiBlockIoProtocol on top of legacy BIOS int13.
+#
+# Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BlockIoDxe
+ MODULE_UNI_FILE = BlockIoDxe.uni
+ FILE_GUID = 4495E47E-42A9-4007-8c17-B6664F909D04
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosBlockIoDriverEntryPoint
+
+[Sources]
+ BiosBlkIo.h
+ Edd.h
+ BiosBlkIo.c
+ BiosInt13.c
+ ComponentName.c
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiLib
+ DevicePathLib
+ MemoryAllocationLib
+
+
+[Protocols]
+ gEfiBlockIoProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiLegacyBiosProtocolGuid ## TO_START
+
+
+[Guids]
+ gEfiLegacyBiosGuid ## PRODUCES ## UNDEFINED
+ gBlockIoVendorGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BlockIoDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.uni
new file mode 100644
index 0000000000..6698430ee1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxeExtra.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxeExtra.uni
new file mode 100644
index 0000000000..900682d090
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c
new file mode 100644
index 0000000000..21d17305fa
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/ComponentName.c
@@ -0,0 +1,309 @@
+/** @file
+
+Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosBlkIo.h"
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosBlockIoComponentName = {
+ BiosBlockIoComponentNameGetDriverName,
+ BiosBlockIoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosBlockIoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosBlockIoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosBlockIoComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosBlockIoDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT13] Block Io Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosBlockIoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosBlockIoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosBlockIoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h
new file mode 100644
index 0000000000..be4d8302cf
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/Edd.h
@@ -0,0 +1,209 @@
+/** @file
+ Include file to suport EDD 3.0.
+ This file is coded to T13 D1386 Revision 3
+ Availible on http://www.t13.org/#Project drafts
+ Currently at ftp://fission.dt.wdc.com/pub/standards/x3t13/project/d1386r3.pdf
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EDD_H_
+#define _EDD_H_
+
+//
+// packing with no compiler padding, so that the fields
+// of the following architected structures can be
+// properly accessed from C code.
+//
+#pragma pack(1)
+
+typedef struct {
+ UINT8 Bus;
+ UINT8 Device;
+ UINT8 Function;
+ UINT8 Controller;
+ UINT32 Reserved;
+} EDD_PCI;
+
+typedef struct {
+ UINT16 Base;
+ UINT16 Reserved;
+ UINT32 Reserved2;
+} EDD_LEGACY;
+
+typedef union {
+ EDD_PCI Pci;
+ EDD_LEGACY Legacy;
+} EDD_INTERFACE_PATH;
+
+typedef struct {
+ UINT8 Master;
+ UINT8 Reserved[15];
+} EDD_ATA;
+
+typedef struct {
+ UINT8 Master;
+ UINT8 Lun;
+ UINT8 Reserved[14];
+} EDD_ATAPI;
+
+typedef struct {
+ UINT16 Pun;
+ UINT64 Lun;
+ UINT8 Reserved[6];
+} EDD_SCSI;
+
+typedef struct {
+ UINT64 SerialNumber;
+ UINT64 Reserved;
+} EDD_USB;
+
+typedef struct {
+ UINT64 Guid;
+ UINT64 Reserved;
+} EDD_1394;
+
+typedef struct {
+ UINT64 Wwn;
+ UINT64 Lun;
+} EDD_FIBRE;
+
+typedef union {
+ EDD_ATA Ata;
+ EDD_ATAPI Atapi;
+ EDD_SCSI Scsi;
+ EDD_USB Usb;
+ EDD_1394 FireWire;
+ EDD_FIBRE FibreChannel;
+} EDD_DEVICE_PATH;
+
+typedef struct {
+ UINT16 StructureSize;
+ UINT16 Flags;
+ UINT32 MaxCylinders;
+ UINT32 MaxHeads;
+ UINT32 SectorsPerTrack;
+ UINT64 PhysicalSectors;
+ UINT16 BytesPerSector;
+ UINT32 Fdpt;
+ UINT16 Key;
+ UINT8 DevicePathLength;
+ UINT8 Reserved1;
+ UINT16 Reserved2;
+ CHAR8 HostBusType[4];
+ CHAR8 InterfaceType[8];
+ EDD_INTERFACE_PATH InterfacePath;
+ EDD_DEVICE_PATH DevicePath;
+ UINT8 Reserved3;
+ UINT8 Checksum;
+} EDD_DRIVE_PARAMETERS;
+
+//
+// EDD_DRIVE_PARAMETERS.Flags defines
+//
+#define EDD_GEOMETRY_VALID 0x02
+#define EDD_DEVICE_REMOVABLE 0x04
+#define EDD_WRITE_VERIFY_SUPPORTED 0x08
+#define EDD_DEVICE_CHANGE 0x10
+#define EDD_DEVICE_LOCKABLE 0x20
+
+//
+// BUGBUG: This bit does not follow the spec. It tends to be always set
+// to work properly with Win98.
+//
+#define EDD_DEVICE_GEOMETRY_MAX 0x40
+
+typedef struct {
+ UINT8 PacketSizeInBytes; // 0x18
+ UINT8 Zero;
+ UINT8 NumberOfBlocks; // Max 0x7f
+ UINT8 Zero2;
+ UINT32 SegOffset;
+ UINT64 Lba;
+ UINT64 TransferBuffer;
+ UINT32 ExtendedBlockCount; // Max 0xffffffff
+ UINT32 Zero3;
+} EDD_DEVICE_ADDRESS_PACKET;
+
+#define EDD_VERSION_30 0x30
+
+//
+// Int 13 BIOS Errors
+//
+#define BIOS_PASS 0x00
+#define BIOS_WRITE_PROTECTED 0x03
+#define BIOS_SECTOR_NOT_FOUND 0x04
+#define BIOS_RESET_FAILED 0x05
+#define BIOS_DISK_CHANGED 0x06
+#define BIOS_DRIVE_DOES_NOT_EXIST 0x07
+#define BIOS_DMA_ERROR 0x08
+#define BIOS_DATA_BOUNDRY_ERROR 0x09
+#define BIOS_BAD_SECTOR 0x0a
+#define BIOS_BAD_TRACK 0x0b
+#define BIOS_MEADIA_TYPE_NOT_FOUND 0x0c
+#define BIOS_INVALED_FORMAT 0x0d
+#define BIOS_ECC_ERROR 0x10
+#define BIOS_ECC_CORRECTED_ERROR 0x11
+#define BIOS_HARD_DRIVE_FAILURE 0x20
+#define BIOS_SEEK_FAILED 0x40
+#define BIOS_DRIVE_TIMEOUT 0x80
+#define BIOS_DRIVE_NOT_READY 0xaa
+#define BIOS_UNDEFINED_ERROR 0xbb
+#define BIOS_WRITE_FAULT 0xcc
+#define BIOS_SENSE_FAILED 0xff
+
+#define MAX_EDD11_XFER 0xfe00
+
+#pragma pack()
+//
+// Internal Data Structures
+//
+typedef struct {
+ CHAR8 Letter;
+ UINT8 Number;
+ UINT8 EddVersion;
+ BOOLEAN ExtendedInt13;
+ BOOLEAN DriveLockingAndEjecting;
+ BOOLEAN Edd;
+ BOOLEAN Extensions64Bit;
+ BOOLEAN ParametersValid;
+ UINT8 ErrorCode;
+ VOID *FdptPointer;
+ BOOLEAN Floppy;
+ BOOLEAN AtapiFloppy;
+ UINT8 MaxHead;
+ UINT8 MaxSector;
+ UINT16 MaxCylinder;
+ UINT16 Pad;
+ EDD_DRIVE_PARAMETERS Parameters;
+} BIOS_LEGACY_DRIVE;
+
+#define BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE SIGNATURE_32 ('b', 'b', 'i', 'o')
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_HANDLE ControllerHandle;
+ EFI_BLOCK_IO_PROTOCOL BlockIo;
+ EFI_BLOCK_IO_MEDIA BlockMedia;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ BIOS_LEGACY_DRIVE Bios;
+
+} BIOS_BLOCK_IO_DEV;
+
+#define BIOS_BLOCK_IO_FROM_THIS(a) CR (a, BIOS_BLOCK_IO_DEV, BlockIo, BIOS_CONSOLE_BLOCK_IO_DEV_SIGNATURE)
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
new file mode 100644
index 0000000000..8c7019f4f6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.c
@@ -0,0 +1,2428 @@
+/** @file
+ ConsoleOut Routines that speak VGA.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosKeyboard.h"
+
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding = {
+ BiosKeyboardDriverBindingSupported,
+ BiosKeyboardDriverBindingStart,
+ BiosKeyboardDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+
+/**
+ Enqueue the key.
+
+ @param Queue The queue to be enqueued.
+ @param KeyData The key data to be enqueued.
+
+ @retval EFI_NOT_READY The queue is full.
+ @retval EFI_SUCCESS Successfully enqueued the key data.
+
+**/
+EFI_STATUS
+Enqueue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if ((Queue->Rear + 1) % QUEUE_MAX_COUNT == Queue->Front) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (&Queue->Buffer[Queue->Rear], KeyData, sizeof (EFI_KEY_DATA));
+ Queue->Rear = (Queue->Rear + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Dequeue the key.
+
+ @param Queue The queue to be dequeued.
+ @param KeyData The key data to be dequeued.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS Successfully dequeued the key data.
+
+**/
+EFI_STATUS
+Dequeue (
+ IN SIMPLE_QUEUE *Queue,
+ IN EFI_KEY_DATA *KeyData
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ CopyMem (KeyData, &Queue->Buffer[Queue->Front], sizeof (EFI_KEY_DATA));
+ Queue->Front = (Queue->Front + 1) % QUEUE_MAX_COUNT;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Check whether the queue is empty.
+
+ @param Queue The queue to be checked.
+
+ @retval EFI_NOT_READY The queue is empty.
+ @retval EFI_SUCCESS The queue is not empty.
+
+**/
+EFI_STATUS
+CheckQueue (
+ IN SIMPLE_QUEUE *Queue
+ )
+{
+ if (Queue->Front == Queue->Rear) {
+ return EFI_NOT_READY;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// EFI Driver Binding Protocol Functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+ BOOLEAN CarryFlag;
+ EFI_PS2_POLICY_PROTOCOL *Ps2Policy;
+ UINT8 Command;
+ EFI_STATUS_CODE_VALUE StatusCode;
+
+ BiosKeyboardPrivate = NULL;
+ IsaIo = NULL;
+ StatusCode = 0;
+
+ //
+ // Get Ps2 policy to set. Will be use if present.
+ //
+ gBS->LocateProtocol (
+ &gEfiPs2PolicyProtocolGuid,
+ NULL,
+ (VOID **) &Ps2Policy
+ );
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Allocate the private device structure
+ //
+ BiosKeyboardPrivate = (BIOS_KEYBOARD_DEV *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_DEV));
+ if (NULL == BiosKeyboardPrivate) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Initialize the private device structure
+ //
+ BiosKeyboardPrivate->Signature = BIOS_KEYBOARD_DEV_SIGNATURE;
+ BiosKeyboardPrivate->Handle = Controller;
+ BiosKeyboardPrivate->LegacyBios = LegacyBios;
+ BiosKeyboardPrivate->IsaIo = IsaIo;
+
+ BiosKeyboardPrivate->SimpleTextIn.Reset = BiosKeyboardReset;
+ BiosKeyboardPrivate->SimpleTextIn.ReadKeyStroke = BiosKeyboardReadKeyStroke;
+
+ BiosKeyboardPrivate->DataRegisterAddress = KEYBOARD_8042_DATA_REGISTER;
+ BiosKeyboardPrivate->StatusRegisterAddress = KEYBOARD_8042_STATUS_REGISTER;
+ BiosKeyboardPrivate->CommandRegisterAddress = KEYBOARD_8042_COMMAND_REGISTER;
+ BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
+
+ BiosKeyboardPrivate->Queue.Front = 0;
+ BiosKeyboardPrivate->Queue.Rear = 0;
+ BiosKeyboardPrivate->SimpleTextInputEx.Reset = BiosKeyboardResetEx;
+ BiosKeyboardPrivate->SimpleTextInputEx.ReadKeyStrokeEx = BiosKeyboardReadKeyStrokeEx;
+ BiosKeyboardPrivate->SimpleTextInputEx.SetState = BiosKeyboardSetState;
+ BiosKeyboardPrivate->SimpleTextInputEx.RegisterKeyNotify = BiosKeyboardRegisterKeyNotify;
+ BiosKeyboardPrivate->SimpleTextInputEx.UnregisterKeyNotify = BiosKeyboardUnregisterKeyNotify;
+ InitializeListHead (&BiosKeyboardPrivate->NotifyList);
+
+ //
+ // Report that the keyboard is being enabled
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_ENABLE
+ );
+
+ //
+ // Setup the WaitForKey event
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ BiosKeyboardWaitForKey,
+ &(BiosKeyboardPrivate->SimpleTextIn),
+ &((BiosKeyboardPrivate->SimpleTextIn).WaitForKey)
+ );
+ if (EFI_ERROR (Status)) {
+ (BiosKeyboardPrivate->SimpleTextIn).WaitForKey = NULL;
+ goto Done;
+ }
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ BiosKeyboardWaitForKeyEx,
+ &(BiosKeyboardPrivate->SimpleTextInputEx),
+ &(BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx)
+ );
+ if (EFI_ERROR (Status)) {
+ BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx = NULL;
+ goto Done;
+ }
+
+ //
+ // Setup a periodic timer, used for reading keystrokes at a fixed interval
+ //
+ Status = gBS->CreateEvent (
+ EVT_TIMER | EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ BiosKeyboardTimerHandler,
+ BiosKeyboardPrivate,
+ &BiosKeyboardPrivate->TimerEvent
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto Done;
+ }
+
+ Status = gBS->SetTimer (
+ BiosKeyboardPrivate->TimerEvent,
+ TimerPeriodic,
+ KEYBOARD_TIMER_INTERVAL
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR;
+ goto Done;
+ }
+
+ //
+ // Report a Progress Code for an attempt to detect the precense of the keyboard device in the system
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_PRESENCE_DETECT
+ );
+
+ //
+ // Reset the keyboard device
+ //
+ Status = BiosKeyboardPrivate->SimpleTextInputEx.Reset (
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ FeaturePcdGet (PcdPs2KbdExtendedVerification)
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[KBD]Reset Failed. Status - %r\n", Status));
+ StatusCode = EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_NOT_DETECTED;
+ goto Done;
+ }
+ //
+ // Do platform specific policy like port swapping and keyboard light default
+ //
+ if (Ps2Policy != NULL) {
+
+ Ps2Policy->Ps2InitHardware (Controller);
+
+ Command = 0;
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_CAPSLOCK) == EFI_KEYBOARD_CAPSLOCK) {
+ Command |= 4;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_NUMLOCK) == EFI_KEYBOARD_NUMLOCK) {
+ Command |= 2;
+ }
+
+ if ((Ps2Policy->KeyboardLight & EFI_KEYBOARD_SCROLLLOCK) == EFI_KEYBOARD_SCROLLLOCK) {
+ Command |= 1;
+ }
+
+ KeyboardWrite (BiosKeyboardPrivate, 0xed);
+ KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
+ KeyboardWrite (BiosKeyboardPrivate, Command);
+ //
+ // Call Legacy BIOS Protocol to set whatever is necessary
+ //
+ LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
+ }
+ //
+ // Get Configuration
+ //
+ Regs.H.AH = 0xc0;
+ CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x15,
+ &Regs
+ );
+
+ if (!CarryFlag) {
+ //
+ // Check bit 6 of Feature Byte 2.
+ // If it is set, then Int 16 Func 09 is supported
+ //
+ if (*(UINT8 *)(UINTN) ((Regs.X.ES << 4) + Regs.X.BX + 0x06) & 0x40) {
+ //
+ // Get Keyboard Functionality
+ //
+ Regs.H.AH = 0x09;
+ CarryFlag = BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+
+ if (!CarryFlag) {
+ //
+ // Check bit 5 of AH.
+ // If it is set, then INT 16 Finc 10-12 are supported.
+ //
+ if ((Regs.H.AL & 0x40) != 0) {
+ //
+ // Set the flag to use INT 16 Func 10-12
+ //
+ BiosKeyboardPrivate->ExtendedKeyboard = TRUE;
+ }
+ }
+ }
+ }
+ DEBUG ((EFI_D_INFO, "[KBD]Extended keystrokes supported by CSM16 - %02x\n", (UINTN)BiosKeyboardPrivate->ExtendedKeyboard));
+ //
+ // Install protocol interfaces for the keyboard device.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ NULL
+ );
+
+Done:
+ if (StatusCode != 0) {
+ //
+ // Report an Error Code for failing to start the keyboard device
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ StatusCode
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+
+ if (BiosKeyboardPrivate != NULL) {
+ if ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey != NULL) {
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
+ }
+
+ if ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx != NULL) {
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextInputEx).WaitForKeyEx);
+ }
+ BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
+
+ if (BiosKeyboardPrivate->TimerEvent != NULL) {
+ gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
+ }
+
+ FreePool (BiosKeyboardPrivate);
+ }
+
+ if (IsaIo != NULL) {
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL *SimpleTextIn;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ //
+ // Disable Keyboard
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ (VOID **) &SimpleTextIn,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextInputExProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (SimpleTextIn);
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiSimpleTextInProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextIn,
+ &gEfiSimpleTextInputExProtocolGuid,
+ &BiosKeyboardPrivate->SimpleTextInputEx,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Release the IsaIo protocol on the controller handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiIsaIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Free other resources
+ //
+ gBS->CloseEvent ((BiosKeyboardPrivate->SimpleTextIn).WaitForKey);
+ gBS->CloseEvent (BiosKeyboardPrivate->TimerEvent);
+ gBS->CloseEvent (BiosKeyboardPrivate->SimpleTextInputEx.WaitForKeyEx);
+ BiosKeyboardFreeNotifyList (&BiosKeyboardPrivate->NotifyList);
+
+ FreePool (BiosKeyboardPrivate);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read data byte from output buffer of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+
+ @return The data byte read from output buffer of Keyboard Controller from data port which often is port 60H.
+
+**/
+UINT8
+KeyReadDataRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ UINT8 Data;
+
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Read (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->DataRegisterAddress,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Read status byte from status register of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+
+ @return The status byte read from status register of Keyboard Controller from command port which often is port 64H.
+
+**/
+UINT8
+KeyReadStatusRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ UINT8 Data;
+
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Read (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->StatusRegisterAddress,
+ 1,
+ &Data
+ );
+
+ return Data;
+}
+
+/**
+ Write command byte to control register of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+**/
+VOID
+KeyWriteCommandRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Write (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->CommandRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller without delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+**/
+VOID
+KeyWriteDataRegister (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ //
+ // Use IsaIo protocol to perform IO operations
+ //
+ BiosKeyboardPrivate->IsaIo->Io.Write (
+ BiosKeyboardPrivate->IsaIo,
+ EfiIsaIoWidthUint8,
+ BiosKeyboardPrivate->DataRegisterAddress,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Read data byte from output buffer of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data The pointer for data that being read out.
+
+ @retval EFI_SUCCESS The data byte read out successfully.
+ @retval EFI_TIMEOUT Timeout occurred during reading out data byte.
+
+**/
+EFI_STATUS
+KeyboardRead (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ OUT UINT8 *Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegFilled;
+
+ TimeOut = 0;
+ RegFilled = 0;
+
+ //
+ // wait till output buffer full then perform the read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
+ RegFilled = 1;
+ *Data = KeyReadDataRegister (BiosKeyboardPrivate);
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegFilled == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+ @retval EFI_SUCCESS The data byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWrite (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // wait for input buffer empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // Write it
+ //
+ KeyWriteDataRegister (BiosKeyboardPrivate, Data);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write command byte to control register of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Command byte to write.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardCommand (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ )
+{
+ UINT32 TimeOut;
+ UINT32 RegEmptied;
+
+ TimeOut = 0;
+ RegEmptied = 0;
+
+ //
+ // Wait For Input Buffer Empty
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+ //
+ // issue the command
+ //
+ KeyWriteCommandRegister (BiosKeyboardPrivate, Data);
+
+ //
+ // Wait For Input Buffer Empty again
+ //
+ RegEmptied = 0;
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_INPB) == 0) {
+ RegEmptied = 1;
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ if (RegEmptied == 0) {
+ return EFI_TIMEOUT;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Wait for a specific value to be presented in
+ Data register of Keyboard Controller by keyboard and then read it,
+ used in keyboard commands ack
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Value The value to be waited for
+ @param WaitForValueTimeOut The limit of microseconds for timeout
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWaitForValue (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Value,
+ IN UINTN WaitForValueTimeOut
+ )
+{
+ UINT8 Data;
+ UINT32 TimeOut;
+ UINT32 SumTimeOut;
+ UINT32 GotIt;
+
+ GotIt = 0;
+ TimeOut = 0;
+ SumTimeOut = 0;
+
+ //
+ // Make sure the initial value of 'Data' is different from 'Value'
+ //
+ Data = 0;
+ if (Data == Value) {
+ Data = 1;
+ }
+ //
+ // Read from 8042 (multiple times if needed)
+ // until the expected value appears
+ // use SumTimeOut to control the iteration
+ //
+ while (1) {
+ //
+ // Perform a read
+ //
+ for (TimeOut = 0; TimeOut < KEYBOARD_TIMEOUT; TimeOut += 30) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_OUTB) != 0) {
+ Data = KeyReadDataRegister (BiosKeyboardPrivate);
+ break;
+ }
+
+ gBS->Stall (30);
+ }
+
+ SumTimeOut += TimeOut;
+
+ if (Data == Value) {
+ GotIt = 1;
+ break;
+ }
+
+ if (SumTimeOut >= WaitForValueTimeOut) {
+ break;
+ }
+ }
+ //
+ // Check results
+ //
+ if (GotIt != 0) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_TIMEOUT;
+ }
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param BiosKeyboardPrivate Bioskeyboard driver private structure.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+KeyboardReadKeyStrokeWorker (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Use TimerEvent callback funciton to check whether there's any key pressed
+ //
+
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+ // Csm will be used to check whether there is a key pending, but the csm will disable all
+ // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+ // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+ // e.g. OS loader, other drivers which are driven by timer event will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+ // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+ //
+ gBS->Stall (1000);
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ BiosKeyboardTimerHandler (NULL, BiosKeyboardPrivate);
+ //
+ // If there's no key, just return
+ //
+ Status = CheckQueue (&BiosKeyboardPrivate->Queue);
+ if (EFI_ERROR (Status)) {
+ gBS->RestoreTPL (OldTpl);
+ return EFI_NOT_READY;
+ }
+
+ Status = Dequeue (&BiosKeyboardPrivate->Queue, KeyData);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+}
+
+//
+// EFI Simple Text In Protocol Functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ UINT8 CommandByte;
+ BOOLEAN MouseEnable;
+ EFI_INPUT_KEY Key;
+
+ MouseEnable = FALSE;
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // 1
+ // Report reset progress code
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_PC_RESET
+ );
+
+ //
+ // Report a Progress Code for clearing the keyboard buffer
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_CLEAR_BUFFER
+ );
+
+ //
+ // 2
+ // Raise TPL to avoid mouse operation impact
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ //
+ // Exhaust output buffer data
+ //
+ do {
+ Status = BiosKeyboardReadKeyStroke (
+ This,
+ &Key
+ );
+ } while (!EFI_ERROR (Status));
+ //
+ // 3
+ // check for KBC itself firstly for setted-up already or not by reading SYSF (bit2) of status register via 64H
+ // if not skip step 4&5 and jump to step 6 to selftest KBC and report this
+ // else go step 4
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & KBC_STSREG_VIA64_SYSF) != 0) {
+ //
+ // 4
+ // CheckMouseStatus to decide enable it later or not
+ //
+ //
+ // Read the command byte of KBC
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_CMDBYTE_R
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardRead (
+ BiosKeyboardPrivate,
+ &CommandByte
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Check mouse enabled or not before
+ //
+ if ((CommandByte & KB_CMMBYTE_DISABLE_AUX) != 0) {
+ MouseEnable = FALSE;
+ } else {
+ MouseEnable = TRUE;
+ }
+ //
+ // 5
+ // disable mouse (via KBC) and Keyborad device
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_AUX_DISABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_DISABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ } else {
+ //
+ // 6
+ // KBC Self Test
+ //
+ //
+ // Report a Progress Code for performing a self test on the keyboard controller
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_KEYBOARD_PC_SELF_TEST
+ );
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KBC_SLFTEST
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_KBCSLFTEST_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ }
+ //
+ // 7
+ // Disable Mouse interface, enable Keyboard interface and declare selftest success
+ //
+ // Mouse device will block keyboard interface before it be configured, so we should disable mouse first.
+ //
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_CMDBYTE_W
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ //
+ // Write 8042 Command Byte, set System Flag
+ // While at the same time:
+ // 1. disable mouse interface,
+ // 2. enable kbd interface,
+ // 3. enable PC/XT kbd translation mode
+ // 4. enable mouse and kbd interrupts
+ //
+ //Command Byte bits:
+ // 7: Reserved
+ // 6: PC/XT translation mode
+ // 5: Disable Auxiliary device interface
+ // 4: Disable keyboard interface
+ // 3: Reserved
+ // 2: System Flag
+ // 1: Enable Auxiliary device interrupt
+ // 0: Enable Keyboard interrupt
+ //
+ CommandByte = 0;
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ (UINT8) ((CommandByte &
+ (~KB_CMMBYTE_DISABLE_KB)) |
+ KB_CMMBYTE_KSCAN2UNI_COV |
+ KB_CMMBYTE_ENABLE_AUXINT |
+ KB_CMMBYTE_ENABLE_KBINT |
+ KB_CMMBYTE_SLFTEST_SUCC |
+ KB_CMMBYTE_DISABLE_AUX)
+ );
+
+ //
+ // For reseting keyboard is not mandatory before booting OS and sometimes keyboard responses very slow,
+ // so we only do the real reseting for keyboard when user asks, and normally during booting an OS, it's skipped.
+ // Call CheckKeyboardConnect() to check whether keyboard is connected, if it is not connected,
+ // Real reset will not do.
+ //
+ if (ExtendedVerification && CheckKeyboardConnect (BiosKeyboardPrivate)) {
+ //
+ // 8
+ // Send keyboard reset command then read ACK
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBRESET
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 9
+ // Wait for keyboard return test OK.
+ //
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_BATTEST_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 10
+ // set keyboard scan code set = 02 (standard configuration)
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBSCODE
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_SCODESET2
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 11
+ // enable keyboard itself (not via KBC) by writing CMD F4 via 60H
+ //
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBEN
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // 12
+ // Additional validation, do it as follow:
+ // 1). check for status register of PARE && TIM via 64H
+ // 2). perform KB checking by writing ABh via 64H
+ //
+ if ((KeyReadStatusRegister (BiosKeyboardPrivate) & (KBC_STSREG_VIA64_PARE | KBC_STSREG_VIA64_TIM)) != 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_CKECK
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_KBCHECK_OK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+ //
+ // 13
+ // Done for validating keyboard. Enable keyboard (via KBC)
+ // and recover the command byte to proper value
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_KB_ENABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ }
+
+ //
+ // 14
+ // conditionally enable mouse (via KBC)
+ //
+ if (MouseEnable) {
+ Status = KeyboardCommand (
+ BiosKeyboardPrivate,
+ KBC_CMDREG_VIA64_AUX_ENABLE
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+
+ }
+ }
+
+Exit:
+ //
+ // 15
+ // resume priority of task level
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_KEY_DATA KeyData;
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, &KeyData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert the Ctrl+[a-z] to Ctrl+[1-26]
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'a' + 1);
+ } else if (KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') {
+ KeyData.Key.UnicodeChar = (CHAR16) (KeyData.Key.UnicodeChar - L'A' + 1);
+ }
+ }
+
+ CopyMem (Key, &KeyData.Key, sizeof (EFI_INPUT_KEY));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Stall 1ms to give a chance to let other driver interrupt this routine for their timer event.
+ // Csm will be used to check whether there is a key pending, but the csm will disable all
+ // interrupt before switch to compatibility16, which mean all the efiCompatibility timer
+ // event will stop work during the compatibility16. And If a caller recursivly invoke this function,
+ // e.g. UI setup or Shell, other drivers which are driven by timer event will have a bad performance during this period,
+ // e.g. usb keyboard driver.
+ // Add a stall period can greatly increate other driver performance during the WaitForKey is recursivly invoked.
+ // 1ms delay will make little impact to the thunk keyboard driver, and user can not feel the delay at all when input.
+ //
+ gBS->Stall (1000);
+ //
+ // Use TimerEvent callback funciton to check whether there's any key pressed
+ //
+ BiosKeyboardTimerHandler (NULL, BIOS_KEYBOARD_DEV_FROM_THIS (Context));
+
+ if (!EFI_ERROR (BiosKeyboardCheckForKey (Context))) {
+ gBS->SignalEvent (Event);
+ }
+}
+
+/**
+ Check key buffer to get the key stroke status.
+
+ @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+ @retval EFI_SUCCESS A key is being pressed now.
+ @retval Other No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ BiosKeyboardPrivate = BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ return CheckQueue (&BiosKeyboardPrivate->Queue);
+}
+//
+// Private worker functions
+//
+#define TABLE_END 0x0
+
+typedef struct _CONVERT_TABLE_ENTRY {
+ UINT16 ScanCode;
+ UINT16 EfiScanCode;
+} CONVERT_TABLE_ENTRY;
+
+CONVERT_TABLE_ENTRY mConvertTable[] = {
+ {
+ 0x47,
+ SCAN_HOME
+ },
+ {
+ 0x48,
+ SCAN_UP
+ },
+ {
+ 0x49,
+ SCAN_PAGE_UP
+ },
+ {
+ 0x4b,
+ SCAN_LEFT
+ },
+ {
+ 0x4d,
+ SCAN_RIGHT
+ },
+ {
+ 0x4f,
+ SCAN_END
+ },
+ {
+ 0x50,
+ SCAN_DOWN
+ },
+ {
+ 0x51,
+ SCAN_PAGE_DOWN
+ },
+ {
+ 0x52,
+ SCAN_INSERT
+ },
+ {
+ 0x53,
+ SCAN_DELETE
+ },
+ //
+ // Function Keys are only valid if KeyChar == 0x00
+ // This function does not require KeyChar to be 0x00
+ //
+ {
+ 0x3b,
+ SCAN_F1
+ },
+ {
+ 0x3c,
+ SCAN_F2
+ },
+ {
+ 0x3d,
+ SCAN_F3
+ },
+ {
+ 0x3e,
+ SCAN_F4
+ },
+ {
+ 0x3f,
+ SCAN_F5
+ },
+ {
+ 0x40,
+ SCAN_F6
+ },
+ {
+ 0x41,
+ SCAN_F7
+ },
+ {
+ 0x42,
+ SCAN_F8
+ },
+ {
+ 0x43,
+ SCAN_F9
+ },
+ {
+ 0x44,
+ SCAN_F10
+ },
+ {
+ 0x85,
+ SCAN_F11
+ },
+ {
+ 0x86,
+ SCAN_F12
+ },
+ //
+ // Convert ALT + Fn keys
+ //
+ {
+ 0x68,
+ SCAN_F1
+ },
+ {
+ 0x69,
+ SCAN_F2
+ },
+ {
+ 0x6a,
+ SCAN_F3
+ },
+ {
+ 0x6b,
+ SCAN_F4
+ },
+ {
+ 0x6c,
+ SCAN_F5
+ },
+ {
+ 0x6d,
+ SCAN_F6
+ },
+ {
+ 0x6e,
+ SCAN_F7
+ },
+ {
+ 0x6f,
+ SCAN_F8
+ },
+ {
+ 0x70,
+ SCAN_F9
+ },
+ {
+ 0x71,
+ SCAN_F10
+ },
+ {
+ TABLE_END,
+ SCAN_NULL
+ },
+};
+
+/**
+ Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
+
+ @param KeyChar Unicode of key.
+ @param ScanCode Scan code of key.
+
+ @return The value of EFI Scancode for the key.
+ @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
+
+**/
+UINT16
+ConvertToEFIScanCode (
+ IN CHAR16 KeyChar,
+ IN UINT16 ScanCode
+ )
+{
+ UINT16 EfiScanCode;
+ UINT16 Index;
+
+ if (KeyChar == CHAR_ESC) {
+ EfiScanCode = SCAN_ESC;
+ } else if (KeyChar == 0x00 || KeyChar == 0xe0) {
+ //
+ // Movement & Function Keys
+ //
+ for (Index = 0; (Index < sizeof (mConvertTable) / sizeof (CONVERT_TABLE_ENTRY)) && (mConvertTable[Index].ScanCode != TABLE_END); Index += 1) {
+ if (ScanCode == mConvertTable[Index].ScanCode) {
+ return mConvertTable[Index].EfiScanCode;
+ }
+ }
+ //
+ // Reach Table end, return default value
+ //
+ return SCAN_NULL;
+ } else {
+ return SCAN_NULL;
+ }
+
+ return EfiScanCode;
+}
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param BiosKeyboardPrivate Keyboard Private Data Struture
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+
+**/
+BOOLEAN
+CheckKeyboardConnect (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ )
+{
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ //
+ // enable keyboard itself and wait for its ack
+ // If can't receive ack, Keyboard should not be connected.
+ //
+ if (!PcdGetBool (PcdFastPS2Detection)) {
+ Status = KeyboardWrite (
+ BiosKeyboardPrivate,
+ KBC_INPBUF_VIA60_KBEN
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Keyboard enable failed!\n"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
+ );
+ return FALSE;
+ }
+
+ Status = KeyboardWaitForValue (
+ BiosKeyboardPrivate,
+ KBC_CMDECHO_ACK,
+ KEYBOARD_WAITFORVALUE_TIMEOUT
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[KBD]CheckKeyboardConnect - Timeout!\n"));
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_KEYBOARD | EFI_P_EC_CONTROLLER_ERROR
+ );
+ return FALSE;
+ }
+ return TRUE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Timer event handler: read a series of key stroke from 8042
+ and put them into memory key buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A BIOS_KEYBOARD_DEV pointer
+
+**/
+VOID
+EFIAPI
+BiosKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_TPL OldTpl;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT8 KbFlag1; // 0040h:0017h - KEYBOARD - STATUS FLAGS 1
+ UINT8 KbFlag2; // 0040h:0018h - KEYBOARD - STATUS FLAGS 2
+ EFI_KEY_DATA KeyData;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ BiosKeyboardPrivate = Context;
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // if there is no key present, just return
+ //
+ if (BiosKeyboardPrivate->ExtendedKeyboard) {
+ Regs.H.AH = 0x11;
+ } else {
+ Regs.H.AH = 0x01;
+ }
+
+ BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+ if (Regs.X.Flags.ZF != 0) {
+ gBS->RestoreTPL (OldTpl);
+ return;
+ }
+
+ //
+ // Read the key
+ //
+ if (BiosKeyboardPrivate->ExtendedKeyboard) {
+ Regs.H.AH = 0x10;
+ } else {
+ Regs.H.AH = 0x00;
+ }
+
+ BiosKeyboardPrivate->LegacyBios->Int86 (
+ BiosKeyboardPrivate->LegacyBios,
+ 0x16,
+ &Regs
+ );
+
+ KeyData.Key.ScanCode = (UINT16) Regs.H.AH;
+ KeyData.Key.UnicodeChar = (UINT16) Regs.H.AL;
+ DEBUG ((
+ EFI_D_INFO,
+ "[KBD]INT16 returns EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
+ KeyData.Key.ScanCode,
+ KeyData.Key.UnicodeChar
+ ));
+
+ KeyData.KeyState.KeyShiftState = EFI_SHIFT_STATE_VALID;
+ KeyData.KeyState.KeyToggleState = EFI_TOGGLE_STATE_VALID;
+ //
+ // Leagcy Bios use Int 9 which is IRQ1 interrupt handler to get keystroke scancode to KB buffer in BDA (BIOS DATE AREA), then
+ // Int 16 depend KB buffer and some key bits in BDA to translate the scancode to ASCII code, and return both the scancode and ASCII
+ // code to Int 16 caller. This translation process works well if the Int 9 could response user input in time. But in Tiano enviorment, the Int 9
+ // will be disabled after the thunk call finish, which means if user crazy input during int 9 being disabled, some keystrokes will be lost when
+ // KB device own hardware buffer overflows. And if the lost keystroke code is CTRL or ALT or SHIFT release code, these function key flags bit
+ // in BDA will not be updated. So the Int 16 will believe the CTRL or ALT or SHIFT is still pressed, and Int 16 will translate later scancode
+ // to wrong ASCII code. We can increase the Thunk frequence to let Int 9 response in time, but this way will much hurt other dirvers
+ // performance, like USB.
+ //
+ // 1. If CTRL or ALT release code is missed, all later input keys will be translated to wrong ASCII codes which the Tiano cannot support. In
+ // this case, the KB input seems fail to work, and user input is blocked. To solve the problem, we can help to clear the CTRL or ALT flag in BDA
+ // after every Int 16 finish. Thus persist to press CTRL or ALT has same effection as only press one time. It is Ok, since user not often use the
+ // CTRL and ALT.
+ //
+ // 2. If SHIFT release code is missed, all later lowercase input will become capital. This is ugly, but not block user input. If user press the lost
+ // SHIFT again, the lowercase will come back to normal. Since user often use the SHIFT, it is not reasonable to help to clear the SHIFT flag in BDA,
+ // which will let persist to press SHIFT has same effection as only press one time.
+ //
+ //0040h:0017h - KEYBOARD - STATUS FLAGS 1
+ // 7 INSert active
+ // 6 Caps Lock active
+ // 5 Num Lock active
+ // 4 Scroll Lock active
+ // 3 either Alt pressed
+ // 2 either Ctrl pressed
+ // 1 Left Shift pressed
+ // 0 Right Shift pressed
+
+
+ //
+ // Clear the CTRL and ALT BDA flag
+ //
+ KbFlag1 = *((UINT8 *) (UINTN) 0x417); // read the STATUS FLAGS 1
+ KbFlag2 = *((UINT8 *) (UINTN) 0x418); // read STATUS FLAGS 2
+
+ DEBUG_CODE (
+ {
+ if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
+ DEBUG ((EFI_D_INFO, "[KBD]Caps Lock Key is pressed.\n"));
+ }
+ if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
+ DEBUG ((EFI_D_INFO, "[KBD]Num Lock Key is pressed.\n"));
+ }
+ if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
+ DEBUG ((EFI_D_INFO, "[KBD]Scroll Lock Key is pressed.\n"));
+ }
+ if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
+ if ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) {
+ DEBUG ((EFI_D_INFO, "[KBD]Left Alt Key is pressed.\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "[KBD]Right Alt Key is pressed.\n"));
+ }
+ }
+ if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
+ if ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) {
+ DEBUG ((EFI_D_INFO, "[KBD]Left Ctrl Key is pressed.\n"));
+ } else {
+ DEBUG ((EFI_D_INFO, "[KBD]Right Ctrl Key is pressed.\n"));
+ }
+ }
+ if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
+ DEBUG ((EFI_D_INFO, "[KBD]Left Shift Key is pressed.\n"));
+ }
+ if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
+ DEBUG ((EFI_D_INFO, "[KBD]Right Shift Key is pressed.\n"));
+ }
+ }
+ );
+
+ //
+ // Record toggle state
+ //
+ if ((KbFlag1 & KB_CAPS_LOCK_BIT) == KB_CAPS_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_CAPS_LOCK_ACTIVE;
+ }
+ if ((KbFlag1 & KB_NUM_LOCK_BIT) == KB_NUM_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_NUM_LOCK_ACTIVE;
+ }
+ if ((KbFlag1 & KB_SCROLL_LOCK_BIT) == KB_SCROLL_LOCK_BIT) {
+ KeyData.KeyState.KeyToggleState |= EFI_SCROLL_LOCK_ACTIVE;
+ }
+ //
+ // Record shift state
+ // BUGBUG: Need add Menu key and Left/Right Logo key state in the future
+ //
+ if ((KbFlag1 & KB_ALT_PRESSED) == KB_ALT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_ALT_PRESSED) == KB_LEFT_ALT_PRESSED) ? EFI_LEFT_ALT_PRESSED : EFI_RIGHT_ALT_PRESSED;
+ }
+ if ((KbFlag1 & KB_CTRL_PRESSED) == KB_CTRL_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= ((KbFlag2 & KB_LEFT_CTRL_PRESSED) == KB_LEFT_CTRL_PRESSED) ? EFI_LEFT_CONTROL_PRESSED : EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if ((KbFlag1 & KB_LEFT_SHIFT_PRESSED) == KB_LEFT_SHIFT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= EFI_LEFT_SHIFT_PRESSED;
+ }
+ if ((KbFlag1 & KB_RIGHT_SHIFT_PRESSED) == KB_RIGHT_SHIFT_PRESSED) {
+ KeyData.KeyState.KeyShiftState |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+
+ //
+ // Clear left alt and left ctrl BDA flag
+ //
+ KbFlag2 &= ~(KB_LEFT_ALT_PRESSED | KB_LEFT_CTRL_PRESSED);
+ *((UINT8 *) (UINTN) 0x418) = KbFlag2;
+ KbFlag1 &= ~0x0C;
+ *((UINT8 *) (UINTN) 0x417) = KbFlag1;
+
+
+ //
+ // Output EFI input key and shift/toggle state
+ //
+ if (KeyData.Key.UnicodeChar == CHAR_NULL || KeyData.Key.UnicodeChar == CHAR_SCANCODE || KeyData.Key.UnicodeChar == CHAR_ESC) {
+ KeyData.Key.ScanCode = ConvertToEFIScanCode (KeyData.Key.UnicodeChar, KeyData.Key.ScanCode);
+ KeyData.Key.UnicodeChar = CHAR_NULL;
+ } else {
+ KeyData.Key.ScanCode = SCAN_NULL;
+ }
+
+ //
+ // CSM16 has converted the Ctrl+[a-z] to [1-26], converted it back.
+ //
+ if ((KeyData.KeyState.KeyShiftState & (EFI_LEFT_CONTROL_PRESSED | EFI_RIGHT_CONTROL_PRESSED)) != 0) {
+ if (KeyData.Key.UnicodeChar >= 1 && KeyData.Key.UnicodeChar <= 26) {
+ if (((KeyData.KeyState.KeyShiftState & (EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED)) != 0) ==
+ ((KeyData.KeyState.KeyToggleState & EFI_CAPS_LOCK_ACTIVE) != 0)
+ ) {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'a' - 1);
+ } else {
+ KeyData.Key.UnicodeChar = (UINT16) (KeyData.Key.UnicodeChar + L'A' - 1);
+ }
+ }
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ "[KBD]Convert to EFI Scan Code, EFI_INPUT_KEY.ScanCode - %x, EFI_INPUT_KEY.UnicodeChar - %x\n",
+ KeyData.Key.ScanCode,
+ KeyData.Key.UnicodeChar
+ ));
+
+ //
+ // Need not return associated shift state if a class of printable characters that
+ // are normally adjusted by shift modifiers.
+ // e.g. Shift Key + 'f' key = 'F'; Shift Key + 'F' key = 'f'.
+ //
+ if ((KeyData.Key.UnicodeChar >= L'A' && KeyData.Key.UnicodeChar <= L'Z') ||
+ (KeyData.Key.UnicodeChar >= L'a' && KeyData.Key.UnicodeChar <= L'z')
+ ) {
+ DEBUG ((EFI_D_INFO, "[KBD]Shift key with a~z are pressed, remove shift state in EFI_KEY_STATE.\n"));
+ KeyData.KeyState.KeyShiftState &= ~(EFI_LEFT_SHIFT_PRESSED | EFI_RIGHT_SHIFT_PRESSED);
+ }
+
+ //
+ // Invoke notification functions if exist
+ //
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, &KeyData)) {
+ CurrentNotify->KeyNotificationFn (&KeyData);
+ }
+ }
+
+ Enqueue (&BiosKeyboardPrivate->Queue, &KeyData);
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return ;
+}
+
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+BiosKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ )
+{
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NotifyNode;
+
+ if (ListHead == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ while (!IsListEmpty (ListHead)) {
+ NotifyNode = CR (
+ ListHead->ForwardLink,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ RemoveEntryList (ListHead->ForwardLink);
+ gBS->FreePool (NotifyNode);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if key is registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ )
+{
+ ASSERT (RegsiteredData != NULL && InputData != NULL);
+
+ if ((RegsiteredData->Key.ScanCode != InputData->Key.ScanCode) ||
+ (RegsiteredData->Key.UnicodeChar != InputData->Key.UnicodeChar)) {
+ return FALSE;
+ }
+
+ //
+ // Assume KeyShiftState/KeyToggleState = 0 in Registered key data means these state could be ignored.
+ //
+ if (RegsiteredData->KeyState.KeyShiftState != 0 &&
+ RegsiteredData->KeyState.KeyShiftState != InputData->KeyState.KeyShiftState) {
+ return FALSE;
+ }
+ if (RegsiteredData->KeyState.KeyToggleState != 0 &&
+ RegsiteredData->KeyState.KeyToggleState != InputData->KeyState.KeyToggleState) {
+ return FALSE;
+ }
+
+ return TRUE;
+
+}
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (Context);
+ BiosKeyboardWaitForKey (Event, &BiosKeyboardPrivate->SimpleTextIn);
+
+}
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ Status = BiosKeyboardPrivate->SimpleTextIn.Reset (
+ &BiosKeyboardPrivate->SimpleTextIn,
+ ExtendedVerification
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ gBS->RestoreTPL (OldTpl);
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ )
+{
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+
+ if (KeyData == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ return KeyboardReadKeyStrokeWorker (BiosKeyboardPrivate, KeyData);
+
+}
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT8 Command;
+
+ if (KeyToggleState == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Thunk keyboard driver doesn't support partial keystroke.
+ //
+ if ((*KeyToggleState & EFI_TOGGLE_STATE_VALID) != EFI_TOGGLE_STATE_VALID ||
+ (*KeyToggleState & EFI_KEY_STATE_EXPOSED) == EFI_KEY_STATE_EXPOSED
+ ) {
+ return EFI_UNSUPPORTED;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ Command = 0;
+ if ((*KeyToggleState & EFI_CAPS_LOCK_ACTIVE) == EFI_CAPS_LOCK_ACTIVE) {
+ Command |= 4;
+ }
+ if ((*KeyToggleState & EFI_NUM_LOCK_ACTIVE) == EFI_NUM_LOCK_ACTIVE) {
+ Command |= 2;
+ }
+ if ((*KeyToggleState & EFI_SCROLL_LOCK_ACTIVE) == EFI_SCROLL_LOCK_ACTIVE) {
+ Command |= 1;
+ }
+
+ Status = KeyboardWrite (BiosKeyboardPrivate, 0xed);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ Status = KeyboardWaitForValue (BiosKeyboardPrivate, 0xfa, KEYBOARD_WAITFORVALUE_TIMEOUT);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ Status = KeyboardWrite (BiosKeyboardPrivate, Command);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ goto Exit;
+ }
+ //
+ // Call Legacy BIOS Protocol to set whatever is necessary
+ //
+ LegacyBios->UpdateKeyboardLedStatus (LegacyBios, Command);
+
+ Status = EFI_SUCCESS;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+
+ return Status;
+
+}
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *NewNotify;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ if (KeyData == NULL || NotifyHandle == NULL || KeyNotificationFunction == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Return EFI_SUCCESS if the (KeyData, NotificationFunction) is already registered.
+ //
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (IsKeyRegistered (&CurrentNotify->KeyData, KeyData)) {
+ if (CurrentNotify->KeyNotificationFn == KeyNotificationFunction) {
+ *NotifyHandle = CurrentNotify;
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+ }
+
+ //
+ // Allocate resource to save the notification function
+ //
+
+ NewNotify = (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) AllocateZeroPool (sizeof (BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY));
+ if (NewNotify == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ NewNotify->Signature = BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE;
+ NewNotify->KeyNotificationFn = KeyNotificationFunction;
+ CopyMem (&NewNotify->KeyData, KeyData, sizeof (EFI_KEY_DATA));
+ InsertTailList (&BiosKeyboardPrivate->NotifyList, &NewNotify->NotifyEntry);
+
+ *NotifyHandle = NewNotify;
+ Status = EFI_SUCCESS;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ )
+{
+ EFI_STATUS Status;
+ BIOS_KEYBOARD_DEV *BiosKeyboardPrivate;
+ EFI_TPL OldTpl;
+ LIST_ENTRY *Link;
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *CurrentNotify;
+
+ //
+ // Check incoming notification handle
+ //
+ if (NotificationHandle == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY *) NotificationHandle)->Signature != BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosKeyboardPrivate = TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS (This);
+
+ //
+ // Enter critical section
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ for (Link = BiosKeyboardPrivate->NotifyList.ForwardLink; Link != &BiosKeyboardPrivate->NotifyList; Link = Link->ForwardLink) {
+ CurrentNotify = CR (
+ Link,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY,
+ NotifyEntry,
+ BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE
+ );
+ if (CurrentNotify == NotificationHandle) {
+ //
+ // Remove the notification function from NotifyList and free resources
+ //
+ RemoveEntryList (&CurrentNotify->NotifyEntry);
+
+ Status = EFI_SUCCESS;
+ goto Exit;
+ }
+ }
+
+ //
+ // Can not find the specified Notification Handle
+ //
+ Status = EFI_INVALID_PARAMETER;
+
+Exit:
+ //
+ // Leave critical section and return
+ //
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ The user Entry Point for module BiosKeyboard. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeBiosKeyboard(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosKeyboardDriverBinding,
+ ImageHandle,
+ &gBiosKeyboardComponentName,
+ &gBiosKeyboardComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h
new file mode 100644
index 0000000000..a27d2e1b23
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/BiosKeyboard.h
@@ -0,0 +1,743 @@
+/** @file
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BIOS_KEYBOARD_H_
+#define _BIOS_KEYBOARD_H_
+
+
+#include <FrameworkDxe.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Ps2Policy.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Driver Binding Externs
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2;
+
+
+#include <IndustryStandard/Pci.h>
+
+//
+// BISO Keyboard Defines
+//
+#define CHAR_SCANCODE 0xe0
+#define CHAR_ESC 0x1b
+
+#define KEYBOARD_8042_DATA_REGISTER 0x60
+#define KEYBOARD_8042_STATUS_REGISTER 0x64
+#define KEYBOARD_8042_COMMAND_REGISTER 0x64
+
+#define KEYBOARD_TIMEOUT 65536 // 0.07s
+#define KEYBOARD_WAITFORVALUE_TIMEOUT 1000000 // 1s
+#define KEYBOARD_BAT_TIMEOUT 4000000 // 4s
+#define KEYBOARD_TIMER_INTERVAL 200000 // 0.02s
+// KEYBOARD COMMAND BYTE -- read by writing command KBC_CMDREG_VIA64_CMDBYTE_R to 64H, then read from 60H
+// write by wrting command KBC_CMDREG_VIA64_CMDBYTE_W to 64H, then write to 60H
+// 7: Reserved
+// 6: PC/XT translation mode convert
+// 5: Disable Auxiliary device interface
+// 4: Disable keyboard interface
+// 3: Reserved
+// 2: System Flag: selftest successful
+// 1: Enable Auxiliary device interrupt
+// 0: Enable Keyboard interrupt )
+//
+#define KB_CMMBYTE_KSCAN2UNI_COV (0x1 << 6)
+#define KB_CMMBYTE_DISABLE_AUX (0x1 << 5)
+#define KB_CMMBYTE_DISABLE_KB (0x1 << 4)
+#define KB_CMMBYTE_SLFTEST_SUCC (0x1 << 2)
+#define KB_CMMBYTE_ENABLE_AUXINT (0x1 << 1)
+#define KB_CMMBYTE_ENABLE_KBINT (0x1 << 0)
+
+//
+// KEYBOARD CONTROLLER STATUS REGISTER - read from 64h
+// 7: Parity error
+// 6: General time out
+// 5: Output buffer holds data for AUX
+// 4: Keyboard is not locked
+// 3: Command written via 64h / Data written via 60h
+// 2: KBC self-test successful / Power-on reset
+// 1: Input buffer holds CPU data / empty
+// 0: Output buffer holds keyboard data / empty
+//
+#define KBC_STSREG_VIA64_PARE (0x1 << 7)
+#define KBC_STSREG_VIA64_TIM (0x1 << 6)
+#define KBC_STSREG_VIA64_AUXB (0x1 << 5)
+#define KBC_STSREG_VIA64_KEYL (0x1 << 4)
+#define KBC_STSREG_VIA64_C_D (0x1 << 3)
+#define KBC_STSREG_VIA64_SYSF (0x1 << 2)
+#define KBC_STSREG_VIA64_INPB (0x1 << 1)
+#define KBC_STSREG_VIA64_OUTB (0x1 << 0)
+
+//
+// COMMANDs of KEYBOARD CONTROLLER COMMAND REGISTER - write to 64h
+//
+#define KBC_CMDREG_VIA64_CMDBYTE_R 0x20
+#define KBC_CMDREG_VIA64_CMDBYTE_W 0x60
+#define KBC_CMDREG_VIA64_AUX_DISABLE 0xA7
+#define KBC_CMDREG_VIA64_AUX_ENABLE 0xA8
+#define KBC_CMDREG_VIA64_KBC_SLFTEST 0xAA
+#define KBC_CMDREG_VIA64_KB_CKECK 0xAB
+#define KBC_CMDREG_VIA64_KB_DISABLE 0xAD
+#define KBC_CMDREG_VIA64_KB_ENABLE 0xAE
+#define KBC_CMDREG_VIA64_INTP_LOW_R 0xC0
+#define KBC_CMDREG_VIA64_INTP_HIGH_R 0xC2
+#define KBC_CMDREG_VIA64_OUTP_R 0xD0
+#define KBC_CMDREG_VIA64_OUTP_W 0xD1
+#define KBC_CMDREG_VIA64_OUTB_KB_W 0xD2
+#define KBC_CMDREG_VIA64_OUTB_AUX_W 0xD3
+#define KBC_CMDREG_VIA64_AUX_W 0xD4
+
+//
+// echos of KEYBOARD CONTROLLER COMMAND - read from 60h
+//
+#define KBC_CMDECHO_KBCSLFTEST_OK 0x55
+#define KBC_CMDECHO_KBCHECK_OK 0x00
+#define KBC_CMDECHO_ACK 0xFA
+#define KBC_CMDECHO_BATTEST_OK 0xAA
+#define KBC_CMDECHO_BATTEST_FAILE 0xFC
+
+//
+// OUTPUT PORT COMMANDs - write port by writing KBC_CMDREG_VIA64_OUTP_W via 64H, then write the command to 60H
+// drive data and clock of KB to high for at least 500us for BAT needs
+//
+#define KBC_OUTPORT_DCHIGH_BAT 0xC0
+//
+// scan code set type
+//
+#define KBC_INPBUF_VIA60_SCODESET1 0x01
+#define KBC_INPBUF_VIA60_SCODESET2 0x02
+#define KBC_INPBUF_VIA60_SCODESET3 0x03
+
+//
+// COMMANDs written to INPUT BUFFER - write to 60h
+//
+#define KBC_INPBUF_VIA60_KBECHO 0xEE
+#define KBC_INPBUF_VIA60_KBSCODE 0xF0
+#define KBC_INPBUF_VIA60_KBTYPE 0xF2
+#define KBC_INPBUF_VIA60_KBDELAY 0xF3
+#define KBC_INPBUF_VIA60_KBEN 0xF4
+#define KBC_INPBUF_VIA60_KBSTDDIS 0xF5
+#define KBC_INPBUF_VIA60_KBSTDEN 0xF6
+#define KBC_INPBUF_VIA60_KBRESEND 0xFE
+#define KBC_INPBUF_VIA60_KBRESET 0xFF
+
+//
+// 0040h:0017h - KEYBOARD - STATUS FLAGS 1
+// 7 INSert active
+// 6 Caps Lock active
+// 5 Num Lock active
+// 4 Scroll Lock active
+// 3 either Alt pressed
+// 2 either Ctrl pressed
+// 1 Left Shift pressed
+// 0 Right Shift pressed
+//
+// 0040h:0018h - KEYBOARD - STATUS FLAGS 2
+// 7: insert key is depressed
+// 6: caps-lock key is depressed (does not work well)
+// 5: num-lock key is depressed (does not work well)
+// 4: scroll lock key is depressed (does not work well)
+// 3: suspend key has been toggled (does not work well)
+// 2: system key is pressed and held (does not work well)
+// 1: left ALT key is pressed
+// 0: left CTRL key is pressed
+//
+#define KB_INSERT_BIT (0x1 << 7)
+#define KB_CAPS_LOCK_BIT (0x1 << 6)
+#define KB_NUM_LOCK_BIT (0x1 << 5)
+#define KB_SCROLL_LOCK_BIT (0x1 << 4)
+#define KB_ALT_PRESSED (0x1 << 3)
+#define KB_CTRL_PRESSED (0x1 << 2)
+#define KB_LEFT_SHIFT_PRESSED (0x1 << 1)
+#define KB_RIGHT_SHIFT_PRESSED (0x1 << 0)
+
+#define KB_SUSPEND_PRESSED (0x1 << 3)
+#define KB_SYSREQ_PRESSED (0x1 << 2)
+#define KB_LEFT_ALT_PRESSED (0x1 << 1)
+#define KB_LEFT_CTRL_PRESSED (0x1 << 0)
+
+//
+// BIOS Keyboard Device Structure
+//
+#define BIOS_KEYBOARD_DEV_SIGNATURE SIGNATURE_32 ('B', 'K', 'B', 'D')
+#define BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY_SIGNATURE SIGNATURE_32 ('c', 'b', 'k', 'h')
+
+typedef struct _BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY {
+ UINTN Signature;
+ EFI_KEY_DATA KeyData;
+ EFI_KEY_NOTIFY_FUNCTION KeyNotificationFn;
+ LIST_ENTRY NotifyEntry;
+} BIOS_KEYBOARD_CONSOLE_IN_EX_NOTIFY;
+
+#define QUEUE_MAX_COUNT 32
+typedef struct {
+ UINTN Front;
+ UINTN Rear;
+ EFI_KEY_DATA Buffer[QUEUE_MAX_COUNT];
+} SIMPLE_QUEUE;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_SIMPLE_TEXT_INPUT_PROTOCOL SimpleTextIn;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL SimpleTextInputEx;
+ UINT16 DataRegisterAddress;
+ UINT16 StatusRegisterAddress;
+ UINT16 CommandRegisterAddress;
+ BOOLEAN ExtendedKeyboard;
+
+ //
+ // Buffer storing EFI_KEY_DATA
+ //
+ SIMPLE_QUEUE Queue;
+
+ //
+ // Notification Function List
+ //
+ LIST_ENTRY NotifyList;
+ EFI_EVENT TimerEvent;
+
+} BIOS_KEYBOARD_DEV;
+
+#define BIOS_KEYBOARD_DEV_FROM_THIS(a) CR (a, BIOS_KEYBOARD_DEV, SimpleTextIn, BIOS_KEYBOARD_DEV_SIGNATURE)
+#define TEXT_INPUT_EX_BIOS_KEYBOARD_DEV_FROM_THIS(a) \
+ CR (a, \
+ BIOS_KEYBOARD_DEV, \
+ SimpleTextInputEx, \
+ BIOS_KEYBOARD_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosKeyboardDriverBinding;
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Check whether the driver supports this device.
+
+ @param This The Udriver binding protocol.
+ @param Controller The controller handle to check.
+ @param RemainingDevicePath The remaining device path.
+
+ @retval EFI_SUCCESS The driver supports this controller.
+ @retval other This device isn't supported.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Starts the device with this driver.
+
+ @param This The driver binding instance.
+ @param Controller Handle of device to bind driver to.
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The controller is controlled by the driver.
+ @retval Other This controller cannot be started.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Stop the device handled by this driver.
+
+ @param This The driver binding protocol.
+ @param Controller The controller to release.
+ @param NumberOfChildren The number of handles in ChildHandleBuffer.
+ @param ChildHandleBuffer The array of child handle.
+
+ @retval EFI_SUCCESS The device was stopped.
+ @retval EFI_DEVICE_ERROR The device could not be stopped due to a device error.
+ @retval Others Fail to uninstall protocols attached on the device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// Simple Text Input Protocol functions
+//
+/**
+ Reset the Keyboard and do BAT test for it, if (ExtendedVerification == TRUE) then do some extra keyboard validations.
+
+ @param This Pointer of simple text Protocol.
+ @param ExtendedVerification Whether perform the extra validation of keyboard. True: perform; FALSE: skip.
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_DEVICE_ERROR Errors occurred during reseting keyboard.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReset (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Read out the scan code of the key that has just been stroked.
+
+ @param This Pointer of simple text Protocol.
+ @param Key Pointer for store the key that read out.
+
+ @retval EFI_SUCCESS The key is read out successfully.
+ @retval other The key reading failed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStroke (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This,
+ OUT EFI_INPUT_KEY *Key
+ );
+
+//
+// Private worker functions
+//
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKey (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Check key buffer to get the key stroke status.
+
+ @param This Pointer of the protocol EFI_SIMPLE_TEXT_IN_PROTOCOL.
+
+ @retval EFI_SUCCESS A key is being pressed now.
+ @retval Other No key is now pressed.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardCheckForKey (
+ IN EFI_SIMPLE_TEXT_INPUT_PROTOCOL *This
+ );
+
+/**
+ Convert unicode combined with scan code of key to the counterpart of EFIScancode of it.
+
+ @param KeyChar Unicode of key.
+ @param ScanCode Scan code of key.
+
+ @return The value of EFI Scancode for the key.
+ @retval SCAN_NULL No corresponding value in the EFI convert table is found for the key.
+
+**/
+UINT16
+ConvertToEFIScanCode (
+ IN CHAR16 KeyChar,
+ IN UINT16 ScanCode
+ );
+
+/**
+ Check whether there is Ps/2 Keyboard device in system by 0xF4 Keyboard Command
+ If Keyboard receives 0xF4, it will respond with 'ACK'. If it doesn't respond, the device
+ should not be in system.
+
+ @param BiosKeyboardPrivate Keyboard Private Data Struture
+
+ @retval TRUE Keyboard in System.
+ @retval FALSE Keyboard not in System.
+
+**/
+BOOLEAN
+CheckKeyboardConnect (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate
+ );
+
+/**
+ Timer event handler: read a series of key stroke from 8042
+ and put them into memory key buffer.
+ It is registered as running under TPL_NOTIFY
+
+ @param Event The timer event
+ @param Context A BIOS_KEYBOARD_DEV pointer
+
+**/
+VOID
+EFIAPI
+BiosKeyboardTimerHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Reset the input device and optionaly run diagnostics
+
+ @param This Protocol instance pointer.
+ @param ExtendedVerification Driver may perform diagnostics on reset.
+
+ @retval EFI_SUCCESS The device was reset.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly and could
+ not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardResetEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Reads the next keystroke from the input device. The WaitForKey Event can
+ be used to test for existance of a keystroke via WaitForEvent () call.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval EFI_SUCCESS The keystroke information was returned.
+ @retval EFI_NOT_READY There was no keystroke data availiable.
+ @retval EFI_DEVICE_ERROR The keystroke information was not returned due to
+ hardware errors.
+ @retval EFI_INVALID_PARAMETER KeyData is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardReadKeyStrokeEx (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ OUT EFI_KEY_DATA *KeyData
+ );
+
+/**
+ Set certain state for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyToggleState A pointer to the EFI_KEY_TOGGLE_STATE to set the
+ state for the input device.
+
+ @retval EFI_SUCCESS The device state was set successfully.
+ @retval EFI_DEVICE_ERROR The device is not functioning correctly and could
+ not have the setting adjusted.
+ @retval EFI_UNSUPPORTED The device does not have the ability to set its state.
+ @retval EFI_INVALID_PARAMETER KeyToggleState is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardSetState (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_TOGGLE_STATE *KeyToggleState
+ );
+
+/**
+ Register a notification function for a particular keystroke for the input device.
+
+ @param This Protocol instance pointer.
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information data for the key that was pressed.
+ @param KeyNotificationFunction Points to the function to be called when the key
+ sequence is typed specified by KeyData.
+ @param NotifyHandle Points to the unique handle assigned to the registered notification.
+
+
+ @retval EFI_SUCCESS The notification function was registered successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate resources for necesssary data structures.
+ @retval EFI_INVALID_PARAMETER KeyData or NotifyHandle is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardRegisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN EFI_KEY_DATA *KeyData,
+ IN EFI_KEY_NOTIFY_FUNCTION KeyNotificationFunction,
+ OUT VOID **NotifyHandle
+ );
+
+/**
+ Remove a registered notification function from a particular keystroke.
+
+ @param This Protocol instance pointer.
+ @param NotificationHandle The handle of the notification function being unregistered.
+
+ @retval EFI_SUCCESS The notification function was unregistered successfully.
+ @retval EFI_INVALID_PARAMETER The NotificationHandle is invalid.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardUnregisterKeyNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *This,
+ IN VOID *NotificationHandle
+ );
+
+/**
+ Wait for a specific value to be presented in
+ Data register of Keyboard Controller by keyboard and then read it,
+ used in keyboard commands ack
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Value The value to be waited for
+ @param WaitForValueTimeOut The limit of microseconds for timeout
+
+ @retval EFI_SUCCESS The command byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWaitForValue (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Value,
+ IN UINTN WaitForValueTimeOut
+ );
+
+/**
+ Write data byte to input buffer or input/output ports of Keyboard Controller with delay and waiting for buffer-empty state.
+
+ @param BiosKeyboardPrivate Keyboard instance pointer.
+ @param Data Data byte to write.
+
+ @retval EFI_SUCCESS The data byte is written successfully.
+ @retval EFI_TIMEOUT Timeout occurred during writing.
+
+**/
+EFI_STATUS
+KeyboardWrite (
+ IN BIOS_KEYBOARD_DEV *BiosKeyboardPrivate,
+ IN UINT8 Data
+ );
+
+/**
+ Free keyboard notify list.
+
+ @param ListHead The list head
+
+ @retval EFI_SUCCESS Free the notify list successfully
+ @retval EFI_INVALID_PARAMETER ListHead is invalid.
+
+**/
+EFI_STATUS
+BiosKeyboardFreeNotifyList (
+ IN OUT LIST_ENTRY *ListHead
+ );
+
+/**
+ Check if key is registered.
+
+ @param RegsiteredData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was registered.
+ @param InputData A pointer to a buffer that is filled in with the keystroke
+ state data for the key that was pressed.
+
+ @retval TRUE Key be pressed matches a registered key.
+ @retval FLASE Match failed.
+
+**/
+BOOLEAN
+IsKeyRegistered (
+ IN EFI_KEY_DATA *RegsiteredData,
+ IN EFI_KEY_DATA *InputData
+ );
+
+/**
+ Waiting on the keyboard event, if there's any key pressed by the user, signal the event
+
+ @param Event The event that be siganlled when any key has been stroked.
+ @param Context Pointer of the protocol EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL.
+
+**/
+VOID
+EFIAPI
+BiosKeyboardWaitForKeyEx (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c
new file mode 100644
index 0000000000..45fa7a21f8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.c
@@ -0,0 +1,183 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosKeyboard.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName = {
+ BiosKeyboardComponentNameGetDriverName,
+ BiosKeyboardComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosKeyboardComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosKeyboardComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosKeyboardDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT16] Keyboard Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosKeyboardDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosKeyboardComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h
new file mode 100644
index 0000000000..0218ef865c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/ComponentName.h
@@ -0,0 +1,153 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BIOS_KEYBOARD_COMPONENT_NAME_H_
+#define _BIOS_KEYBOARD_COMPONENT_NAME_H_
+
+
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosKeyboardComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosKeyboardComponentName2;
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosKeyboardComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
new file mode 100644
index 0000000000..a453480aa9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
@@ -0,0 +1,77 @@
+## @file
+# Ps2 Keyboard driver.
+#
+# Ps2 Keyboard driver by using Legacy Bios protocol service and IsaIo protocol
+# service. This dirver uses legacy INT16 to get the key stroke status.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = KeyboardDxe
+ MODULE_UNI_FILE = KeyboardDxe.uni
+ FILE_GUID = 5479662B-6AE4-49e8-A6BD-6DE4B625811F
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InitializeBiosKeyboard
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosKeyboardDriverBinding
+# COMPONENT_NAME = gBiosKeyboardComponentName
+#
+
+[Sources]
+ ComponentName.c
+ ComponentName.h
+ BiosKeyboard.c
+ BiosKeyboard.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ ReportStatusCodeLib
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ BaseLib
+ PcdLib
+
+[Protocols]
+ gEfiIsaIoProtocolGuid ## TO_START
+ gEfiSimpleTextInProtocolGuid ## BY_START
+ gEfiSimpleTextInputExProtocolGuid ## BY_START
+ gEfiLegacyBiosProtocolGuid ## CONSUMES
+ gEfiPs2PolicyProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2KbdExtendedVerification|FALSE ## CONSUMES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFastPS2Detection ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ KeyboardDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.uni
new file mode 100644
index 0000000000..f86542d37f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxeExtra.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxeExtra.uni
new file mode 100644
index 0000000000..38f08d5138
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c
new file mode 100644
index 0000000000..7af2dedd5d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.c
@@ -0,0 +1,3522 @@
+/** @file
+
+Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+
+///
+/// EFI Driver Binding Protocol Instance
+///
+EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding = {
+ BiosSnp16DriverBindingSupported,
+ BiosSnp16DriverBindingStart,
+ BiosSnp16DriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+///
+/// This boolean is used to determine if we should release the cached vector during an error condition.
+///
+BOOLEAN mCachedInt1A = FALSE;
+
+//
+// Private worker functions;
+//
+
+/**
+ Start the UNDI interface.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+ @param Ax PCI address of Undi device.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStartUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINT16 Ax
+ );
+
+/**
+ Start the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStopUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Stop the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
+ @retval Others Status of stop 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCleanupUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Get runtime information for Undi network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get runtime information for Undi network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetInformation (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Get NIC type
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NIC type.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNicType (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Get NDIS information
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NDIS information.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ );
+
+/**
+ Signal handlers for ExitBootServices event.
+
+ Clean up any Real-mode UNDI residue from the system
+
+ @param Event ExitBootServices event
+ @param Context
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Loads the undi driver.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_SUCCESS - Successfully loads undi driver.
+ @retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
+**/
+EFI_STATUS
+Undi16SimpleNetworkLoadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Unload 16 bit UNDI Option ROM from memory
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+Undi16SimpleNetworkUnloadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ );
+
+/**
+ Entry point for EFI drivers.
+
+ @param ImageHandle Handle that identifies the loaded image.
+ @param SystemTable System Table for this image.
+
+ @return EFI_STATUS Return status from EfiLibInstallAllDriverProtocols.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosSnp16DriverBinding,
+ ImageHandle,
+ &gBiosSnp16ComponentName,
+ &gBiosSnp16ComponentName2
+ );
+}
+
+//
+// EFI Driver Binding Protocol Functions
+//
+/**
+ Tests to see if this driver supports a given controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The driver supports given controller.
+ @retval EFI_UNSUPPORT The driver doesn't support given controller.
+ @retval Other Other errors prevent driver finishing to test
+ if the driver supports given controller.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // See if this is a PCI Network Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint32, 0, sizeof (Pci) / sizeof (UINT32), &Pci);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == PCI_CLASS_NETWORK) {
+ Status = EFI_SUCCESS;
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+/**
+ Starts the Snp device controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS - The device was started.
+ @retval EFI_DEVICE_ERROR - The device could not be started due to a device error.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ EFI_DEV_PATH Node;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINTN Flags;
+ UINT64 Supports;
+
+ SimpleNetworkDevice = NULL;
+ PciIo = NULL;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Allocate memory for this SimpleNetwork device instance
+ //
+ Status = gBS->AllocatePool (
+ EfiBootServicesData,
+ sizeof (EFI_SIMPLE_NETWORK_DEV),
+ (VOID **) &SimpleNetworkDevice
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ZeroMem (SimpleNetworkDevice, sizeof (EFI_SIMPLE_NETWORK_DEV));
+
+ //
+ // Initialize the SimpleNetwork device instance
+ //
+ SimpleNetworkDevice->Signature = EFI_SIMPLE_NETWORK_DEV_SIGNATURE;
+ SimpleNetworkDevice->LegacyBios = LegacyBios;
+ SimpleNetworkDevice->BaseDevicePath = DevicePath;
+ SimpleNetworkDevice->PciIo = PciIo;
+
+ //
+ // Initialize the Nii Protocol
+ //
+ SimpleNetworkDevice->Nii.Revision = EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL_REVISION;
+ SimpleNetworkDevice->Nii.Type = EfiNetworkInterfaceUndi;
+
+ CopyMem (&SimpleNetworkDevice->Nii.StringId, "UNDI", 4);
+
+ //
+ // Load 16 bit UNDI Option ROM into Memory
+ //
+ Status = Undi16SimpleNetworkLoadUndi (SimpleNetworkDevice);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_NET, "ERROR : Could not load UNDI. Status = %r\n", Status));
+ goto Done;
+ }
+
+ SimpleNetworkDevice->UndiLoaded = TRUE;
+
+ //
+ // Call PXENV_START_UNDI - Initilizes the UNID interface for use.
+ //
+ PciIo->GetLocation (PciIo, &Segment, &Bus, &Device, &Function);
+ Status = Undi16SimpleNetworkStartUndi (
+ SimpleNetworkDevice,
+ (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function))
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_NET, "ERROR : Could not StartUndi. Status = %r\n", Status));
+ goto Done;
+ }
+ //
+ // Initialize the Simple Network Protocol
+ //
+ DEBUG ((DEBUG_NET, "Initialize SimpleNetworkDevice instance\n"));
+
+ SimpleNetworkDevice->SimpleNetwork.Revision = EFI_SIMPLE_NETWORK_PROTOCOL_REVISION;
+ SimpleNetworkDevice->SimpleNetwork.Start = Undi16SimpleNetworkStart;
+ SimpleNetworkDevice->SimpleNetwork.Stop = Undi16SimpleNetworkStop;
+ SimpleNetworkDevice->SimpleNetwork.Initialize = Undi16SimpleNetworkInitialize;
+ SimpleNetworkDevice->SimpleNetwork.Reset = Undi16SimpleNetworkReset;
+ SimpleNetworkDevice->SimpleNetwork.Shutdown = Undi16SimpleNetworkShutdown;
+ SimpleNetworkDevice->SimpleNetwork.ReceiveFilters = Undi16SimpleNetworkReceiveFilters;
+ SimpleNetworkDevice->SimpleNetwork.StationAddress = Undi16SimpleNetworkStationAddress;
+ SimpleNetworkDevice->SimpleNetwork.Statistics = Undi16SimpleNetworkStatistics;
+ SimpleNetworkDevice->SimpleNetwork.MCastIpToMac = Undi16SimpleNetworkMCastIpToMac;
+ SimpleNetworkDevice->SimpleNetwork.NvData = Undi16SimpleNetworkNvData;
+ SimpleNetworkDevice->SimpleNetwork.GetStatus = Undi16SimpleNetworkGetStatus;
+ SimpleNetworkDevice->SimpleNetwork.Transmit = Undi16SimpleNetworkTransmit;
+ SimpleNetworkDevice->SimpleNetwork.Receive = Undi16SimpleNetworkReceive;
+ SimpleNetworkDevice->SimpleNetwork.Mode = &(SimpleNetworkDevice->SimpleNetworkMode);
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_WAIT,
+ TPL_NOTIFY,
+ Undi16SimpleNetworkWaitForPacket,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &SimpleNetworkDevice->SimpleNetwork.WaitForPacket
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
+ goto Done;
+ }
+ //
+ // Create an event to be signalled when ExitBootServices occurs in order
+ // to clean up nicely
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ Undi16SimpleNetworkEvent,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &SimpleNetworkDevice->EfiBootEvent
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : Could not create event. Status = %r\n", Status));
+ goto Done;
+ }
+
+ //
+ // Create an event to be signalled when Legacy Boot occurs to clean up the IVT
+ //
+ Status = EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ Undi16SimpleNetworkEvent,
+ NULL,
+ &SimpleNetworkDevice->LegacyBootEvent
+ );
+
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR,"ERROR : Could not create event. Status = %r\n",Status));
+ goto Done;
+ }
+
+ //
+ // Initialize the SimpleNetwork Mode Information
+ //
+ DEBUG ((DEBUG_NET, "Initialize Mode Information\n"));
+
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
+ SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize = 14;
+ SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable = TRUE;
+ SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported = TRUE;
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterMask = EFI_SIMPLE_NETWORK_RECEIVE_UNICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS |
+ EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST;
+ SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount = MAXNUM_MCADDR;
+
+ //
+ // Initialize the SimpleNetwork Private Information
+ //
+ DEBUG ((DEBUG_NET, "Initialize Private Information\n"));
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1,
+ (VOID **) &SimpleNetworkDevice->Xmit
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxRealModeMediaHeader
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxRealModeDataBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ 1,
+ &SimpleNetworkDevice->TxDestAddr
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ SimpleNetworkDevice->Xmit->XmitOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) & 0x000f);
+
+ SimpleNetworkDevice->Xmit->XmitSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeMediaHeader) >> 4);
+
+ SimpleNetworkDevice->Xmit->DataBlkCount = 1;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDPtrType = 1;
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDRsvdByte = 0;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrOffset = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) & 0x000f);
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataPtrSegment = (UINT16) (((UINT32)(UINTN) SimpleNetworkDevice->TxRealModeDataBuffer) >> 4);
+
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // Start() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "Start()\n"));
+
+ Status = Undi16SimpleNetworkStart (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // GetInformation() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetInformation()\n"));
+
+ Status = Undi16SimpleNetworkGetInformation (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Build the device path for the child device
+ //
+ ZeroMem (&Node, sizeof (Node));
+ Node.DevPath.Type = MESSAGING_DEVICE_PATH;
+ Node.DevPath.SubType = MSG_MAC_ADDR_DP;
+ SetDevicePathNodeLength (&Node.DevPath, sizeof (MAC_ADDR_DEVICE_PATH));
+ CopyMem (
+ &Node.MacAddr.MacAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ sizeof (EFI_MAC_ADDRESS)
+ );
+ SimpleNetworkDevice->DevicePath = AppendDevicePathNode (
+ SimpleNetworkDevice->BaseDevicePath,
+ &Node.DevPath
+ );
+
+ //
+ // GetNicType() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetNicType()\n"));
+
+ Status = Undi16SimpleNetworkGetNicType (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // GetNdisInfo() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "GetNdisInfo()\n"));
+
+ Status = Undi16SimpleNetworkGetNdisInfo (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Stop() the SimpleNetwork device
+ //
+ DEBUG ((DEBUG_NET, "Stop()\n"));
+
+ Status = SimpleNetworkDevice->SimpleNetwork.Stop (&SimpleNetworkDevice->SimpleNetwork);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Print Mode information
+ //
+ DEBUG ((DEBUG_NET, "Mode->State = %d\n", SimpleNetworkDevice->SimpleNetworkMode.State));
+ DEBUG ((DEBUG_NET, "Mode->HwAddressSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize));
+ DEBUG ((DEBUG_NET, "Mode->MacAddressChangeable = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable));
+ DEBUG ((DEBUG_NET, "Mode->MultiplTxSupported = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MultipleTxSupported));
+ DEBUG ((DEBUG_NET, "Mode->NvRamSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamSize));
+ DEBUG ((DEBUG_NET, "Mode->NvRamAccessSize = %d\n", SimpleNetworkDevice->SimpleNetworkMode.NvRamAccessSize));
+ DEBUG ((DEBUG_NET, "Mode->ReceiveFilterSetting = %d\n", SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting));
+ DEBUG ((DEBUG_NET, "Mode->IfType = %d\n", SimpleNetworkDevice->SimpleNetworkMode.IfType));
+ DEBUG ((DEBUG_NET, "Mode->MCastFilterCount = %d\n", SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount));
+ for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; Index++) {
+ DEBUG ((DEBUG_NET, " Filter[%02d] = ", Index));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index].Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+ }
+
+ DEBUG ((DEBUG_NET, "CurrentAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, "BroadcastAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, "PermanentAddress = "));
+ for (Index2 = 0; Index2 < 16; Index2++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress.Addr[Index2]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // The network device was started, information collected, and stopped.
+ // Install protocol interfaces for the SimpleNetwork device.
+ //
+ DEBUG ((DEBUG_NET, "Install Protocol Interfaces on network interface\n"));
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &SimpleNetworkDevice->Handle,
+ &gEfiSimpleNetworkProtocolGuid,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ &SimpleNetworkDevice->Nii,
+ &gEfiDevicePathProtocolGuid,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Open PCI I/O from the newly created child handle
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ SimpleNetworkDevice->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+
+ DEBUG ((DEBUG_INIT, "UNDI16 Driver : EFI_SUCCESS\n"));
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if (SimpleNetworkDevice != NULL) {
+
+ Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
+ //
+ // CLOSE + SHUTDOWN
+ //
+ Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
+ //
+ // CLEANUP
+ //
+ Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
+ //
+ // STOP
+ //
+ if (SimpleNetworkDevice->UndiLoaded) {
+ Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
+ }
+
+ if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
+ }
+
+ if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
+ }
+
+ if (SimpleNetworkDevice->EfiBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
+ }
+
+ if (SimpleNetworkDevice->Xmit != NULL) {
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
+ );
+ }
+
+ if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
+ }
+
+ if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
+ }
+
+ if (SimpleNetworkDevice->TxDestAddr != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
+ }
+
+ gBS->FreePool (SimpleNetworkDevice);
+
+ //
+ // Only restore the vector if it was cached.
+ //
+ if (mCachedInt1A) {
+ RestoreCachedVectorAddress (0x1A);
+ mCachedInt1A = FALSE;
+ }
+ }
+
+ if (PciIo != NULL) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Supports,
+ NULL
+ );
+ }
+ }
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ if (Status != EFI_OUT_OF_RESOURCES) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ }
+ return Status;
+}
+
+/**
+ Stops the device by given device controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed. May be NULL if
+ NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS - The device was stopped.
+ @retval EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ BOOLEAN AllChildrenStopped;
+ EFI_SIMPLE_NETWORK_PROTOCOL *SimpleNetwork;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT64 Supports;
+
+ //
+ // Complete all outstanding transactions to Controller.
+ // Don't allow any new transaction to Controller to be started.
+ //
+ if (NumberOfChildren == 0) {
+ //
+ // Close the bus driver
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationDisable,
+ Supports,
+ NULL
+ );
+ }
+ }
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = EFI_DEVICE_ERROR;
+ }
+ return Status;
+ }
+
+ AllChildrenStopped = TRUE;
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+
+ Status = gBS->OpenProtocol (
+ ChildHandleBuffer[Index],
+ &gEfiSimpleNetworkProtocolGuid,
+ (VOID **) &SimpleNetwork,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (SimpleNetwork);
+
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index]
+ );
+
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ SimpleNetworkDevice->Handle,
+ &gEfiSimpleNetworkProtocolGuid,
+ &SimpleNetworkDevice->SimpleNetwork,
+ &gEfiNetworkInterfaceIdentifierProtocolGuid,
+ &SimpleNetworkDevice->Nii,
+ &gEfiDevicePathProtocolGuid,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ ChildHandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ } else {
+
+ Undi16SimpleNetworkShutdown (&SimpleNetworkDevice->SimpleNetwork);
+ //
+ // CLOSE + SHUTDOWN
+ //
+ Undi16SimpleNetworkCleanupUndi (SimpleNetworkDevice);
+ //
+ // CLEANUP
+ //
+ Undi16SimpleNetworkStopUndi (SimpleNetworkDevice);
+ //
+ // STOP
+ //
+ if (SimpleNetworkDevice->UndiLoaded) {
+ Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
+ }
+
+ if (SimpleNetworkDevice->SimpleNetwork.WaitForPacket != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->SimpleNetwork.WaitForPacket);
+ }
+
+ if (SimpleNetworkDevice->LegacyBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->LegacyBootEvent);
+ }
+
+ if (SimpleNetworkDevice->EfiBootEvent != NULL) {
+ gBS->CloseEvent (SimpleNetworkDevice->EfiBootEvent);
+ }
+
+ if (SimpleNetworkDevice->Xmit != NULL) {
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->Xmit,
+ sizeof (PXENV_UNDI_TBD_T) / EFI_PAGE_SIZE + 1
+ );
+ }
+
+ if (SimpleNetworkDevice->TxRealModeMediaHeader != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeMediaHeader, 1);
+ }
+
+ if (SimpleNetworkDevice->TxRealModeDataBuffer != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxRealModeDataBuffer, 1);
+ }
+
+ if (SimpleNetworkDevice->TxDestAddr != NULL) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->TxDestAddr, 1);
+ }
+
+ gBS->FreePool (SimpleNetworkDevice);
+ }
+
+ }
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+//
+// FIFO Support Functions
+//
+/**
+ Judge whether transmit FIFO is full.
+
+ @param Fifo Point to trasmit FIFO structure.
+
+ @return BOOLEAN whether transmit FIFO is full.
+**/
+BOOLEAN
+SimpleNetworkTransmitFifoFull (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
+ )
+{
+ if (((Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE) == Fifo->First) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Judge whether transmit FIFO is empty.
+
+ @param Fifo Point to trasmit FIFO structure.
+
+ @return BOOLEAN whether transmit FIFO is empty.
+**/
+BOOLEAN
+SimpleNetworkTransmitFifoEmpty (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo
+ )
+{
+ if (Fifo->Last == Fifo->First) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+
+/**
+ Add data into transmit buffer.
+
+ @param Fifo Point to trasmit FIFO structure.
+ @param Data The data point want to be added.
+
+ @retval EFI_OUT_OF_RESOURCES FIFO is full
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+SimpleNetworkTransmitFifoAdd (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
+ VOID *Data
+ )
+{
+ if (SimpleNetworkTransmitFifoFull (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Fifo->Data[Fifo->Last] = Data;
+ Fifo->Last = (Fifo->Last + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get a data and remove it from network transmit FIFO.
+
+ @param Fifo Point to trasmit FIFO structure.
+ @param Data On return, point to the data point want to be got and removed.
+
+ @retval EFI_OUT_OF_RESOURCES network transmit buffer is empty.
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+SimpleNetworkTransmitFifoRemove (
+ EFI_SIMPLE_NETWORK_DEV_FIFO *Fifo,
+ VOID **Data
+ )
+{
+ if (SimpleNetworkTransmitFifoEmpty (Fifo)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *Data = Fifo->Data[Fifo->First];
+ Fifo->First = (Fifo->First + 1) % EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get recive filter setting according to EFI mask value.
+
+ @param ReceiveFilterSetting filter setting EFI mask value.
+
+ @return UINT16 Undi filter setting value.
+**/
+UINT16
+Undi16GetPacketFilterSetting (
+ UINTN ReceiveFilterSetting
+ )
+{
+ UINT16 PktFilter;
+
+ PktFilter = 0;
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_UNICAST) != 0) {
+ PktFilter |= FLTR_DIRECTED;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ PktFilter |= FLTR_DIRECTED;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_BROADCAST) != 0) {
+ PktFilter |= FLTR_BRDCST;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS) != 0) {
+ PktFilter |= FLTR_PRMSCS;
+ }
+
+ if ((ReceiveFilterSetting & EFI_SIMPLE_NETWORK_RECEIVE_PROMISCUOUS_MULTICAST) != 0) {
+ PktFilter |= FLTR_PRMSCS;
+ //
+ // @bug : Do not know if this is right????
+ //
+ }
+ //
+ // @bug : What is FLTR_SRC_RTG?
+ //
+ return PktFilter;
+}
+
+/**
+ Get filter setting from multi cast buffer .
+
+ @param Mode Point to mode structure.
+ @param McastBuffer The multi cast buffer
+ @param HwAddressSize Size of filter value.
+
+**/
+VOID
+Undi16GetMCastFilters (
+ IN EFI_SIMPLE_NETWORK_MODE *Mode,
+ IN OUT PXENV_UNDI_MCAST_ADDR_T *McastBuffer,
+ IN UINTN HwAddressSize
+ )
+{
+ UINTN Index;
+
+ //
+ // @bug : What if Mode->MCastFilterCount > MAXNUM_MCADDR?
+ //
+ McastBuffer->MCastAddrCount = (UINT16) Mode->MCastFilterCount;
+ for (Index = 0; Index < MAXNUM_MCADDR; Index++) {
+ if (Index < McastBuffer->MCastAddrCount) {
+ CopyMem (&McastBuffer->MCastAddr[Index], &Mode->MCastFilter[Index], HwAddressSize);
+ } else {
+ ZeroMem (&McastBuffer->MCastAddr[Index], HwAddressSize);
+ }
+ }
+}
+//
+// Load 16 bit UNDI Option ROM into memory
+//
+/**
+ Loads the undi driver.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_SUCCESS - Successfully loads undi driver.
+ @retval EFI_NOT_FOUND - Doesn't find undi driver or undi driver load failure.
+**/
+EFI_STATUS
+Undi16SimpleNetworkLoadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN RomAddress;
+ PCI_EXPANSION_ROM_HEADER *PciExpansionRomHeader;
+ PCI_DATA_STRUCTURE *PciDataStructure;
+ PCI_TYPE00 Pci;
+
+ if (!mCachedInt1A) {
+ Status = CacheVectorAddress (0x1A);
+ if (!EFI_ERROR (Status)) {
+ mCachedInt1A = TRUE;
+ }
+ }
+
+ PciIo = SimpleNetworkDevice->PciIo;
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ for (RomAddress = 0xc0000; RomAddress < 0xfffff; RomAddress += 0x800) {
+
+ PciExpansionRomHeader = (PCI_EXPANSION_ROM_HEADER *) RomAddress;
+
+ if (PciExpansionRomHeader->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ continue;
+ }
+
+ DEBUG ((DEBUG_INIT, "Option ROM found at %X\n", RomAddress));
+
+ //
+ // If the pointer to the PCI Data Structure is invalid, no further images can be located.
+ // The PCI Data Structure must be DWORD aligned.
+ //
+ if (PciExpansionRomHeader->PcirOffset == 0 ||
+ (PciExpansionRomHeader->PcirOffset & 3) != 0 ||
+ RomAddress + PciExpansionRomHeader->PcirOffset + sizeof (PCI_DATA_STRUCTURE) > 0x100000) {
+ break;
+ }
+
+ PciDataStructure = (PCI_DATA_STRUCTURE *) (RomAddress + PciExpansionRomHeader->PcirOffset);
+
+ if (PciDataStructure->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
+ continue;
+ }
+
+ DEBUG ((DEBUG_INIT, "PCI Data Structure found at %X\n", PciDataStructure));
+
+ if (PciDataStructure->VendorId != Pci.Hdr.VendorId || PciDataStructure->DeviceId != Pci.Hdr.DeviceId) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_INIT,
+ "PCI device with matchinng VendorId and DeviceId (%d,%d)\n",
+ (UINTN) PciDataStructure->VendorId,
+ (UINTN) PciDataStructure->DeviceId)
+ );
+
+ Status = LaunchBaseCode (SimpleNetworkDevice, RomAddress);
+
+ if (!EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Free resources allocated in LaunchBaseCode
+ //
+ Undi16SimpleNetworkUnloadUndi (SimpleNetworkDevice);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Unload 16 bit UNDI Option ROM from memory
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+Undi16SimpleNetworkUnloadUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ if (SimpleNetworkDevice->UndiLoaderTable != NULL) {
+ ZeroMem (SimpleNetworkDevice->UndiLoaderTable, SimpleNetworkDevice->UndiLoaderTablePages << EFI_PAGE_SHIFT);
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->UndiLoaderTable,
+ SimpleNetworkDevice->UndiLoaderTablePages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationDataSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationDataSegment,
+ SimpleNetworkDevice->DestinationDataSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationDataSegment,
+ SimpleNetworkDevice->DestinationDataSegmentPages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationStackSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationStackSegment,
+ SimpleNetworkDevice->DestinationStackSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationStackSegment,
+ SimpleNetworkDevice->DestinationStackSegmentPages
+ );
+ }
+
+ if (SimpleNetworkDevice->DestinationCodeSegment != NULL) {
+ ZeroMem (
+ SimpleNetworkDevice->DestinationCodeSegment,
+ SimpleNetworkDevice->DestinationCodeSegmentPages << EFI_PAGE_SHIFT
+ );
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) SimpleNetworkDevice->DestinationCodeSegment,
+ SimpleNetworkDevice->DestinationCodeSegmentPages
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Start the UNDI interface.
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+ @param Ax PCI address of Undi device.
+
+ @retval EFI_DEVICE_ERROR Fail to start 16 bit UNDI ROM.
+ @retval Others Status of start 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStartUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINT16 Ax
+ )
+{
+ EFI_STATUS Status;
+ PXENV_START_UNDI_T Start;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ //
+ // @bug : What is this state supposed to be???
+ //
+ Start.Status = INIT_PXE_STATUS;
+ Start.Ax = Ax;
+ Start.Bx = 0x0000;
+ Start.Dx = 0x0000;
+ Start.Di = 0x0000;
+ Start.Es = 0x0000;
+
+ Status = PxeStartUndi (SimpleNetworkDevice, &Start);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Start.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop the UNDI interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to stop 16 bit UNDI ROM.
+ @retval Others Status of stop 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkStopUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ PXENV_STOP_UNDI_T Stop;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Stop.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiStop (SimpleNetworkDevice, &Stop);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Stop.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Cleanup Unid network interface
+
+ @param SimpleNetworkDevice A pointer to EFI_SIMPLE_NETWORK_DEV data structure.
+
+ @retval EFI_DEVICE_ERROR Fail to cleanup 16 bit UNDI ROM.
+ @retval Others Status of cleanup 16 bit UNDI ROM.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCleanupUndi (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice
+ )
+{
+ EFI_STATUS Status;
+ PXENV_UNDI_CLEANUP_T Cleanup;
+
+ //
+ // Call 16 bit UNDI ROM to cleanup the network interface
+ //
+ Cleanup.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiCleanup (SimpleNetworkDevice, &Cleanup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Cleanup.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return Status;
+}
+
+/**
+ Get runtime information for Undi network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get runtime information for Undi network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetInformation (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN Index;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ ZeroMem (&SimpleNetworkDevice->GetInformation, sizeof (PXENV_UNDI_GET_INFORMATION_T));
+
+ SimpleNetworkDevice->GetInformation.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetInformation (SimpleNetworkDevice, &SimpleNetworkDevice->GetInformation);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetInformation.Status = %d\n", SimpleNetworkDevice->GetInformation.Status));
+ DEBUG ((DEBUG_NET, " GetInformation.BaseIo = %d\n", SimpleNetworkDevice->GetInformation.BaseIo));
+ DEBUG ((DEBUG_NET, " GetInformation.IntNumber = %d\n", SimpleNetworkDevice->GetInformation.IntNumber));
+ DEBUG ((DEBUG_NET, " GetInformation.MaxTranUnit = %d\n", SimpleNetworkDevice->GetInformation.MaxTranUnit));
+ DEBUG ((DEBUG_NET, " GetInformation.HwType = %d\n", SimpleNetworkDevice->GetInformation.HwType));
+ DEBUG ((DEBUG_NET, " GetInformation.HwAddrLen = %d\n", SimpleNetworkDevice->GetInformation.HwAddrLen));
+ DEBUG ((DEBUG_NET, " GetInformation.ROMAddress = %d\n", SimpleNetworkDevice->GetInformation.ROMAddress));
+ DEBUG ((DEBUG_NET, " GetInformation.RxBufCt = %d\n", SimpleNetworkDevice->GetInformation.RxBufCt));
+ DEBUG ((DEBUG_NET, " GetInformation.TxBufCt = %d\n", SimpleNetworkDevice->GetInformation.TxBufCt));
+
+ DEBUG ((DEBUG_NET, " GetInformation.CurNodeAddr ="));
+ for (Index = 0; Index < 16; Index++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.CurrentNodeAddress[Index]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ DEBUG ((DEBUG_NET, " GetInformation.PermNodeAddr ="));
+ for (Index = 0; Index < 16; Index++) {
+ DEBUG ((DEBUG_NET, "%02x ", SimpleNetworkDevice->GetInformation.PermNodeAddress[Index]));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetInformation.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize = SimpleNetworkDevice->GetInformation.HwAddrLen;
+
+ SimpleNetworkDevice->SimpleNetworkMode.MaxPacketSize = SimpleNetworkDevice->GetInformation.MaxTranUnit;
+
+ SimpleNetworkDevice->SimpleNetworkMode.IfType = (UINT8) SimpleNetworkDevice->GetInformation.HwType;
+
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
+ );
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SimpleNetworkDevice->GetInformation.CurrentNodeAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress
+ );
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ &SimpleNetworkDevice->GetInformation.PermNodeAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ //
+ // hard code broadcast address - not avail in PXE2.1
+ //
+ ZeroMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
+ sizeof SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress
+ );
+
+ SetMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.BroadcastAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
+ 0xff
+ );
+
+ return Status;
+}
+
+/**
+ Get NIC type
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NIC type.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNicType (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (&SimpleNetworkDevice->GetNicType, sizeof (PXENV_UNDI_GET_NIC_TYPE_T));
+
+ SimpleNetworkDevice->GetNicType.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetNicType (SimpleNetworkDevice, &SimpleNetworkDevice->GetNicType);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetNicType.Status = %d\n", SimpleNetworkDevice->GetNicType.Status));
+ DEBUG ((DEBUG_NET, " GetNicType.NicType = %d\n", SimpleNetworkDevice->GetNicType.NicType));
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetNicType.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ return Status;
+}
+
+/**
+ Get NDIS information
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_SUCCESS Sucess operation.
+ @retval Others Fail to get NDIS information.
+**/
+EFI_STATUS
+Undi16SimpleNetworkGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ ZeroMem (&SimpleNetworkDevice->GetNdisInfo, sizeof (PXENV_UNDI_GET_NDIS_INFO_T));
+
+ SimpleNetworkDevice->GetNdisInfo.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiGetNdisInfo (SimpleNetworkDevice, &SimpleNetworkDevice->GetNdisInfo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DEBUG ((DEBUG_NET, " GetNdisInfo.Status = %d\n", SimpleNetworkDevice->GetNdisInfo.Status));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.IfaceType = %a\n", SimpleNetworkDevice->GetNdisInfo.IfaceType));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.LinkSpeed = %d\n", SimpleNetworkDevice->GetNdisInfo.LinkSpeed));
+ DEBUG ((DEBUG_NET, " GetNdisInfo.ServiceFlags = %08x\n", SimpleNetworkDevice->GetNdisInfo.ServiceFlags));
+
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->GetNdisInfo.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The information has been retrieved. Fill in Mode data.
+ //
+ return Status;
+}
+
+/**
+ Call Undi ROM 16bit ISR() to check interrupt cause.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param FrameLength The length of frame buffer.
+ @param FrameHeaderLength The length of frame buffer's header if has.
+ @param Frame The frame buffer to process network interrupt.
+ @param ProtType The type network transmit protocol
+ @param PktType The type of package.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM's ISR, or status is invalid.
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+Undi16SimpleNetworkIsr (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINTN *FrameLength,
+ IN UINTN *FrameHeaderLength, OPTIONAL
+ IN UINT8 *Frame, OPTIONAL
+ IN UINT8 *ProtType, OPTIONAL
+ IN UINT8 *PktType OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ BOOLEAN FrameReceived;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ FrameReceived = FALSE;
+
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_NET, "Isr() IsrValid = %d\n", SimpleNetworkDevice->IsrValid));
+
+ if (!SimpleNetworkDevice->IsrValid) {
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_START;
+
+ DEBUG ((DEBUG_NET, "Isr() START\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // There have been no events on this UNDI interface, so return EFI_NOT_READY
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_NOT_OURS) {
+ return EFI_SUCCESS;
+ }
+ //
+ // There is data to process, so call until all events processed.
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_PROCESS;
+
+ DEBUG ((DEBUG_NET, "Isr() PROCESS\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ SimpleNetworkDevice->IsrValid = TRUE;
+ }
+ //
+ // Call UNDI GET_NEXT until DONE
+ //
+ while (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_DONE) {
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // UNDI is busy. Caller will have to call again.
+ // This should never happen with a polled mode driver.
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_BUSY) {
+ DEBUG ((DEBUG_NET, " BUSY\n"));
+ return EFI_SUCCESS;
+ }
+ //
+ // Check for invalud UNDI FuncFlag
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_RECEIVE &&
+ SimpleNetworkDevice->Isr.FuncFlag != PXENV_UNDI_ISR_OUT_TRANSMIT
+ ) {
+ DEBUG ((DEBUG_NET, " Invalid SimpleNetworkDevice->Isr.FuncFlag value %d\n", SimpleNetworkDevice->Isr.FuncFlag));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Check for Transmit Event
+ //
+ if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_TRANSMIT) {
+ DEBUG ((DEBUG_NET, " TRANSMIT\n"));
+ SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_TRANSMIT_INTERRUPT;
+ }
+ //
+ // Check for Receive Event
+ //
+ else if (SimpleNetworkDevice->Isr.FuncFlag == PXENV_UNDI_ISR_OUT_RECEIVE) {
+ //
+ // note - this code will hang on a receive interrupt in a GetStatus loop
+ //
+ DEBUG ((DEBUG_NET, " RECEIVE\n"));
+ SimpleNetworkDevice->InterruptStatus |= EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.BufferLength = %d\n", SimpleNetworkDevice->Isr.BufferLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameLength = %d\n", SimpleNetworkDevice->Isr.FrameLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.FrameHeaderLength = %d\n", SimpleNetworkDevice->Isr.FrameHeaderLength));
+ DEBUG (
+ (
+ DEBUG_NET, "SimpleNetworkDevice->Isr.Frame = %04x:%04x\n", SimpleNetworkDevice->Isr.FrameSegSel,
+ SimpleNetworkDevice->Isr.FrameOffset
+ )
+ );
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.ProtType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
+ DEBUG ((DEBUG_NET, "SimpleNetworkDevice->Isr.PktType = 0x%02x\n", SimpleNetworkDevice->Isr.BufferLength));
+
+ if (FrameReceived) {
+ return EFI_SUCCESS;
+ }
+
+ if ((Frame == NULL) || (SimpleNetworkDevice->Isr.FrameLength > *FrameLength)) {
+ DEBUG ((DEBUG_NET, "return EFI_BUFFER_TOO_SMALL *FrameLength = %08x\n", *FrameLength));
+ *FrameLength = SimpleNetworkDevice->Isr.FrameLength;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ *FrameLength = SimpleNetworkDevice->Isr.FrameLength;
+ if (FrameHeaderLength != NULL) {
+ *FrameHeaderLength = SimpleNetworkDevice->Isr.FrameHeaderLength;
+ }
+
+ if (ProtType != NULL) {
+ *ProtType = SimpleNetworkDevice->Isr.ProtType;
+ }
+
+ if (PktType != NULL) {
+ *PktType = SimpleNetworkDevice->Isr.PktType;
+ }
+
+ CopyMem (
+ Frame,
+ (VOID *)(UINTN) ((SimpleNetworkDevice->Isr.FrameSegSel << 4) + SimpleNetworkDevice->Isr.FrameOffset),
+ SimpleNetworkDevice->Isr.BufferLength
+ );
+ Frame = Frame + SimpleNetworkDevice->Isr.BufferLength;
+ if (SimpleNetworkDevice->Isr.BufferLength == SimpleNetworkDevice->Isr.FrameLength) {
+ FrameReceived = TRUE;
+ }
+ }
+ //
+ // There is data to process, so call until all events processed.
+ //
+ ZeroMem (&SimpleNetworkDevice->Isr, sizeof (PXENV_UNDI_ISR_T));
+ SimpleNetworkDevice->Isr.Status = INIT_PXE_STATUS;
+ SimpleNetworkDevice->Isr.FuncFlag = PXENV_UNDI_ISR_IN_GET_NEXT;
+
+ DEBUG ((DEBUG_NET, "Isr() GET NEXT\n"));
+
+ Status = PxeUndiIsr (SimpleNetworkDevice, &SimpleNetworkDevice->Isr);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ // if (SimpleNetworkDevice->Isr.Status != PXENV_STATUS_SUCCESS) {
+ // return EFI_DEVICE_ERROR;
+ // }
+ //
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+ return EFI_SUCCESS;
+}
+//
+// ///////////////////////////////////////////////////////////////////////////////////////
+// Simple Network Protocol Interface Functions using 16 bit UNDI Option ROMs
+/////////////////////////////////////////////////////////////////////////////////////////
+//
+// Start()
+//
+/**
+ Call 16 bit UNDI ROM to start the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_STARTUP_T Startup;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ case EfiSimpleNetworkInitialized:
+ return EFI_ALREADY_STARTED;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Startup.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiStartup (SimpleNetworkDevice, &Startup);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Startup.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been started, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
+
+ //
+ //
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = 0;
+ SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = 0;
+
+ return Status;
+}
+//
+// Stop()
+//
+/**
+ Call 16 bit UNDI ROM to stop the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStopped;
+
+ return Status;
+}
+
+//
+// Initialize()
+//
+/**
+ Initialize network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtraRxBufferSize The size of extra request receive buffer.
+ @param ExtraTxBufferSize The size of extra request transmit buffer.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_INITIALIZE_T Initialize;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ break;
+
+ case EfiSimpleNetworkInitialized:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Initialize.Status = INIT_PXE_STATUS;
+ Initialize.ProtocolIni = 0;
+
+ Status = PxeUndiInitialize (SimpleNetworkDevice, &Initialize);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Status = %r\n", Status));
+ DEBUG ((DEBUG_ERROR, "Initialize.Status == %xh\n", Initialize.Status));
+
+ if (Initialize.Status == PXENV_STATUS_UNDI_MEDIATEST_FAILED) {
+ Status = EFI_NO_MEDIA;
+ }
+
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Initialize.Status != PXENV_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiInitialize() - Initialize.Status = %04x\n", Initialize.Status));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ Open.Status = INIT_PXE_STATUS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Open.McastBuffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Status = %r\n", Status));
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Open.Status != PXENV_STATUS_SUCCESS) {
+ DEBUG ((DEBUG_ERROR, "ERROR : PxeUndiOpen() - Open.Status = %04x\n", Open.Status));
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been initialized, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkInitialized;
+
+ //
+ // If initialize succeeds, then assume that media is present.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = TRUE;
+
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ return Status;
+}
+//
+// Reset()
+//
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtendedVerification Need extended verfication.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_RESET_T Reset;
+ UINT16 Rx_filter;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ Reset.Status = INIT_PXE_STATUS;
+
+ Rx_filter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Reset.R_Mcast_Buf,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ Status = PxeUndiResetNic (SimpleNetworkDevice, &Reset, Rx_filter);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Reset.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ return Status;
+}
+//
+// Shutdown()
+//
+/**
+ Shutdown network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_SHUTDOWN_T Shutdown;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+
+ //
+ // Call 16 bit UNDI ROM to start the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Close.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ Shutdown.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiShutdown (SimpleNetworkDevice, &Shutdown);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Shutdown.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // The UNDI interface has been initialized, so update the State.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.State = EfiSimpleNetworkStarted;
+
+ //
+ // If shutdown succeeds, then assume that media is not present.
+ //
+ SimpleNetworkDevice->SimpleNetworkMode.MediaPresent = FALSE;
+
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // A short delay. Without this an initialize immediately following
+ // a shutdown will cause some versions of UNDI-16 to stop operating.
+ //
+ gBS->Stall (250000);
+
+ return Status;
+}
+//
+// ReceiveFilters()
+//
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Enable Enable mask value
+ @param Disable Disable mask value
+ @param ResetMCastFilter Whether reset multi cast filter or not
+ @param MCastFilterCnt Count of mutli cast filter for different MAC address
+ @param MCastFilter Buffer for mustli cast filter for different MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT32 NewFilter;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // First deal with possible filter setting changes
+ //
+ if ((Enable == 0) && (Disable == 0) && !ResetMCastFilter) {
+ return EFI_SUCCESS;
+ }
+
+ NewFilter = (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting | Enable) &~Disable;
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ if ((MCastFilterCnt == 0) || (MCastFilter == 0) || MCastFilterCnt > SimpleNetworkDevice->SimpleNetworkMode.MaxMCastFilterCount) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Call 16 bit UNDI ROM to close the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Close.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ //
+ // Reset the recycled transmit buffer FIFO
+ //
+ SimpleNetworkDevice->TxBufferFifo.First = 0;
+ SimpleNetworkDevice->TxBufferFifo.Last = 0;
+
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ZeroMem (&Open, sizeof Open);
+
+ Open.Status = INIT_PXE_STATUS;
+ Open.PktFilter = Undi16GetPacketFilterSetting (NewFilter);
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ //
+ // Copy the MAC addresses into the UNDI open parameter structure
+ //
+ Open.McastBuffer.MCastAddrCount = (UINT16) MCastFilterCnt;
+ for (Index = 0; Index < MCastFilterCnt; ++Index) {
+ CopyMem (
+ Open.McastBuffer.MCastAddr[Index],
+ &MCastFilter[Index],
+ sizeof Open.McastBuffer.MCastAddr[Index]
+ );
+ }
+ } else if (!ResetMCastFilter) {
+ for (Index = 0; Index < SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount; ++Index) {
+ CopyMem (
+ Open.McastBuffer.MCastAddr[Index],
+ &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
+ sizeof Open.McastBuffer.MCastAddr[Index]
+ );
+ }
+ }
+
+ Status = PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (Open.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ SimpleNetworkDevice->IsrValid = FALSE;
+ SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting = NewFilter;
+
+ if ((NewFilter & EFI_SIMPLE_NETWORK_RECEIVE_MULTICAST) != 0) {
+ SimpleNetworkDevice->SimpleNetworkMode.MCastFilterCount = (UINT32) MCastFilterCnt;
+ for (Index = 0; Index < MCastFilterCnt; ++Index) {
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.MCastFilter[Index],
+ &MCastFilter[Index],
+ sizeof (EFI_MAC_ADDRESS)
+ );
+ }
+ }
+ //
+ // Read back multicast addresses.
+ //
+ return EFI_SUCCESS;
+}
+//
+// StationAddress()
+//
+/**
+ Set new MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether reset station MAC address to permenent address
+ @param New A pointer to New address
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS * New OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_SET_STATION_ADDR_T SetStationAddr;
+ //
+ // EFI_DEVICE_PATH_PROTOCOL *OldDevicePath;
+ //
+ PXENV_UNDI_CLOSE_T Close;
+ PXENV_UNDI_OPEN_T Open;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ SetStationAddr.Status = INIT_PXE_STATUS;
+
+ if (Reset) {
+ //
+ // If we are reseting the Station Address to the permanent address, and the
+ // Station Address is not programmable, then just return EFI_SUCCESS.
+ //
+ if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
+ return EFI_SUCCESS;
+ }
+ //
+ // If the address is already the permanent address, then just return success.
+ //
+ if (CompareMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ ) == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy the adapters permanent address to the new station address
+ //
+ CopyMem (
+ &SetStationAddr.StationAddress,
+ &SimpleNetworkDevice->SimpleNetworkMode.PermanentAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+ } else {
+ //
+ // If we are setting the Station Address, and the
+ // Station Address is not programmable, return invalid parameter.
+ //
+ if (!SimpleNetworkDevice->SimpleNetworkMode.MacAddressChangeable) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // If the address is already the new address, then just return success.
+ //
+ if (CompareMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ New,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ ) == 0) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Copy New to the new station address
+ //
+ CopyMem (
+ &SetStationAddr.StationAddress,
+ New,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ }
+ //
+ // Call 16 bit UNDI ROM to stop the network interface
+ //
+ Close.Status = INIT_PXE_STATUS;
+
+ PxeUndiClose (SimpleNetworkDevice, &Close);
+
+ //
+ // Call 16-bit UNDI ROM to set the station address
+ //
+ SetStationAddr.Status = PXENV_STATUS_SUCCESS;
+
+ Status = PxeUndiSetStationAddr (SimpleNetworkDevice, &SetStationAddr);
+
+ //
+ // Call 16-bit UNDI ROM to start the network interface
+ //
+ Open.Status = PXENV_STATUS_SUCCESS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = Undi16GetPacketFilterSetting (SimpleNetworkDevice->SimpleNetworkMode.ReceiveFilterSetting);
+ Undi16GetMCastFilters (
+ &SimpleNetworkDevice->SimpleNetworkMode,
+ &Open.McastBuffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ PxeUndiOpen (SimpleNetworkDevice, &Open);
+
+ //
+ // Check status from station address change
+ //
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (SetStationAddr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ CopyMem (
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress,
+ &SetStationAddr.StationAddress,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+#if 0 /* The device path is based on the permanent address not the current address. */
+ //
+ // The station address was changed, so update the device path with the new MAC address.
+ //
+ OldDevicePath = SimpleNetworkDevice->DevicePath;
+ SimpleNetworkDevice->DevicePath = DuplicateDevicePath (SimpleNetworkDevice->BaseDevicePath);
+ SimpleNetworkAppendMacAddressDevicePath (
+ &SimpleNetworkDevice->DevicePath,
+ &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress
+ );
+
+ Status = LibReinstallProtocolInterfaces (
+ SimpleNetworkDevice->Handle,
+ &DevicePathProtocol,
+ OldDevicePath,
+ SimpleNetworkDevice->DevicePath,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "Failed to reinstall the DevicePath protocol for the Simple Network Device\n"));
+ DEBUG ((DEBUG_ERROR, " Status = %r\n", Status));
+ }
+
+ FreePool (OldDevicePath);
+#endif /* 0 */
+
+ return Status;
+}
+//
+// Statistics()
+//
+/**
+ Resets or collects the statistics on a network interface.
+
+ @param This Protocol instance pointer.
+ @param Reset Set to TRUE to reset the statistics for the network interface.
+ @param StatisticsSize On input the size, in bytes, of StatisticsTable. On
+ output the size, in bytes, of the resulting table of
+ statistics.
+ @param StatisticsTable A pointer to the EFI_NETWORK_STATISTICS structure that
+ contains the statistics.
+
+ @retval EFI_SUCCESS The statistics were collected from the network interface.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_BUFFER_TOO_SMALL The Statistics buffer was too small. The current buffer
+ size needed to hold the statistics is returned in
+ StatisticsSize.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_CLEAR_STATISTICS_T ClearStatistics;
+ PXENV_UNDI_GET_STATISTICS_T GetStatistics;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if ((StatisticsSize != NULL) && (*StatisticsSize != 0) && (StatisticsTable == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // If Reset is TRUE, then clear all the statistics.
+ //
+ if (Reset) {
+
+ DEBUG ((DEBUG_NET, " RESET Statistics\n"));
+
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ ClearStatistics.Status = INIT_PXE_STATUS;
+
+ Status = PxeUndiClearStatistics (SimpleNetworkDevice, &ClearStatistics);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (ClearStatistics.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ DEBUG ((DEBUG_NET, " RESET Statistics Complete"));
+ }
+
+ if (StatisticsSize != NULL) {
+ EFI_NETWORK_STATISTICS LocalStatisticsTable;
+
+ DEBUG ((DEBUG_NET, " GET Statistics\n"));
+
+ //
+ // If the size if valid, then see if the table is valid
+ //
+ if (StatisticsTable == NULL) {
+ DEBUG ((DEBUG_NET, " StatisticsTable is NULL\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ GetStatistics.Status = INIT_PXE_STATUS;
+ GetStatistics.XmtGoodFrames = 0;
+ GetStatistics.RcvGoodFrames = 0;
+ GetStatistics.RcvCRCErrors = 0;
+ GetStatistics.RcvResourceErrors = 0;
+
+ Status = PxeUndiGetStatistics (SimpleNetworkDevice, &GetStatistics);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (GetStatistics.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Fill in the Statistics Table with the collected values.
+ //
+ SetMem (&LocalStatisticsTable, sizeof LocalStatisticsTable, 0xff);
+
+ LocalStatisticsTable.TxGoodFrames = GetStatistics.XmtGoodFrames;
+ LocalStatisticsTable.RxGoodFrames = GetStatistics.RcvGoodFrames;
+ LocalStatisticsTable.RxCrcErrorFrames = GetStatistics.RcvCRCErrors;
+ LocalStatisticsTable.RxDroppedFrames = GetStatistics.RcvResourceErrors;
+
+ CopyMem (StatisticsTable, &LocalStatisticsTable, *StatisticsSize);
+
+ DEBUG (
+ (DEBUG_NET,
+ " Statistics Collected : Size=%d Buf=%08x\n",
+ *StatisticsSize,
+ StatisticsTable)
+ );
+
+ DEBUG ((DEBUG_NET, " GET Statistics Complete"));
+
+ if (*StatisticsSize < sizeof LocalStatisticsTable) {
+ DEBUG ((DEBUG_NET, " BUFFER TOO SMALL\n"));
+ Status = EFI_BUFFER_TOO_SMALL;
+ }
+
+ *StatisticsSize = sizeof LocalStatisticsTable;
+
+ return Status;
+
+ }
+
+ return EFI_SUCCESS;
+}
+//
+// MCastIpToMac()
+//
+/**
+ Translate IP address to MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param IPv6 IPv6 or IPv4
+ @param IP A pointer to given Ip address.
+ @param MAC On return, translated MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_INVALID_PARAMETER Invalid IP address.
+ @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.
+ @retval EFI_UNSUPPORTED Do not support IPv6
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkMCastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_GET_MCAST_ADDR_T GetMcastAddr;
+
+ if (This == NULL || IP == NULL || MAC == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // 16 bit UNDI Option ROMS do not support IPv6. Check for IPv6 usage.
+ //
+ if (IPv6) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Call 16 bit UNDI ROM to open the network interface
+ //
+ GetMcastAddr.Status = INIT_PXE_STATUS;
+ CopyMem (&GetMcastAddr.InetAddr, IP, 4);
+
+ Status = PxeUndiGetMcastAddr (SimpleNetworkDevice, &GetMcastAddr);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ if (GetMcastAddr.Status != PXENV_STATUS_SUCCESS) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Copy the MAC address from the returned data structure.
+ //
+ CopyMem (
+ MAC,
+ &GetMcastAddr.MediaAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ return Status;
+}
+//
+// NvData()
+//
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ReadWrite,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+//
+// GetStatus()
+//
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN FrameLength;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (InterruptStatus == NULL && TxBuf == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FrameLength = 0;
+ Status = Undi16SimpleNetworkIsr (This, &FrameLength, NULL, NULL, NULL, NULL);
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // See if the caller wants interrupt info.
+ //
+ if (InterruptStatus != NULL) {
+ *InterruptStatus = SimpleNetworkDevice->InterruptStatus;
+ SimpleNetworkDevice->InterruptStatus = 0;
+ }
+ //
+ // See if the caller wants transmit buffer status info.
+ //
+ if (TxBuf != NULL) {
+ *TxBuf = 0;
+ SimpleNetworkTransmitFifoRemove (&(SimpleNetworkDevice->TxBufferFifo), TxBuf);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ PXENV_UNDI_TRANSMIT_T XmitInfo;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BufferSize < SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ if (HeaderSize != 0) {
+ if (HeaderSize != SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddr == NULL || Protocol == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (
+ Buffer,
+ DestAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+ }
+
+ if (SrcAddr == NULL) {
+ SrcAddr = &SimpleNetworkDevice->SimpleNetworkMode.CurrentAddress;
+ }
+
+ CopyMem (
+ (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize,
+ SrcAddr,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ if (Protocol != NULL) {
+ *(UINT16 *) ((UINT8 *) Buffer + 2 * SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize) = (UINT16) (((*Protocol & 0xFF) << 8) | ((*Protocol >> 8) & 0xFF));
+ }
+ }
+ //
+ // See if the recycled transmit buffer FIFO is full.
+ // If it is full, then we can not transmit until the caller calls GetStatus() to pull
+ // off recycled transmit buffers.
+ //
+ if (SimpleNetworkTransmitFifoFull (&(SimpleNetworkDevice->TxBufferFifo))) {
+ return EFI_NOT_READY;
+ }
+ //
+ // Output debug trace message.
+ //
+ DEBUG ((DEBUG_NET, "Undi16SimpleNetworkTransmit\n\r "));
+
+ //
+ // Initialize UNDI WRITE parameter structure.
+ //
+ XmitInfo.Status = INIT_PXE_STATUS;
+ XmitInfo.Protocol = P_UNKNOWN;
+ XmitInfo.XmitFlag = XMT_DESTADDR;
+ XmitInfo.DestAddrOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr & 0x000f);
+ XmitInfo.DestAddrSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->TxDestAddr >> 4);
+ XmitInfo.TBDOffset = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit & 0x000f);
+ XmitInfo.TBDSegment = (UINT16) ((UINT32)(UINTN) SimpleNetworkDevice->Xmit >> 4);
+ XmitInfo.Reserved[0] = 0;
+ XmitInfo.Reserved[1] = 0;
+
+ CopyMem (
+ SimpleNetworkDevice->TxDestAddr,
+ Buffer,
+ SimpleNetworkDevice->SimpleNetworkMode.HwAddressSize
+ );
+
+ CopyMem (
+ SimpleNetworkDevice->TxRealModeMediaHeader,
+ Buffer,
+ SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize
+ );
+
+ SimpleNetworkDevice->Xmit->ImmedLength = (UINT16) SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize;
+
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen = (UINT16) (BufferSize - SimpleNetworkDevice->Xmit->ImmedLength);
+
+ CopyMem (
+ SimpleNetworkDevice->TxRealModeDataBuffer,
+ (UINT8 *) Buffer + SimpleNetworkDevice->SimpleNetworkMode.MediaHeaderSize,
+ SimpleNetworkDevice->Xmit->DataBlock[0].TDDataLen
+ );
+
+ //
+ // Make API call to UNDI TRANSMIT
+ //
+ XmitInfo.Status = 0;
+
+ Status = PxeUndiTransmit (SimpleNetworkDevice, &XmitInfo);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check the status code from the 16 bit UNDI ROM
+ //
+ switch (XmitInfo.Status) {
+ case PXENV_STATUS_OUT_OF_RESOURCES:
+ return EFI_NOT_READY;
+
+ case PXENV_STATUS_SUCCESS:
+ break;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Add address of Buffer to the recycled transmit buffer FIFO
+ //
+ SimpleNetworkTransmitFifoAdd (&(SimpleNetworkDevice->TxBufferFifo), Buffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN MediaAddrSize;
+ UINT8 ProtType;
+
+ if (This == NULL || BufferSize == NULL || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = Undi16SimpleNetworkIsr (
+ This,
+ BufferSize,
+ HeaderSize,
+ Buffer,
+ &ProtType,
+ NULL
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) == 0) {
+ return EFI_NOT_READY;
+
+ }
+
+ SimpleNetworkDevice->InterruptStatus &= ~EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT;
+
+ MediaAddrSize = This->Mode->HwAddressSize;
+
+ if (SrcAddr != NULL) {
+ CopyMem (SrcAddr, (UINT8 *) Buffer + MediaAddrSize, MediaAddrSize);
+ }
+
+ if (DestAddr != NULL) {
+ CopyMem (DestAddr, Buffer, MediaAddrSize);
+ }
+
+ if (Protocol != NULL) {
+ *((UINT8 *) Protocol) = *((UINT8 *) Buffer + (2 * MediaAddrSize) + 1);
+ *((UINT8 *) Protocol + 1) = *((UINT8 *) Buffer + (2 * MediaAddrSize));
+ }
+
+ DEBUG ((DEBUG_NET, "Packet Received: BufferSize=%d HeaderSize = %d\n", *BufferSize, *HeaderSize));
+
+ return Status;
+
+}
+//
+// WaitForPacket()
+//
+/**
+ wait for a packet to be received.
+
+ @param Event Event used with WaitForEvent() to wait for a packet to be received.
+ @param Context Event Context
+
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkWaitForPacket (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Someone is waiting on the receive packet event, if there's
+ // a packet pending, signal the event
+ //
+ if (!EFI_ERROR (Undi16SimpleNetworkCheckForPacket (Context))) {
+ gBS->SignalEvent (Event);
+ }
+}
+//
+// CheckForPacket()
+//
+/**
+ Check whether packet is ready for receive.
+
+ @param This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Receive data is ready.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCheckForPacket (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice;
+ UINTN FrameLength;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ SimpleNetworkDevice = EFI_SIMPLE_NETWORK_DEV_FROM_THIS (This);
+
+ if (SimpleNetworkDevice == NULL) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Verify that the current state of the adapter is valid for this call.
+ //
+ switch (SimpleNetworkDevice->SimpleNetworkMode.State) {
+ case EfiSimpleNetworkInitialized:
+ break;
+
+ case EfiSimpleNetworkStopped:
+ return EFI_NOT_STARTED;
+
+ case EfiSimpleNetworkStarted:
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+
+ FrameLength = 0;
+ Status = Undi16SimpleNetworkIsr (
+ This,
+ &FrameLength,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return ((SimpleNetworkDevice->InterruptStatus & EFI_SIMPLE_NETWORK_RECEIVE_INTERRUPT) != 0) ? EFI_SUCCESS : EFI_NOT_READY;
+}
+
+/**
+ Signal handlers for ExitBootServices event.
+
+ Clean up any Real-mode UNDI residue from the system
+
+ @param Event ExitBootServices event
+ @param Context
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // NOTE: This is not the only way to effect this cleanup. The prescribed mechanism
+ // would be to perform an UNDI STOP command. This strategam has been attempted
+ // but results in problems making some of the EFI core services from TPL_CALLBACK.
+ // This issue needs to be resolved, but the other alternative has been to perform
+ // the unchain logic explicitly, as done below.
+ //
+ RestoreCachedVectorAddress (0x1A);
+}
+
+/**
+ Allocate buffer below 1M for real mode.
+
+ @param NumPages The number pages want to be allocated.
+ @param Buffer On return, allocated buffer.
+
+ @return Status of allocating pages.
+**/
+EFI_STATUS
+BiosSnp16AllocatePagesBelowOneMb (
+ UINTN NumPages,
+ VOID **Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+
+ PhysicalAddress = 0x000fffff;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiRuntimeServicesData,
+ NumPages,
+ &PhysicalAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Buffer = (VOID *) (UINTN) PhysicalAddress;
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h
new file mode 100644
index 0000000000..b29059f685
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.h
@@ -0,0 +1,1655 @@
+/** @file
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BIOS_SNP_16_H_
+#define _BIOS_SNP_16_H_
+
+#include <Uefi.h>
+
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/NetworkInterfaceIdentifier.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/EventGroup.h>
+
+#include <IndustryStandard/Pci.h>
+
+#include "Pxe.h"
+
+//
+// BIOS Simple Network Protocol Device Structure
+//
+#define EFI_SIMPLE_NETWORK_DEV_SIGNATURE SIGNATURE_32 ('s', 'n', '1', '6')
+
+#define INIT_PXE_STATUS 0xabcd
+
+#define EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE 64
+
+typedef struct {
+ UINT32 First;
+ UINT32 Last;
+ VOID * Data[EFI_SIMPLE_NETWORK_MAX_TX_FIFO_SIZE];
+} EFI_SIMPLE_NETWORK_DEV_FIFO;
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_NETWORK_PROTOCOL SimpleNetwork;
+ EFI_SIMPLE_NETWORK_MODE SimpleNetworkMode;
+ EFI_NETWORK_INTERFACE_IDENTIFIER_PROTOCOL Nii;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ //
+ // Local Data for Simple Network Protocol interface goes here
+ //
+ BOOLEAN UndiLoaded;
+ EFI_EVENT EfiBootEvent;
+ EFI_EVENT LegacyBootEvent;
+ UINT16 PxeEntrySegment;
+ UINT16 PxeEntryOffset;
+ EFI_SIMPLE_NETWORK_DEV_FIFO TxBufferFifo;
+ EFI_DEVICE_PATH_PROTOCOL *BaseDevicePath;
+ PXE_T *Pxe; ///< Pointer to !PXE structure
+ PXENV_UNDI_GET_INFORMATION_T GetInformation; ///< Data from GET INFORMATION
+ PXENV_UNDI_GET_NIC_TYPE_T GetNicType; ///< Data from GET NIC TYPE
+ PXENV_UNDI_GET_NDIS_INFO_T GetNdisInfo; ///< Data from GET NDIS INFO
+ BOOLEAN IsrValid; ///< TRUE if Isr contains valid data
+ PXENV_UNDI_ISR_T Isr; ///< Data from ISR
+ PXENV_UNDI_TBD_T *Xmit; //
+ VOID *TxRealModeMediaHeader; ///< < 1 MB Size = 0x100
+ VOID *TxRealModeDataBuffer; ///< < 1 MB Size = GetInformation.MaxTranUnit
+ VOID *TxDestAddr; ///< < 1 MB Size = 16
+ UINT8 InterruptStatus; ///< returned/cleared by GetStatus, set in ISR
+ UINTN UndiLoaderTablePages;
+ UINTN DestinationDataSegmentPages;
+ UINTN DestinationStackSegmentPages;
+ UINTN DestinationCodeSegmentPages;
+ VOID *UndiLoaderTable;
+ VOID *DestinationDataSegment;
+ VOID *DestinationStackSegment;
+ VOID *DestinationCodeSegment;
+} EFI_SIMPLE_NETWORK_DEV;
+
+#define EFI_SIMPLE_NETWORK_DEV_FROM_THIS(a) \
+ CR (a, \
+ EFI_SIMPLE_NETWORK_DEV, \
+ SimpleNetwork, \
+ EFI_SIMPLE_NETWORK_DEV_SIGNATURE \
+ )
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosSnp16DriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosSnp16ComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2;
+
+
+//
+// Driver Binding Protocol functions
+//
+/**
+ Tests to see if this driver supports a given controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS The driver supports given controller.
+ @retval EFI_UNSUPPORT The driver doesn't support given controller.
+ @retval Other Other errors prevent driver finishing to test
+ if the driver supports given controller.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ Starts the Snp device controller
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param RemainingDevicePath A pointer to the remaining portion of a device path.
+
+ @retval EFI_SUCCESS - The device was started.
+ @retval EFI_DEVICE_ERROR - The device could not be started due to a device error.
+ @retval EFI_OUT_OF_RESOURCES - The request could not be completed due to a lack of resources.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+;
+
+/**
+ Stops the device by given device controller.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param Controller The handle of the controller to test.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed. May be NULL if
+ NumberOfChildren is 0.
+
+ @retval EFI_SUCCESS - The device was stopped.
+ @retval EFI_DEVICE_ERROR - The device could not be stopped due to a device error.
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16DriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+;
+
+//
+// Simple Network Protocol functions
+//
+/**
+ Call 16 bit UNDI ROM to start the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStart (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Call 16 bit UNDI ROM to stop the network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_DEVICE_ERROR Network interface has not be initialized.
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStop (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Initialize network interface
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtraRxBufferSize The size of extra request receive buffer.
+ @param ExtraTxBufferSize The size of extra request transmit buffer.
+
+ @retval EFI_DEVICE_ERROR Fail to execute 16 bit ROM call.
+ @retval EFI_SUCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkInitialize (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN ExtraRxBufferSize OPTIONAL,
+ IN UINTN ExtraTxBufferSize OPTIONAL
+ )
+;
+
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param ExtendedVerification Need extended verfication.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReset (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+;
+
+/**
+ Shutdown network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkShutdown (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Reset network interface.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Enable Enable mask value
+ @param Disable Disable mask value
+ @param ResetMCastFilter Whether reset multi cast filter or not
+ @param MCastFilterCnt Count of mutli cast filter for different MAC address
+ @param MCastFilter Buffer for mustli cast filter for different MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceiveFilters (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN UINT32 Enable,
+ IN UINT32 Disable,
+ IN BOOLEAN ResetMCastFilter,
+ IN UINTN MCastFilterCnt OPTIONAL,
+ IN EFI_MAC_ADDRESS * MCastFilter OPTIONAL
+ )
+;
+
+/**
+ Set new MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether reset station MAC address to permenent address
+ @param New A pointer to New address
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStationAddress (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN EFI_MAC_ADDRESS * New OPTIONAL
+ )
+;
+
+/**
+ Collect statistics.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param Reset Whether cleanup old statistics data.
+ @param StatisticsSize The buffer of statistics table.
+ @param StatisticsTable A pointer to statistics buffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkStatistics (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ IN BOOLEAN Reset,
+ IN OUT UINTN *StatisticsSize OPTIONAL,
+ OUT EFI_NETWORK_STATISTICS * StatisticsTable OPTIONAL
+ )
+;
+
+/**
+ Translate IP address to MAC address.
+
+ @param This A pointer to EFI_SIMPLE_NETWORK_PROTOCOL structure.
+ @param IPv6 IPv6 or IPv4
+ @param IP A pointer to given Ip address.
+ @param MAC On return, translated MAC address.
+
+ @retval EFI_INVALID_PARAMETER Invalid This paramter.
+ @retval EFI_INVALID_PARAMETER Invalid IP address.
+ @retval EFI_INVALID_PARAMETER Invalid return buffer for holding MAC address.
+ @retval EFI_UNSUPPORTED Do not support IPv6
+ @retval EFI_DEVICE_ERROR Network device has not been initialized.
+ @retval EFI_NOT_STARTED Network device has been stopped.
+ @retval EFI_DEVICE_ERROR Invalid status for network device
+ @retval EFI_SUCCESS Success operation.
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkMCastIpToMac (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN IPv6,
+ IN EFI_IP_ADDRESS *IP,
+ OUT EFI_MAC_ADDRESS *MAC
+ )
+;
+
+/**
+ Performs read and write operations on the NVRAM device attached to a
+ network interface.
+
+ @param This The protocol instance pointer.
+ @param ReadWrite TRUE for read operations, FALSE for write operations.
+ @param Offset Byte offset in the NVRAM device at which to start the read or
+ write operation. This must be a multiple of NvRamAccessSize and
+ less than NvRamSize.
+ @param BufferSize The number of bytes to read or write from the NVRAM device.
+ This must also be a multiple of NvramAccessSize.
+ @param Buffer A pointer to the data buffer.
+
+ @retval EFI_SUCCESS The NVRAM access was performed.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkNvData (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN BOOLEAN Write,
+ IN UINTN Offset,
+ IN UINTN BufferSize,
+ IN OUT VOID *Buffer
+ )
+;
+
+/**
+ Reads the current interrupt status and recycled transmit buffer status from
+ a network interface.
+
+ @param This The protocol instance pointer.
+ @param InterruptStatus A pointer to the bit mask of the currently active interrupts
+ If this is NULL, the interrupt status will not be read from
+ the device. If this is not NULL, the interrupt status will
+ be read from the device. When the interrupt status is read,
+ it will also be cleared. Clearing the transmit interrupt
+ does not empty the recycled transmit buffer array.
+ @param TxBuf Recycled transmit buffer address. The network interface will
+ not transmit if its internal recycled transmit buffer array
+ is full. Reading the transmit buffer does not clear the
+ transmit interrupt. If this is NULL, then the transmit buffer
+ status will not be read. If there are no transmit buffers to
+ recycle and TxBuf is not NULL, * TxBuf will be set to NULL.
+
+ @retval EFI_SUCCESS The status of the network interface was retrieved.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkGetStatus (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL * This,
+ OUT UINT32 *InterruptStatus OPTIONAL,
+ OUT VOID **TxBuf OPTIONAL
+ )
+;
+
+/**
+ Places a packet in the transmit queue of a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header to be filled in by
+ the Transmit() function. If HeaderSize is non-zero, then it
+ must be equal to This->Mode->MediaHeaderSize and the DestAddr
+ and Protocol parameters must not be NULL.
+ @param BufferSize The size, in bytes, of the entire packet (media header and
+ data) to be transmitted through the network interface.
+ @param Buffer A pointer to the packet (media header followed by data) to be
+ transmitted. This parameter cannot be NULL. If HeaderSize is zero,
+ then the media header in Buffer must already be filled in by the
+ caller. If HeaderSize is non-zero, then the media header will be
+ filled in by the Transmit() function.
+ @param SrcAddr The source HW MAC address. If HeaderSize is zero, then this parameter
+ is ignored. If HeaderSize is non-zero and SrcAddr is NULL, then
+ This->Mode->CurrentAddress is used for the source HW MAC address.
+ @param DestAddr The destination HW MAC address. If HeaderSize is zero, then this
+ parameter is ignored.
+ @param Protocol The type of header to build. If HeaderSize is zero, then this
+ parameter is ignored. See RFC 1700, section "Ether Types", for
+ examples.
+
+ @retval EFI_SUCCESS The packet was placed on the transmit queue.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkTransmit (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ IN UINTN HeaderSize,
+ IN UINTN BufferSize,
+ IN VOID *Buffer,
+ IN EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ IN EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ IN UINT16 *Protocol OPTIONAL
+ )
+;
+
+/**
+ Receives a packet from a network interface.
+
+ @param This The protocol instance pointer.
+ @param HeaderSize The size, in bytes, of the media header received on the network
+ interface. If this parameter is NULL, then the media header size
+ will not be returned.
+ @param BufferSize On entry, the size, in bytes, of Buffer. On exit, the size, in
+ bytes, of the packet that was received on the network interface.
+ @param Buffer A pointer to the data buffer to receive both the media header and
+ the data.
+ @param SrcAddr The source HW MAC address. If this parameter is NULL, the
+ HW MAC source address will not be extracted from the media
+ header.
+ @param DestAddr The destination HW MAC address. If this parameter is NULL,
+ the HW MAC destination address will not be extracted from the
+ media header.
+ @param Protocol The media header type. If this parameter is NULL, then the
+ protocol will not be extracted from the media header. See
+ RFC 1700 section "Ether Types" for examples.
+
+ @retval EFI_SUCCESS The received data was stored in Buffer, and BufferSize has
+ been updated to the number of bytes received.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+
+**/
+EFI_STATUS
+EFIAPI
+Undi16SimpleNetworkReceive (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This,
+ OUT UINTN *HeaderSize OPTIONAL,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer,
+ OUT EFI_MAC_ADDRESS *SrcAddr OPTIONAL,
+ OUT EFI_MAC_ADDRESS *DestAddr OPTIONAL,
+ OUT UINT16 *Protocol OPTIONAL
+ )
+;
+
+/**
+ wait for a packet to be received.
+
+ @param Event Event used with WaitForEvent() to wait for a packet to be received.
+ @param Context Event Context
+
+**/
+VOID
+EFIAPI
+Undi16SimpleNetworkWaitForPacket (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+;
+
+/**
+ Check whether packet is ready for receive.
+
+ @param This The protocol instance pointer.
+
+ @retval EFI_SUCCESS Receive data is ready.
+ @retval EFI_NOT_STARTED The network interface has not been started.
+ @retval EFI_NOT_READY The network interface is too busy to accept this transmit
+ request.
+ @retval EFI_BUFFER_TOO_SMALL The BufferSize parameter is too small.
+ @retval EFI_INVALID_PARAMETER One or more of the parameters has an unsupported value.
+ @retval EFI_DEVICE_ERROR The command could not be sent to the network interface.
+ @retval EFI_UNSUPPORTED This function is not supported by the network interface.
+**/
+EFI_STATUS
+Undi16SimpleNetworkCheckForPacket (
+ IN EFI_SIMPLE_NETWORK_PROTOCOL *This
+ )
+;
+
+/**
+ Cache Interrupt verctor address converted from IVT number.
+
+ @param VectorNumber IVT number
+
+ @retval EFI_SUCCESS Success to operation.
+**/
+EFI_STATUS
+CacheVectorAddress (
+ UINT8 VectorNumber
+ )
+;
+
+/**
+ Get interrupt vector address according to IVT number.
+
+ @param VectorNumber Given IVT number
+
+ @return cached interrupt vector address.
+**/
+EFI_STATUS
+RestoreCachedVectorAddress (
+ UINT8 VectorNumber
+ )
+;
+
+/**
+ If available, launch the BaseCode from a NIC option ROM.
+ This should install the !PXE and PXENV+ structures in memory for
+ subsequent use.
+
+
+ @param SimpleNetworkDevice Simple network device instance
+ @param RomAddress The ROM base address for NIC rom.
+
+ @retval EFI_NOT_FOUND The check sum does not match
+ @retval EFI_NOT_FOUND Rom ID offset is wrong
+ @retval EFI_NOT_FOUND No Rom ID structure is found
+**/
+EFI_STATUS
+LaunchBaseCode (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINTN RomAddress
+ )
+;
+
+/**
+ PXE
+ START UNDI
+ Op-Code: PXENV_START_UNDI (0000h)
+ Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is
+ responsible for saving the information it needs to communicate with the hardware.
+ This service is also responsible for hooking the Int 1Ah service routine
+ Note: This API service must be called only once during UNDI Option ROM boot.
+ The UNDI driver is responsible for saving this information and using it every time
+ PXENV_UNDI_STARTUP is called.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 AX;
+ UINT16 BX;
+ UINT16 DX;
+ UINT16 DI;
+ UINT16 ES;
+ } PXENV_START_UNDI_T;
+ Set before calling API service
+ AX, BX, DX, DI, ES: BIOS initialization parameter registers. These
+ fields should contain the same information passed to the option ROM
+ initialization routine by the Host System BIOS. Information about the
+ contents of these registers can be found in the [PnP], [PCI] and
+ [BBS] specifications.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeStartUndi (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_START_UNDI_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI STARTUP
+ Op-Code: PXENV_UNDI_STARTUP (0001h)
+ Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper
+ operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used
+ to complete this initialization. The rest of the UNDI APIs will not be available until this call has
+ been completed.
+ Note: PXENV_UNDI_STARTUP must not be called again without first calling
+ PXENV_UNDI_SHUTDOWN.
+ PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for
+ chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and
+ PXENV_STOP_UNDI API calls.
+ This service cannot be used in protected mode.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_STARTUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStartup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_STARTUP_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLEANUP
+ Op-Code: PXENV_UNDI_CLEANUP (0002h)
+ Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field
+ in the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be
+ made just before unloading the Universal NIC Driver. The rest of the API will not be available
+ after this call executes.
+ This service cannot be used in protected mode.
+ typedef struct {
+ PXENX_STATUS Status;
+ } PXENV_UNDI_CLEANUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiCleanup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEANUP_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI INITIALIZE
+ Op-Code: PXENV_UNDI_INITIALIZE (0003h)
+ Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter and programs it with default parameters. The default parameters used
+ are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the
+ receive and transmit units of the network adapter to readily receive or transmit packets. The
+ application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.
+ This call must be made by an application to establish an interface to the network adapter driver.
+ Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for
+ the Protocol field in the parameter structure.
+ typedef struct {
+ PXENV_STATUS Status;
+ ADDR32 ProtocolIni;
+ UINT8 reserved[8];
+ } PXENV_UNDI_INITIALIZE_T;
+ Set before calling API service
+ ProtocolIni: Physical address of a memory copy of the driver
+ module from the protocol.ini file obtained from the protocol manager
+ driver (refer to the NDIS 2.0 specification). This parameter is
+ supported for the universal NDIS driver to pass the information
+ contained in the protocol.ini file to the NIC driver for any specific
+ configuration of the NIC. (Note that the module identification in the
+ protocol.ini file was done by NDIS.) This value can be NULL for any
+ other application interfacing to the universal NIC driver
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitialize (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIALIZE_T *PxeUndiTable
+ )
+;
+
+/**
+ Wrapper routine for reset adapter.
+
+ PXE
+ UNDI RESET ADAPTER
+ Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)
+ Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to
+ Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the
+ network. This routine cannot be used to replace Initialize or Shutdown calls.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_RESET_T;
+
+ #define MAXNUM_MCADDR 8
+
+ typedef struct {
+ UINT16 MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+ } PXENV_UNDI_MCAST_ADDRESS_t;
+
+ Set before calling API service
+ R_Mcast_Buf: This is a structure of MCastAddrCount and
+ McastAddr.
+ MCastAddrCount: Number of multicast MAC addresses in the
+ buffer.
+ McastAddr: List of up to MAXNUM_MCADDR multicast MAC
+ addresses.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+ @param RxFilter Filter setting mask value for PXE recive .
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiResetNic (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_RESET_T *PxeUndiTable,
+ IN UINT16 RxFilter
+ )
+;
+
+/**
+ PXE
+ UNDI SHUTDOWN
+ Op-Code: PXENV_UNDI_SHUTDOWN (0005h)
+ Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.
+ Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the
+ Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_SHUTDOWN_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiShutdown (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SHUTDOWN_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI OPEN
+ Op-Code: PXENV_UNDI_OPEN (0006h)
+ Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call activates the adapter network connection and sets the adapter ready to accept packets
+ for transmit and receive.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 OpenFlag;
+ UINT16 PktFilter;
+ #define FLTR_DIRECTED 0x0001
+ #define FLTR_BRDCST 0x0002
+ #define FLTR_PRMSCS 0x0004
+ #define FLTR_SRC_RTG 0x0008
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_OPEN_T;
+ Set before calling API service
+ OpenFlag: This is an adapter specific input parameter. This is
+ supported for the universal NDIS 2.0 driver to pass in the open flags
+ provided by the protocol driver. (See the NDIS 2.0 specification.)
+ This can be zero.
+ PktFilter: Filter for receiving packets. This can be one, or more, of
+ the FLTR_xxx constants. Multiple values are arithmetically or-ed
+ together.
+ directed packets are packets that may come to your MAC address
+ or the multicast MAC address.
+ R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiOpen (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_OPEN_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLOSE
+ Op-Code: PXENV_UNDI_CLOSE (0007h)
+ Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or
+ received until the network adapter is open again.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLOSE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClose (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLOSE_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI TRANSMIT PACKET
+ Op-Code: PXENV_UNDI_TRANSMIT (0008h)
+ Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that
+ has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.
+ The status code must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call transmits a buffer to the network. The media header
+ for the packet can be filled by the calling protocol, but it might not be.
+ The network adapter driver will fill it if required by the values in the
+ parameter block. The packet is buffered for transmission provided there is
+ an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no
+ buffer is available the function returns PXENV_EXIT_FAILURE with a status
+ code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is
+ implementation-dependent. An interrupt is generated on completion of the
+ transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is
+ permitted in the context of a transmit complete interrupt.
+
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 Protocol;
+ #define P_UNKNOWN 0
+ #define P_IP 1
+ #define P_ARP 2
+ #define P_RARP 3
+ UINT8 XmitFlag;
+ #define XMT_DESTADDR 0x0000
+ #define XMT_BROADCAST 0x0001
+ SEGOFF16 DestAddr;
+ SEGOFF16 TBD;
+ UINT32 Reserved[2];
+ } t_PXENV_UNDI_TRANSMIT;
+
+ #define MAX_DATA_BLKS 8
+
+ typedef struct {
+ UINT16 ImmedLength;
+ SEGOFF16 Xmit;
+ UINT16 DataBlkCount;
+ struct DataBlk {
+ UINT8 TDPtrType;
+ UINT8 TDRsvdByte;
+ UINT16 TDDataLen;
+ SEGOFF16 TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+ } PXENV_UNDI_TBD_T
+
+ Set before calling API service
+ Protocol: This is the protocol of the upper layer that is calling UNDI
+ TRANSMIT call. If the upper layer has filled the media header, this
+ field must be P_UNKNOWN.
+ XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a
+ pointer to the destination media address in the field DestAddr. If
+ XMT_BROADCAST, the NIC driver fills the broadcast address for the
+ destination.
+ TBD: Segment:Offset address of the transmit buffer descriptor.
+ ImmedLength: Length of the immediate transmit buffer: Xmit.
+ Xmit: Segment:Offset of the immediate transmit buffer.
+ DataBlkCount: Number of blocks in this transmit buffer.
+ TDPtrType:
+ 0 => 32-bit physical address in TDDataPtr (not supported in this
+ version of PXE)
+ 1 => segment:offset in TDDataPtr which can be a real mode or 16-bit
+ protected mode pointer
+ TDRsvdByte: Reserved must be zero.
+ TDDatalen: Data block length in bytes.
+ TDDataPtr: Segment:Offset of the transmit block.
+ DataBlock: Array of transmit data blocks.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiTransmit (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_TRANSMIT_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)
+ Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call changes the current list of multicast addresses to the input list and resets the network
+ adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_SET_MCAST_ADDR_T;
+ Set before calling API service
+ R_Mcast_Buf: See description in the UNDI RESET ADAPTER
+ (0004h) API.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_MCAST_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET STATION ADDRESS
+ Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)
+ Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call sets the MAC address to be the input value and is called before opening the network
+ adapter. Later, the open call uses this variable as a temporary MAC address to program the
+ adapter individual address registers.
+ typedef struct {
+ PXENV_STATUS Status;
+ MAC_ADDR StationAddress;
+ } PXENV_UNDI_SET_STATION_ADDR_T;
+ Set before calling API service
+ StationAddress: Temporary MAC address to be used for
+ transmit and receive.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetStationAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_STATION_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI SET PACKET FILTER
+ Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)
+ Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with
+ the open call.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 filter;
+ } PXENV_UNDI_SET_PACKET_FILTER_T;
+ Set before calling API service
+ Filter: See the receive filter values in the UNDI OPEN
+ (0006h) API description.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetPacketFilter (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_PACKET_FILTER_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET INFORMATION
+ Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)
+ Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call copies the network adapter variables, including the MAC address, into the input buffer.
+ Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and
+ PXENV_UNDI_STARTUP have been issued. All other fields must be valid after
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been
+ called.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 BaseIo;
+ UINT16 IntNumber;
+ UINT16 MaxTranUnit;
+ UINT16 HwType;
+ #define ETHER_TYPE 1
+ #define EXP_ETHER_TYPE 2
+ #define IEEE_TYPE 6
+ #define ARCNET_TYPE 7
+ UINT16 HwAddrLen;
+ MAC_ADDR CurrentNodeAddress;
+ MAC_ADDR PermNodeAddress;
+ SEGSEL ROMAddress;
+ UINT16 RxBufCt;
+ UINT16 TxBufCt;
+ } PXENV_UNDI_GET_INFORMATION_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ BaseIO: Adapter base I/O address.
+ IntNumber: Adapter IRQ number.
+ MaxTranUnit: Adapter maximum transmit unit.
+ HWType: Type of protocol at the hardware level.
+ HWAddrLen: Length of the hardware address.
+ CurrentNodeAddress: Current hardware address.
+ PermNodeAddress: Permanent hardware address.
+ ROMAddress: Real mode ROM segment address.
+ RxBufCnt: Receive queue length.
+ TxBufCnt: Transmit queue length.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetInformation (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_INFORMATION_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET STATISTICS
+ Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)
+ Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call reads statistical information from the network adapter, and returns.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT32 XmtGoodFrames;
+ UINT32 RcvGoodFrames;
+ UINT32 RcvCRCErrors;
+ UINT32 RcvResourceErrors;
+ } PXENV_UNDI_GET_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ XmtGoodFrames: Number of successful transmissions.
+ RcvGoodFrames: Number of good frames received.
+ RcvCRCErrors: Number of frames received with CRC
+ error.
+ RcvResourceErrors: Number of frames discarded
+ because receive queue was full.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATISTICS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI CLEAR STATISTICS
+ Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)
+ Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call clears the statistical information from the network adapter.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLEAR_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClearStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEAR_STATISTICS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI INITIATE DIAGS
+ Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)
+ Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run
+ hardware diagnostics and to update its status information.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_INITIATE_DIAGS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitiateDiags (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIATE_DIAGS_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI FORCE INTERRUPT
+ Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)
+ Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the
+ network adapter driver usually queues the packet and calls the application's callback receive
+ routine with a pointer to the packet received. Then, the callback routine either can copy the packet
+ to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,
+ the network adapter driver does not remove it from the input queue. When the application wants to
+ copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive
+ interrupt.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_FORCE_INTERRUPT_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiForceInterrupt (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_FORCE_INTERRUPT_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)
+ Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call converts the given IP multicast address to a hardware multicast address.
+ typedef struct {
+ PXENV_STATUS Status;
+ IP4 InetAddr;
+ MAC_ADDR MediaAddr;
+ } PXENV_UNDI_GET_MCAST_ADDR_T;
+ Set before calling API service
+ InetAddr: IP multicast address.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ MediaAddr: MAC multicast address.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_MCAST_ADDR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET NIC TYPE
+ Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)
+ Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE_T parameter structure that has been initialized by
+ the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the
+ NIC information.
+ Description: This call, if successful, provides the NIC-specific information necessary to identify the network
+ adapter that is used to boot the system.
+ Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if
+ the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific
+ information can be obtained from the DHCPDISCOVER packet itself.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef {
+ PXENV_STATUS Status;
+ UINT8 NicType;
+ #define PCI_NIC 2
+ #define PnP_NIC 3
+ #define CardBus_NIC 4
+ Union {
+ Struct {
+ UINT16 Vendor_ID;
+ UINT16 Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT8 Rev;
+ UINT16 BusDevFunc;
+ UINT16 SubVendor_ID;
+ UINT16 SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ UINT32 EISA_Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT16 CardSelNum;
+ } pnp;
+ } info;
+ } PXENV_UNDI_GET_NIC_TYPE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ NICType: Type of NIC information stored in the parameter
+ structure.
+ Info: Information about the fields in this union can be found
+ in the [PnP] and [PCI] specifications
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNicType (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NIC_TYPE_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET IFACE INFO
+ Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)
+ Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the
+ interface specific information.
+ Description: This call, if successful, provides the network interface specific information such as the interface
+ type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the
+ universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.
+ Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the
+ universal driver to translate/convert this information into a format that is required in its specification
+ or to suit the expectation of the upper level protocol modules.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef struct {
+ PXENV_STATUS Status
+ UINT8 IfaceType[16];
+ UINT32 LinkSpeed;
+ UINT32 ServiceFlags;
+ UINT32 Reserved[4];
+ } PXENV_UNDI_GET_NDIS_INFO_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ IfaceType: Name of MAC type in ASCIIZ format. This is
+ used by the universal NDIS driver to specify its driver type
+ to the protocol driver.
+ LinkSpeed: Defined in the NDIS 2.0 specification.
+ ServiceFlags: Defined in the NDIS 2.0 specification.
+ Reserved: Must be zero.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NDIS_INFO_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+ Note: Interrupt Service Routine Operation:
+ In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the
+ application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR
+ API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing
+ (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).
+ When the Network Interface HW generates an interrupt the protocol driver interrupt service
+ routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then
+ calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for
+ the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface
+ level and read any status values required to further process the interrupt. UNDI must return as
+ quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or
+ PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the
+ interrupt was generated by this particular Network Interface or not.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was
+ not generated by our NIC, and interrupt processing is complete.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start
+ a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is
+ now complete.
+ The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to
+ PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and
+ return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the
+ first buffer pointer of that frame in the parameter block.
+ The protocol driver calls UNDI repeatedly with the FuncFlag equal to
+ PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received
+ frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l
+ remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous
+ buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter
+ block. Otherwise it must return the first buffer in the next frame.
+ If there is no received frame pending to be processed, UNDI processes the transmit completes and
+ if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the
+ NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.
+ IMPORTANT: It is possible for the protocol driver to be interrupted again while in the
+ strategy routine when the UNDI re-enables interrupts.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiIsr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_ISR_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ STOP UNDI
+ Op-Code: PXENV_STOP_UNDI (0015h)
+ Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This routine is responsible for unhooking the Int 1Ah service routine.
+ Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid
+ status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from
+ base memory. Also, UNDI must not be removed from base memory if BC is not removed from base
+ memory.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_STOP_UNDI_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStop (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_STOP_UNDI_T *PxeUndiTable
+ )
+;
+
+/**
+ PXE
+ UNDI GET STATE
+ Op-Code: PXENV_UNDI_GET_STATE (0015h)
+ Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state
+ constants
+ Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call
+ sequences
+ typedef struct {
+ #define PXE_UNDI_GET_STATE_STARTED 1
+ #define PXE_UNDI_GET_STATE_INITIALIZED 2
+ #define PXE_UNDI_GET_STATE_OPENED 3
+ PXENV_STATUS Status;
+ UINT8 UNDIstate;
+ } PXENV_UNDI_GET_STATE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ State: See definitions of the state constants.
+ Note. UNDI implementation is responsible for maintaining
+ internal state machine.
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetState (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATE_T *PxeUndiTable
+ )
+;
+
+/**
+ Effect the Far Call into the PXE Layer
+
+ Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
+ services will not work, unless there are three 16-bit parameters pushed onto the stack.
+ push DS ;Far pointer to parameter structure
+ push offset pxe_data_call_struct ;is pushed onto stack.
+ push Index ;UINT16 is pushed onto stack.
+ call dword ptr (s_PXE ptr es:[di]).EntryPointSP
+ add sp, 6 ;Caller cleans up stack.
+
+ @param SimpleNetworkDevice Device instance for simple network
+ @param Table Point to parameter/retun value table for legacy far call
+ @param TableSize The size of paramter/return value table
+ @param CallIndex The index of legacy call.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+MakePxeCall (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT VOID *Table,
+ IN UINTN TableSize,
+ IN UINT16 CallIndex
+ )
+;
+
+/**
+ Allocate buffer below 1M for real mode.
+
+ @param NumPages The number pages want to be allocated.
+ @param Buffer On return, allocated buffer.
+
+ @return Status of allocating pages.
+**/
+EFI_STATUS
+BiosSnp16AllocatePagesBelowOneMb (
+ UINTN NumPages,
+ VOID **Buffer
+ )
+;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.uni
new file mode 100644
index 0000000000..7bfc6abbc4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16Extra.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16Extra.uni
new file mode 100644
index 0000000000..273cbec3a0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/BiosSnp16Extra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c
new file mode 100644
index 0000000000..488c597517
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/ComponentName.c
@@ -0,0 +1,309 @@
+/** @file
+
+Copyright (c) 1999 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosSnp16ComponentName = {
+ BiosSnp16ComponentNameGetDriverName,
+ BiosSnp16ComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosSnp16ComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosSnp16ComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosSnp16ComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosSnp16DriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[UNDI] Simple Network Protocol Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosSnp16DriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosSnp16ComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosSnp16ComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
new file mode 100644
index 0000000000..243048c551
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Misc.c
@@ -0,0 +1,962 @@
+/** @file
+ Helper Routines that use a PXE-enabled NIC option ROM.
+
+Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+#define TO_SEGMENT(x) ((UINT16) (RShiftU64 ((UINT32)(UINTN) (x), 4) & 0xF000))
+#define TO_OFFSET(x) ((UINT16) ((UINT32)(UINTN) (x) & 0xFFFF))
+#define PARAGRAPH_SIZE 0x10
+#define IVT_BASE 0x00000000
+
+#pragma pack(1)
+typedef struct {
+ UINT16 Signature; ///< 0xaa55
+ UINT8 ROMlength; ///< size of this ROM in 512 byte blocks
+ UINT8 InitEntryPoint[4]; ///< a jump to the initialization routine
+ UINT8 Reserved[0xf]; ///< various
+ UINT16 PxeRomIdOffset; ///< offset of UNDI, $BC$, or BUSD ROM ID structure
+ UINT16 PcirHeaderOffset; ///< offset of PCI Expansion Header
+ UINT16 PnpHeaderOffset; ///< offset of Plug and Play Expansion Header
+} OPTION_ROM_HEADER;
+#pragma pack()
+
+UINT32 CachedVectorAddress[0x100];
+
+/**
+ Cache Interrupt verctor address converted from IVT number.
+
+ @param VectorNumber IVT number
+
+ @retval EFI_SUCCESS Success to operation.
+**/
+EFI_STATUS
+CacheVectorAddress (
+ UINT8 VectorNumber
+ )
+{
+ UINT32 *Address;
+
+ Address = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);
+ CachedVectorAddress[VectorNumber] = *Address;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get interrupt vector address according to IVT number.
+
+ @param VectorNumber Given IVT number
+
+ @return cached interrupt vector address.
+**/
+EFI_STATUS
+RestoreCachedVectorAddress (
+ UINT8 VectorNumber
+ )
+{
+ UINT32 *Address;
+
+ Address = (UINT32 *)(UINTN) (IVT_BASE + VectorNumber * 4);
+ *Address = CachedVectorAddress[VectorNumber];
+ return EFI_SUCCESS;
+}
+
+/**
+ Print Undi loader table.
+
+ @param UndiLoaderStructure Point to Undi Loader table structure.
+
+**/
+VOID
+Print_Undi_Loader_Table (
+ VOID *UndiLoaderStructure
+ )
+{
+ UNDI_LOADER_T *DisplayPointer;
+
+ DisplayPointer = (UNDI_LOADER_T *) UndiLoaderStructure;
+
+ DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
+ DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) UndiLoaderStructure));
+
+ DEBUG ((DEBUG_NET, "\n\rStatus = 0x%X\n\r", DisplayPointer->Status));
+ DEBUG ((DEBUG_NET, "\t_AX_= 0x%X\n\r", DisplayPointer->Ax));
+ DEBUG ((DEBUG_NET, "\t_BX_= 0x%X\n\r", DisplayPointer->Bx));
+ DEBUG ((DEBUG_NET, "\t_DX_= 0x%X\n\r", DisplayPointer->Dx));
+ DEBUG ((DEBUG_NET, "\t_DI_= 0x%X\n\r", DisplayPointer->Di));
+ DEBUG ((DEBUG_NET, "\t_ES_= 0x%X\n\r", DisplayPointer->Es));
+ DEBUG ((DEBUG_NET, "\tUNDI_DS= 0x%X\n\r", DisplayPointer->Undi_Ds));
+ DEBUG ((DEBUG_NET, "\tUNDI_CS= 0x%X\n\r", DisplayPointer->Undi_Cs));
+ DEBUG ((DEBUG_NET, "\tPXEptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Segment));
+ DEBUG ((DEBUG_NET, "\tPXEptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXEptr.Offset));
+ DEBUG ((DEBUG_NET, "\tPXENVptr:SEG= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Segment));
+ DEBUG ((DEBUG_NET, "\tPXENVptr:OFF= 0x%X\n\r", (UINT16) DisplayPointer->PXENVptr.Offset));
+}
+
+/**
+ Simple table dumper. The ROMID table is necessary in order to effect
+ the "Early UNDI" trick. Herein, the UNDI layer can be loaded in the
+ pre-boot phase without having to download a Network Boot Program
+ across the wire. It is required in the implementation in that we
+ are not using PXE.
+
+ @param RomIDStructure Point to RomID structure.
+
+**/
+VOID
+Print_ROMID_Table (
+ IN VOID *RomIDStructure
+ )
+{
+ UNDI_ROMID_T *DisplayPointer;
+
+ DisplayPointer = (UNDI_ROMID_T *) RomIDStructure;
+
+ DEBUG ((DEBUG_NET, "Before Parsing the table contents, the table itself lives\n"));
+ DEBUG ((DEBUG_NET, "\tat the address 0x%X\n\r", (UINT32)(UINTN) RomIDStructure));
+
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rROMID %c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3])
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "Length of this structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
+ DisplayPointer->StructCksum)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Structure format revision number= 0x%X\n\r",
+ DisplayPointer->StructRev)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "API Revision number = 0x%X 0x%X 0x%X\n\r",
+ DisplayPointer->UNDI_Rev[0],
+ DisplayPointer->UNDI_Rev[1],
+ DisplayPointer->UNDI_Rev[2])
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Offset of UNDI loader routine in the option ROM image= 0x%X\n\r",
+ DisplayPointer->UNDI_Loader)
+ );
+ DEBUG ((DEBUG_NET, "From the data above, the absolute entry point of the UNDI loader is\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\tat address 0x%X\n\r",
+ (UINT32) (DisplayPointer->UNDI_Loader + ((UINT32) (UINTN)(DisplayPointer - 0x20) & 0xFFFF0)))
+ );
+ DEBUG ((DEBUG_NET, "Minimum stack segment size, in bytes,\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "needed to load and run the UNDI= 0x%X \n\r",
+ DisplayPointer->StackSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "UNDI runtime code and data = 0x%X\n\r",
+ DisplayPointer->DataSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Segment size = 0x%X\n\r",
+ DisplayPointer->CodeSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rBus Type = %c%c%c%c\n\r",
+ DisplayPointer->BusType[0],
+ DisplayPointer->BusType[1],
+ DisplayPointer->BusType[2],
+ DisplayPointer->BusType[3])
+ );
+}
+
+/**
+ Print PXE table.
+
+ @param PxeTable Point to PXE table structure
+
+**/
+VOID
+Print_PXE_Table (
+ IN VOID* PxeTable
+ )
+{
+ PXE_T *DisplayPointer;
+ UINTN Index;
+ UINT8 *Dptr;
+
+ DisplayPointer = (PXE_T *) PxeTable;
+ Dptr = (UINT8 *) PxeTable;
+
+ DEBUG ((DEBUG_NET, "This is the PXE table at address 0x%X\n\r", PxeTable));
+
+ DEBUG ((DEBUG_NET, "A dump of the 0x%X bytes is:\n\r", sizeof (PXE_T)));
+
+ for (Index = 0; Index < sizeof (PXE_T); Index++) {
+ if ((Index % 0x10) == 0) {
+ DEBUG ((DEBUG_NET, "\t\n\r"));
+ }
+
+ DEBUG ((DEBUG_NET, " 0x%X ", *Dptr++));
+ }
+
+ DEBUG ((DEBUG_NET, "\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rPXE %c%c%c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3])
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Length of this structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Use to make byte checksum of this structure == zero is = 0x%X\n\r",
+ DisplayPointer->StructCksum)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Structure format revision number = 0x%X\n\r",
+ DisplayPointer->StructRev)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Must be zero, is equal to 0x%X\n\r",
+ DisplayPointer->Reserved1)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Far pointer to UNDI ROMID = 0x%X\n\r",
+ (UINT32) (DisplayPointer->Undi.Segment << 0x4 | DisplayPointer->Undi.Offset))
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Far pointer to base-code ROMID = 0x%X\n\r",
+ (UINT32) ((DisplayPointer->Base.Segment << 0x04) | DisplayPointer->Base.Offset))
+ );
+ DEBUG ((DEBUG_NET, "16bit stack segment API entry point. This will be seg:off in \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "real mode and sel:off in 16:16 protected mode = 0x%X:0x%X\n\r",
+ DisplayPointer->EntryPointSP.Segment,
+ DisplayPointer->EntryPointSP.Offset)
+ );
+
+ DEBUG ((DEBUG_NET, "\n\tNOTE to the implementer\n\tThis is the entry to use for call-ins\n\r"));
+
+ DEBUG ((DEBUG_NET, "32bit stack Segment API entry point. This will be sel:off. \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "In real mode, sel == 0 = 0x%X:0x%X\n\r",
+ DisplayPointer->EntryPointESP.Segment,
+ DisplayPointer->EntryPointESP.Offset)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Reserved2 value, must be zero, is equal to 0x%X\n\r",
+ DisplayPointer->Reserved2)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Number of segment descriptors in this structur = 0x%X\n\r",
+ (UINT8) DisplayPointer->SegDescCnt)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "First segment descriptor in GDT assigned to PXE = 0x%X\n\r",
+ (UINT16) DisplayPointer->FirstSelector)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->Stack.Seg_Addr,
+ (UINT32) DisplayPointer->Stack.Phy_Addr,
+ (UINT16) DisplayPointer->Stack.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The UNDIData is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDIData.Seg_Addr,
+ (UINT32) DisplayPointer->UNDIData.Phy_Addr,
+ (UINT16) DisplayPointer->UNDIData.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The UNDICodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDICode.Seg_Addr,
+ (UINT32) DisplayPointer->UNDICode.Phy_Addr,
+ (UINT16) DisplayPointer->UNDICode.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The Stack is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->UNDICodeWrite.Seg_Addr,
+ (UINT32) DisplayPointer->UNDICodeWrite.Phy_Addr,
+ (UINT16) DisplayPointer->UNDICodeWrite.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_Data is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_Data.Seg_Addr,
+ (UINT32) DisplayPointer->BC_Data.Phy_Addr,
+ (UINT16) DisplayPointer->BC_Data.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_Code is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_Code.Seg_Addr,
+ (UINT32) DisplayPointer->BC_Code.Phy_Addr,
+ (UINT16) DisplayPointer->BC_Code.Seg_Size)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The BC_CodeWrite is \n\r\tSegment Addr = 0x%X\n\r\tPhysical Addr = 0x%X\n\r\tSeg Size = 0x%X\n\r",
+ (UINT16) DisplayPointer->BC_CodeWrite.Seg_Addr,
+ (UINT32) DisplayPointer->BC_CodeWrite.Phy_Addr,
+ (UINT16) DisplayPointer->BC_CodeWrite.Seg_Size)
+ );
+}
+
+/**
+ Print PXENV table.
+
+ @param PxenvTable Point to PXENV
+
+**/
+VOID
+Print_PXENV_Table (
+ IN VOID *PxenvTable
+ )
+{
+ PXENV_T *DisplayPointer;
+
+ DisplayPointer = (PXENV_T *) PxenvTable;
+
+ DEBUG (
+ (DEBUG_NET,
+ "\n\rPXENV+ %c%c%c%c%c%c\n\r",
+ DisplayPointer->Signature[0],
+ DisplayPointer->Signature[1],
+ DisplayPointer->Signature[2],
+ DisplayPointer->Signature[3],
+ DisplayPointer->Signature[4],
+ DisplayPointer->Signature[5])
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "PXE version number. \n\r\tLSB is minor version. \n\r\tMSB is major version = 0x%X\n\r",
+ DisplayPointer->Version)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Length of PXE-2.0 Entry Point structure in bytes = 0x%X\n\r",
+ DisplayPointer->StructLength)
+ );
+ DEBUG ((DEBUG_NET, "Used to make structure checksum equal zero is now = 0x%X\n\r", DisplayPointer->StructCksum));
+ DEBUG ((DEBUG_NET, "Real mode API entry point segment:Offset. = 0x%X\n\r", DisplayPointer->RMEntry));
+ DEBUG ((DEBUG_NET, "Protected mode API entry point = 0x%X\n\r", DisplayPointer->PMEntryOff));
+ DEBUG ((DEBUG_NET, " segment:Offset. This will always be zero. \n\r"));
+ DEBUG ((DEBUG_NET, "Protected mode API calls = 0x%X\n\r", DisplayPointer->PMEntrySeg));
+ DEBUG ((DEBUG_NET, "Real mode stack segment = 0x%X\n\r", DisplayPointer->StackSeg));
+ DEBUG ((DEBUG_NET, "Stack segment size in bytes = 0x%X\n\r", DisplayPointer->StackSize));
+ DEBUG ((DEBUG_NET, "Real mode base-code code segment = 0x%X\n\r", DisplayPointer->BaseCodeSeg));
+ DEBUG ((DEBUG_NET, "Base-code code segment size = 0x%X\n\r", DisplayPointer->BaseCodeSize));
+ DEBUG ((DEBUG_NET, "Real mode base-code data segment = 0x%X\n\r", DisplayPointer->BaseDataSeg));
+ DEBUG ((DEBUG_NET, "Base-code data segment size = 0x%X\n\r", DisplayPointer->BaseDataSize));
+
+ DEBUG (
+ (DEBUG_NET,
+ "UNDI code segment size in bytes = 0x%X\n\r",
+ DisplayPointer->UNDICodeSize)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "Real mode segment:Offset pointer \n\r\tto PXE Runtime ID structure, address = 0x%X\n\r",
+ DisplayPointer->RuntimePtr)
+ );
+ DEBUG (
+ (
+ DEBUG_NET,
+ "From above, we have a linear address of 0x%X\n\r",
+ (UINT32)
+ (
+ ((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF) +
+ (((UINT32)(UINTN)(DisplayPointer->RuntimePtr) & 0xFFFF0000) >> 12)
+ )
+ )
+ );
+}
+
+
+#define OPTION_ROM_PTR ((OPTION_ROM_HEADER *) RomAddress)
+
+/**
+ If available, launch the BaseCode from a NIC option ROM.
+ This should install the !PXE and PXENV+ structures in memory for
+ subsequent use.
+
+
+ @param SimpleNetworkDevice Simple network device instance
+ @param RomAddress The ROM base address for NIC rom.
+
+ @retval EFI_NOT_FOUND The check sum does not match
+ @retval EFI_NOT_FOUND Rom ID offset is wrong
+ @retval EFI_NOT_FOUND No Rom ID structure is found
+**/
+EFI_STATUS
+LaunchBaseCode (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ UINTN RomAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET InOutRegs;
+ UNDI_ROMID_T *RomIdTableAddress;
+ UNDI_LOADER_T *UndiLoaderTable;
+ UINT16 Segment;
+ UINT16 *StackPointer;
+ VOID *Buffer;
+ UINTN Size;
+ PXE_T *Pxe;
+ UINT32 RomLength;
+ UINTN PciSegment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ BOOLEAN ThunkFailed;
+
+ DEBUG ((DEBUG_NET, "\n\r\n\rCheck for the UNDI ROMID Signature\n\r"));
+
+ //
+ // paranoia - check structures for validity
+ //
+ RomLength = OPTION_ROM_PTR->ROMlength << 9;
+ if (CalculateSum8 ((UINT8 *) RomAddress, RomLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "ROM Header Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ RomIdTableAddress = (UNDI_ROMID_T *) (RomAddress + OPTION_ROM_PTR->PxeRomIdOffset);
+
+ if ((UINTN) (OPTION_ROM_PTR->PxeRomIdOffset + RomIdTableAddress->StructLength) > RomLength) {
+ DEBUG ((DEBUG_ERROR, "ROM ID Offset Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // see if this is a header for an UNDI ROM ID structure (vs. a $BC$ or BUSD type)
+ //
+ if (CompareMem (RomIdTableAddress->Signature, UNDI_ROMID_SIG, sizeof RomIdTableAddress->Signature) != 0) {
+ DEBUG ((DEBUG_ERROR, "No ROM ID Structure found....\n\r"));
+ return EFI_NOT_FOUND;
+ //
+ // its not - keep looking
+ //
+ }
+
+ if (CalculateSum8 ((UINT8 *) RomIdTableAddress, RomIdTableAddress->StructLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "ROM ID Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ Print_ROMID_Table (RomIdTableAddress);
+
+ DEBUG (
+ (DEBUG_NET,
+ "The ROM ID is located at 0x%X\n\r",
+ RomIdTableAddress)
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "With an UNDI Loader located at 0x%X\n\r",
+ RomAddress + RomIdTableAddress->UNDI_Loader)
+ );
+
+ //
+ // found an UNDI ROM ID structure
+ //
+ SimpleNetworkDevice->Nii.ImageAddr = RomAddress;
+ SimpleNetworkDevice->Nii.ImageSize = RomLength;
+ SimpleNetworkDevice->Nii.MajorVer = RomIdTableAddress->UNDI_Rev[2];
+ SimpleNetworkDevice->Nii.MinorVer = RomIdTableAddress->UNDI_Rev[1];
+
+ DEBUG ((DEBUG_NET, "Allocate area for the UNDI_LOADER_T structure\n\r"));
+ //
+ // Allocate 1 page below 1MB to put real mode thunk code in
+ //
+ // Undi Loader Table is a PXE Specification prescribed data structure
+ // that is used to transfer information into and out of the Undi layer.
+ // Note how it must be located below 1 MB.
+ //
+ SimpleNetworkDevice->UndiLoaderTablePages = EFI_SIZE_TO_PAGES (PARAGRAPH_SIZE + sizeof (UNDI_LOADER_T));
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->UndiLoaderTablePages,
+ &SimpleNetworkDevice->UndiLoaderTable
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ UndiLoaderTable = SimpleNetworkDevice->UndiLoaderTable;
+
+ DEBUG ((DEBUG_NET, "Allocate area for the real-mode stack whose sole purpose\n\r"));
+ DEBUG ((DEBUG_NET, "in life right now is to store a SEG:OFFSET combo pair that\n\r"));
+ DEBUG ((DEBUG_NET, "points to an Undi_Loader_t table structure\n\r"));
+
+ Size = 0x100;
+ Status = gBS->AllocatePool (EfiLoaderData, Size, &Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Now we want to put a pointer to the Under Loader Table in our MemPage
+ // Buffer. This will be the argument stack for the call into the Undi Loader
+ //
+ StackPointer = (UINT16 *) Buffer;
+ *StackPointer++ = TO_OFFSET (UndiLoaderTable);
+ //
+ // push the OFFSET
+ //
+ *StackPointer++ = TO_SEGMENT (UndiLoaderTable);
+ //
+ // push the SEGMENT
+ //
+ StackPointer = (UINT16 *) Buffer;
+ //
+ // reset the stack pointer
+ //
+ DEBUG (
+ (DEBUG_NET,
+ "After the fixups, the stack pointer is 0x%X\n\r",
+ (UINT64)(UINTN) StackPointer)
+ );
+
+ //
+ // Allocate memory for the Deployed UNDI.
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationDataSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->DataSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationDataSegmentPages,
+ &SimpleNetworkDevice->DestinationDataSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+
+ UndiLoaderTable->Undi_Ds = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationDataSegment >> 4);
+
+ //
+ // Allocate memory for the Deployed UNDI stack
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationStackSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->StackSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationStackSegmentPages,
+ &SimpleNetworkDevice->DestinationStackSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+ //
+ // Allocate memory for the Deployed UNDI.
+ // The UNDI is essentially telling us how much space it needs, and
+ // it is up to the EFI driver to allocate sufficient, boot-time
+ // persistent resources for the call
+ //
+ SimpleNetworkDevice->DestinationCodeSegmentPages = EFI_SIZE_TO_PAGES (RomIdTableAddress->CodeSize);
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ SimpleNetworkDevice->DestinationCodeSegmentPages,
+ &SimpleNetworkDevice->DestinationCodeSegment
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+
+ UndiLoaderTable->Undi_Cs = (UINT16) ((UINTN) SimpleNetworkDevice->DestinationCodeSegment >> 4);
+
+ //
+ // these are in the Input and Output Parameter to be sent to the UNDI Loader code
+ //
+ UndiLoaderTable->Status = 0xAA55;
+ //
+ // -------------------- Changed by Michael_Huang@3Com.com -----------------
+ // UndiLoaderTable->_AX is AX value when UNDI ROM is initialized by BIOS, it is the PCI bus device
+ // function of the NIC. Please refer to PXE Spec for detail info.
+ // old code is:
+ // UndiLoaderTable->Ax = 0x0;
+ // -----------------------------------------------------------------------
+ //
+ SimpleNetworkDevice->PciIo->GetLocation (
+ SimpleNetworkDevice->PciIo,
+ &PciSegment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ UndiLoaderTable->Ax = (UINT16) ((Bus << 0x8) | (Device << 0x3) | (Function));
+ UndiLoaderTable->Bx = 0x0;
+ UndiLoaderTable->Dx = 0x0;
+ UndiLoaderTable->Di = 0x0;
+ UndiLoaderTable->Es = 0x0;
+
+ //
+ // set these OUT values to zero in order to ensure that
+ // uninitialized memory is not mistaken for display data
+ //
+ UndiLoaderTable->PXEptr.Offset = 0;
+ UndiLoaderTable->PXEptr.Segment = 0;
+ UndiLoaderTable->PXENVptr.Segment = 0;
+ UndiLoaderTable->PXENVptr.Offset = 0;
+
+ DEBUG (
+ (DEBUG_INIT,
+ "The NIC is located at Bus 0x%X, Device 0x%X, Function 0x%X\n\r",
+ Bus,
+ Device,
+ Function)
+ );
+
+ //
+ // These are the values that set up the ACTUAL IA32 machine state, whether in
+ // Real16 in EFI32 or the IVE for IA64
+ // register values are unused except for CS:IP and SS:SP
+ //
+ InOutRegs.X.AX = 0;
+ InOutRegs.X.BX = 0;
+ InOutRegs.X.CX = 0;
+ InOutRegs.X.DX = 0;
+ InOutRegs.X.SI = 0;
+ InOutRegs.X.DI = 0;
+ InOutRegs.X.BP = 0;
+ InOutRegs.X.DS = 0;
+ InOutRegs.X.ES = 0;
+ //
+ // just to be clean
+ //
+ DEBUG ((DEBUG_NET, "The way this game works is that the SS:SP +4 should point\n\r"));
+ DEBUG ((DEBUG_NET, "to the contents of the UndiLoaderTable\n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "The Undi Loader Table is at address = 0x%X\n\r",
+ (UINT32)(UINTN) UndiLoaderTable)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "The segment and offsets are 0x%X and 0x%X, resp\n",
+ TO_SEGMENT (UndiLoaderTable),
+ TO_OFFSET (UndiLoaderTable))
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "The Linear Address of the UNDI Loader entry is 0x%X\n",
+ RomAddress + RomIdTableAddress->UNDI_Loader)
+ );
+
+ DEBUG (
+ (DEBUG_NET,
+ "The Address offset of the UNDI Loader entry is 0x%X\n",
+ RomIdTableAddress->UNDI_Loader)
+ );
+
+ DEBUG ((DEBUG_NET, "Before the call, we have...\n\r"));
+ Print_Undi_Loader_Table (UndiLoaderTable);
+
+ Segment = ((UINT16) (RShiftU64 (RomAddress, 4) & 0xFFFF));
+ DEBUG ((DEBUG_NET, "The Segment of the call is 0x%X\n\r", Segment));
+
+ //
+ // make the call into the UNDI Code
+ //
+ DEBUG ((DEBUG_INIT, "Make the call into the UNDI code now\n\r"));
+
+ DEBUG ((DEBUG_NET, "\nThe 20-BIt address of the Call, and the location \n\r"));
+ DEBUG ((DEBUG_NET, "\twhere we should be able to set a breakpoint is \n\r"));
+ DEBUG (
+ (DEBUG_NET,
+ "\t\t0x%X, from SEG:OFF 0x%X:0x%X\n\r\n\r",
+ Segment * 0x10 + RomIdTableAddress->UNDI_Loader,
+ Segment,
+ RomIdTableAddress->UNDI_Loader)
+ );
+
+ ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
+ SimpleNetworkDevice->LegacyBios,
+ Segment, // Input segment
+ (UINT16) RomIdTableAddress->UNDI_Loader, // Offset
+ &InOutRegs, // Ptr to Regs
+ Buffer, // Reference to Stack
+ Size // Size of the Stack
+ );
+ if (ThunkFailed) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG (
+ (DEBUG_NET,
+ "The return code UndiLoaderTable->Status is = 0x%X\n\r",
+ UndiLoaderTable->Status)
+ );
+ DEBUG (
+ (DEBUG_NET,
+ "This error code should match eax, which is = 0x%X\n\r",
+ InOutRegs.X.AX)
+ );
+
+ if ((UndiLoaderTable->Status != 0) || (InOutRegs.X.AX != PXENV_EXIT_SUCCESS)) {
+ DEBUG ((DEBUG_NET, "LaunchBaseCode exits with error, RomAddress = 0x%X\n\r", RomAddress));
+ return EFI_ABORTED;
+ }
+
+ DEBUG ((DEBUG_NET, "Now returned from the UNDI code\n\r"));
+
+ DEBUG ((DEBUG_NET, "After the call, we have...\n\r"));
+ Print_Undi_Loader_Table (UndiLoaderTable);
+
+ DEBUG ((DEBUG_NET, "Display the PXENV+ and !PXE tables exported by NIC\n\r"));
+ Print_PXENV_Table ((VOID *)(UINTN)((UndiLoaderTable->PXENVptr.Segment << 4) | UndiLoaderTable->PXENVptr.Offset));
+ Print_PXE_Table ((VOID *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset));
+
+ Pxe = (PXE_T *)(UINTN)((UndiLoaderTable->PXEptr.Segment << 4) + UndiLoaderTable->PXEptr.Offset);
+ SimpleNetworkDevice->Nii.Id = (UINT64)(UINTN) Pxe;
+
+ gBS->FreePool (Buffer);
+
+ //
+ // paranoia - make sure a valid !PXE structure
+ //
+ if (CompareMem (Pxe->Signature, PXE_SIG, sizeof Pxe->Signature) != 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE Structure not found....\n\r"));
+ return EFI_NOT_FOUND;
+ //
+ // its not - keep looking
+ //
+ }
+
+ if (CalculateSum8 ((UINT8 *) Pxe, Pxe->StructLength) != 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE Checksum Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (Pxe->StructLength < (UINT8 *) &Pxe->FirstSelector - (UINT8 *) Pxe->Signature) {
+ DEBUG ((DEBUG_ERROR, "!PXE Length Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ if ((((UINTN) Pxe->Undi.Segment) << 4) + Pxe->Undi.Offset != (UINTN) RomIdTableAddress) {
+ DEBUG ((DEBUG_ERROR, "!PXE RomId Address Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+ //
+ // This is the magic to bind the global PXE interface
+ // This dirtiness is for non-protocol shrouded access
+ //
+ SimpleNetworkDevice->PxeEntrySegment = Pxe->EntryPointSP.Segment;
+
+ if (SimpleNetworkDevice->PxeEntrySegment == 0) {
+ DEBUG ((DEBUG_ERROR, "!PXE EntryPointSP segment Error\n\r"));
+ return EFI_NOT_FOUND;
+ }
+
+ SimpleNetworkDevice->PxeEntryOffset = Pxe->EntryPointSP.Offset;
+
+ DEBUG (
+ (
+ DEBUG_NET, "The entry point is 0x%X:0x%X\n\r", SimpleNetworkDevice->PxeEntrySegment, SimpleNetworkDevice->
+ PxeEntryOffset
+ )
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Effect the Far Call into the PXE Layer
+
+ Note: When using a 32-bit stack segment do not push 32-bit words onto the stack. The PXE API
+ services will not work, unless there are three 16-bit parameters pushed onto the stack.
+ push DS ;Far pointer to parameter structure
+ push offset pxe_data_call_struct ;is pushed onto stack.
+ push Index ;UINT16 is pushed onto stack.
+ call dword ptr (s_PXE ptr es:[di]).EntryPointSP
+ add sp, 6 ;Caller cleans up stack.
+
+ @param SimpleNetworkDevice Device instance for simple network
+ @param Table Point to parameter/retun value table for legacy far call
+ @param TableSize The size of paramter/return value table
+ @param CallIndex The index of legacy call.
+
+ @return EFI_STATUS
+**/
+EFI_STATUS
+MakePxeCall (
+ EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT VOID *Table,
+ IN UINTN TableSize,
+ IN UINT16 CallIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET InOutRegs;
+ UINT16 *BPtr;
+ VOID *Buffer;
+ UINTN Size;
+ VOID *MemPageAddress;
+ UINTN Index;
+ BOOLEAN ThunkFailed;
+
+ DEBUG ((DEBUG_NET, "MakePxeCall(CallIndex = %02x, Table = %X, TableSize = %d)\n", CallIndex, Table, TableSize));
+
+ if (SimpleNetworkDevice->PxeEntrySegment == 0 && SimpleNetworkDevice->PxeEntryOffset == 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = EFI_SUCCESS;
+
+ //
+ // Allocate a transient data structure for the argument table
+ // This table needs to have the input XXX_t structure copied into here.
+ // The PXE UNDI can only grab this table when it's below one-MB, and
+ // this implementation will not try to push this table on the stack
+ // (although this is a possible optimization path since EFI always allocates
+ // 4K as a minimum page size...............)
+ //
+ Status = BiosSnp16AllocatePagesBelowOneMb (
+ TableSize / EFI_PAGE_SIZE + 1,
+ &MemPageAddress
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((DEBUG_ERROR, "We had a failure in AllocatePages, status code = 0x%X\n", Status));
+ return Status;
+ }
+ //
+ // Copy the > 1MB pool table to a sub-1MB buffer
+ //
+ CopyMem (MemPageAddress, Table, TableSize);
+
+ //
+ // Allocate space for IA-32 register context
+ //
+ ZeroMem (&InOutRegs, sizeof (InOutRegs));
+ InOutRegs.X.ES = SimpleNetworkDevice->PxeEntrySegment;
+ InOutRegs.X.DI = SimpleNetworkDevice->PxeEntryOffset;
+
+ //
+ // The game here is to build the stack which will subsequently
+ // get copied down below 1 MB by the FarCall primitive.
+ // This is now our working stack
+ //
+ Size = 6;
+ Status = gBS->AllocatePool (
+ EfiRuntimeServicesData,
+ Size,
+ &Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BPtr = (UINT16 *) Buffer;
+ *BPtr++ = CallIndex;
+ //
+ // SP + 2
+ //
+ *BPtr++ = TO_OFFSET (MemPageAddress);
+ *BPtr++ = TO_SEGMENT (MemPageAddress);
+
+ DEBUG ((DEBUG_NET, "State before FarCall86\n"));
+ DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
+ BPtr = (UINT16 *) Buffer;
+ DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
+ DEBUG ((DEBUG_NET, " MemPage = "));
+ for (Index = 0; Index < TableSize; Index++) {
+ DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ ThunkFailed = SimpleNetworkDevice->LegacyBios->FarCall86 (
+ SimpleNetworkDevice->LegacyBios,
+ SimpleNetworkDevice->PxeEntrySegment, // Input segment
+ SimpleNetworkDevice->PxeEntryOffset,
+ &InOutRegs, // Ptr to Regs
+ Buffer, // Reference to Stack
+ 6 // Size of the Stack
+ );
+ if (ThunkFailed) {
+ return EFI_ABORTED;
+ }
+
+ DEBUG ((DEBUG_NET, "State after FarCall86\n"));
+ DEBUG ((DEBUG_NET, "The Buffer is at 0x%X\n\r", Buffer));
+ BPtr = (UINT16 *) Buffer;
+ DEBUG ((DEBUG_NET, " Buffer = %04X %04X %04X", *BPtr, *(BPtr + 1), *(BPtr + 2)));
+ DEBUG ((DEBUG_NET, " MemPage = "));
+ for (Index = 0; Index < TableSize; Index++) {
+ DEBUG ((DEBUG_NET, " %02x", *((UINT8 *) MemPageAddress + Index)));
+ }
+
+ DEBUG ((DEBUG_NET, "\n"));
+
+ //
+ // Copy the sub 1MB table to > 1MB table
+ //
+ CopyMem (Table, MemPageAddress, TableSize);
+
+ //
+ // For PXE UNDI call, AX contains the return status.
+ // Convert the PXE UNDI Status to EFI_STATUS type
+ //
+ if (InOutRegs.X.AX == PXENV_EXIT_SUCCESS) {
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+ //
+ // Clean up house
+ //
+ gBS->FreePool (Buffer);
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS) (UINTN) MemPageAddress, TableSize / EFI_PAGE_SIZE + 1);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h
new file mode 100644
index 0000000000..54503a840f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Pxe.h
@@ -0,0 +1,613 @@
+/** @file
+ These are PXE Specification 2.1-compliant data structures and defines.
+
+ This file relies upon the existence of a PXE-compliant ROM
+ in memory, as defined by the Preboot Execution Environment
+ Specification (PXE), Version 2.1, located at
+
+ http://developer.intel.com/ial/wfm/wfmspecs.htm
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _PXEDEF_H_
+#define _PXEDEF_H_
+
+#pragma pack(1)
+
+//
+// PXE structure signatures
+//
+#define BC_ROMID_SIG "$BC$"
+#define UNDI_ROMID_SIG "UNDI"
+#define BUSD_ROMID_SIG "BUSD"
+
+#define PXE_SIG "!PXE"
+#define PXENV_SIG "PXENV+"
+
+#define BC_ROMID_REV 0x00
+#define UNDI_ROMID_REV 0x00
+#define BUSD_ROMID_REV 0x00
+
+#define PXE_REV 0x00
+#define PXENV_REV 0x0201
+
+#define PXENV_PTR SIGNATURE_32 ('P', 'X', 'E', 'N')
+#define PXE_PTR SIGNATURE_32 ('!', 'P', 'X', 'E')
+#define UNDI_ROMID_SIG_PTR SIGNATURE_32 ('U', 'N', 'D', 'I')
+
+typedef UINT16 SEGSEL; // Real mode segment or protected mode selector.
+typedef UINT16 OFF16; // Unsigned 16bit offset.
+typedef UINT32 ADDR32;
+
+//
+// Bus types
+//
+#define PXENV_BUS_ISA 0
+#define PXENV_BUS_EISA 1
+#define PXENV_BUS_MCA 2
+#define PXENV_BUS_PCI 3
+#define PXENV_BUS_VESA 4
+#define PXENV_BUS_PCMCIA 5
+
+//
+//
+// Result codes returned in AX by a PXENV API service.
+//
+#define PXENV_EXIT_SUCCESS 0x0000
+#define PXENV_EXIT_FAILURE 0x0001
+
+//
+// Status codes returned in the status word of PXENV API parameter structures.
+//
+// Generic API errors - these do not match up with the M0x or E0x messages
+// that are reported by the loader.
+//
+#define PXENV_STATUS_SUCCESS 0x00
+#define PXENV_STATUS_FAILURE 0x01
+#define PXENV_STATUS_BAD_FUNC 0x02
+#define PXENV_STATUS_UNSUPPORTED 0x03
+#define PXENV_STATUS_KEEP_UNDI 0x04
+#define PXENV_STATUS_KEEP_ALL 0x05
+#define PXENV_STATUS_OUT_OF_RESOURCES 0x06
+
+typedef enum {
+ PxeEnvStatus_Success,
+ PxeEnvStatus_Failure,
+ PxeEnvStatus_BadFunc,
+ PxeEnvStatus_Unsupported,
+ PxeEnvStatus_KeepUndi,
+ PxeEnvStatus_KeepAll
+} EFI_PXE_STATUS;
+
+/* Driver errors (0x60 to 0x6F) */
+
+// These errors are for UNDI compatible NIC drivers.
+#define PXENV_STATUS_UNDI_INVALID_FUNCTION 0x60
+#define PXENV_STATUS_UNDI_MEDIATEST_FAILED 0x61
+#define PXENV_STATUS_UNDI_CANNOT_INIT_NIC_FOR_MCAST 0x62
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_NIC 0x63
+#define PXENV_STATUS_UNDI_CANNOT_INITIALIZE_PHY 0x64
+#define PXENV_STATUS_UNDI_CANNOT_READ_CONFIG_DATA 0x65
+#define PXENV_STATUS_UNDI_CANNOT_READ_INIT_DATA 0x66
+#define PXENV_STATUS_UNDI_BAD_MAC_ADDR 0x67
+#define PXENV_STATUS_UNDI_BAD_EEPROM_CKSUM 0x68
+#define PXENV_STATUS_UNDI_ERROR_SETTING_ISR 0x69
+#define PXENV_STATUS_UNDI_INVALID_STATE 0x6A
+#define PXENV_STATUS_UNDI_TRANSMIT_ERROR 0x6B
+#define PXENV_STATUS_UNDI_INVALID_PARAMETER 0x6C
+
+typedef struct {
+ UINT16 Seg_Addr;
+ UINT32 Phy_Addr;
+ UINT16 Seg_Size;
+} NEWSEGDESC_T;
+
+typedef struct {
+ OFF16 Offset;
+ SEGSEL Segment;
+} SEGOFF16;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 UNDI_Rev[3]; ///< API revision number stored in Intel order.
+ //
+ // Revision 2.1.0 == 0x00, 0x01, 0x02
+ //
+ UINT16 UNDI_Loader; ///< Offset of UNDI loader routine in the option ROM image.
+ UINT16 StackSize; ///< Minimum stack segment size, in bytes, needed to load and run the UNDI.
+ UINT16 DataSize; ///< UNDI runtime code and data
+ UINT16 CodeSize; ///< segment sizes.
+ UINT8 BusType[4]; ///< 'ISAR', 'EISA', 'PCIR', 'PCCR'
+} UNDI_ROMID_T;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 BC_Rev[3]; ///< API revision number stored in Intel order.
+ //
+ // Revision 2.1.0 == 0x00, 0x01, 0x02
+ //
+ UINT16 BC_Loader; ///< Offset of base-code loader routine in the option ROM image.
+ UINT16 StackSize; ///< Minimum stack segment size (bytes) needed to load/run base-code.
+ UINT16 DataSize; ///< Base-code runtime code and data
+ UINT16 CodeSize; ///< segment sizes.
+} BC_ROMID_T;
+
+typedef struct {
+ UINT8 Signature[4]; ///< Structure signature is not NULL terminated.
+ UINT8 StructLength; ///< Length of this structure in bytes.
+ UINT8 StructCksum; ///< Use to make byte checksum of this structure == zero.
+ UINT8 StructRev; ///< Structure format revision number.
+ UINT8 Reserved1; ///< must be zero
+ ///
+ /// UNDI_ROMID_T __FAR *UNDI;// Far pointer to UNDI ROMID
+ ///
+ SEGOFF16 Undi;
+
+ ///
+ /// BC_ROMID_T __FAR *Base; // Far pointer to base-code ROMID
+ ///
+ SEGOFF16 Base;
+
+ ///
+ /// UINT16 (__FAR __CDECL *EntryPointSP)(UINT16 func, VOID __FAR *param);
+ /// 16bit stack segment API entry point. This will be seg:off in
+ /// real mode and sel:off in 16:16 protected mode.
+ ///
+ SEGOFF16 EntryPointSP;
+
+ ///
+ /// UINT16 (__FAR __CDECL *EntryPointESP)(UINT16 func, VOID __FAR *param);
+ /// 32bit stack segment API entry point. This will be sel:off.
+ /// In real mode, sel == 0
+ ///
+ SEGOFF16 EntryPointESP;
+ ///
+ /// UINT16 (__FAR __CDECL *StatusCallout)(UINT16 param);
+ /// Address of DHCP/TFTP status callout routine.
+ ///
+ SEGOFF16 StatusCallout;
+ UINT8 Reserved2; ///< must be zero
+ UINT8 SegDescCnt; ///< Number of segment descriptors in this structure.
+ UINT16 FirstSelector; ///< First segment descriptor in GDT assigned to PXE.
+ NEWSEGDESC_T Stack;
+ NEWSEGDESC_T UNDIData;
+ NEWSEGDESC_T UNDICode;
+ NEWSEGDESC_T UNDICodeWrite;
+ NEWSEGDESC_T BC_Data;
+ NEWSEGDESC_T BC_Code;
+ NEWSEGDESC_T BC_CodeWrite;
+} PXE_T;
+
+typedef struct {
+ CHAR8 Signature[6]; ///< "PXENV+"
+ UINT16 Version; ///< PXE version number. LSB is minor version. MSB is major version.
+ UINT8 StructLength; ///< Length of PXE-2.0 Entry Point structure in bytes.
+ UINT8 StructCksum; ///< Used to make structure checksum equal zero.
+ UINT32 RMEntry; ///< Real mode API entry point segment:offset.
+ UINT32 PMEntryOff; ///< Protected mode API entry point
+ UINT16 PMEntrySeg; ///< segment:offset. This will always be zero. Protected mode API calls
+ ///< must be made through the API entry points in the PXE Runtime ID structure.
+
+ UINT16 StackSeg; ///< Real mode stack segment.
+ UINT16 StackSize; ///< Stack segment size in bytes.
+ UINT16 BaseCodeSeg; ///< Real mode base-code code segment.
+ UINT16 BaseCodeSize; ///< Base-code code segment size
+ UINT16 BaseDataSeg; ///< Real mode base-code data segment.
+ UINT16 BaseDataSize; ///< Base-code data segment size
+ UINT16 UNDIDataSeg; ///< Real mode UNDI data segment.
+ UINT16 UNDIDataSize; ///< UNDI data segment size in bytes.
+ UINT16 UNDICodeSeg; ///< Real mode UNDI code segment.
+ UINT16 UNDICodeSize; ///< UNDI code segment size in bytes.
+ PXE_T *RuntimePtr; ///< Real mode segment:offset pointer to PXE Runtime ID structure.
+} PXENV_T;
+
+typedef struct {
+ OUT UINT16 Status;
+ IN OUT UINT16 Ax;
+ IN OUT UINT16 Bx;
+ IN OUT UINT16 Dx;
+ IN OUT UINT16 Di;
+ IN OUT UINT16 Es;
+ IN OUT UINT16 Undi_Ds;
+ IN OUT UINT16 Undi_Cs;
+ OUT SEGOFF16 PXEptr;
+ OUT SEGOFF16 PXENVptr;
+} UNDI_LOADER_T;
+
+//
+// Put in some UNDI-specific arguments
+//
+#define PXENV_START_UNDI 0x0000
+#define PXENV_UNDI_STARTUP 0x0001
+#define PXENV_UNDI_CLEANUP 0x0002
+#define PXENV_UNDI_INITIALIZE 0x0003
+#define PXENV_UNDI_RESET_NIC 0x0004
+#define PXENV_UNDI_SHUTDOWN 0x0005
+#define PXENV_UNDI_OPEN 0x0006
+#define PXENV_UNDI_CLOSE 0x0007
+#define PXENV_UNDI_TRANSMIT 0x0008
+#define PXENV_UNDI_SET_MCAST_ADDR 0x0009
+#define PXENV_UNDI_SET_STATION_ADDR 0x000A
+#define PXENV_UNDI_SET_PACKET_FILTER 0x000B
+#define PXENV_UNDI_GET_INFORMATION 0x000C
+#define PXENV_UNDI_GET_STATISTICS 0x000D
+#define PXENV_UNDI_CLEAR_STATISTICS 0x000E
+#define PXENV_UNDI_INITIATE_DIAGS 0x000F
+#define PXENV_UNDI_FORCE_INTERRUPT 0x0010
+#define PXENV_UNDI_GET_MCAST_ADDR 0x0011
+#define PXENV_UNDI_GET_NIC_TYPE 0x0012
+#define PXENV_UNDI_GET_NDIS_INFO 0x0013
+#define PXENV_UNDI_ISR 0x0014
+#define PXENV_STOP_UNDI 0x0015
+#define PXENV_UNDI_GET_STATE 0x0016
+
+#define ADDR_LEN 16
+#define MAXNUM_MCADDR 8
+#define IPLEN 4 ///< length of an IP address
+#define XMT_DESTADDR 0x0000 ///< destination address given
+#define XMT_BROADCAST 0x0001 ///< use broadcast address
+
+typedef struct {
+ UINT16 MCastAddrCount; ///< In: Number of multi-cast
+
+ /* addresses. */
+ UINT8 MCastAddr[MAXNUM_MCADDR][ADDR_LEN]; /* In: */
+
+ /* list of multi-cast addresses. */
+
+ /* Each address can take up to */
+
+ /* ADDR_LEN bytes and a maximum */
+
+ /* of MAXNUM_MCADDR address can */
+
+ /* be provided*/
+} PXENV_UNDI_MCAST_ADDR_T;
+
+/* Definitions of TFTP API parameter structures.
+ */
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT16 Ax; ///< In: These register fields must be
+ IN UINT16 Bx; ///< filled in with the same data
+ IN UINT16 Dx; ///< that was passed to the MLID
+ IN UINT16 Di; ///< option ROM boot code by the
+ IN UINT16 Es; ///< system BIOS.
+} PXENV_START_UNDI_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_STARTUP_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLEANUP_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is an input parameter and is a 32-bit physical address of
+ /// a memory copy of the driver module in the protocol.ini file
+ /// obtained from the Protocol Manager driver(refer to NDIS 2.0
+ /// specifications). This parameter is basically supported for
+ /// the universal NDIS driver to pass the information contained in
+ /// protocol.ini file to the NIC driver for any specific
+ /// configuration of the NIC. (Note that the module
+ /// identification in the protocol.ini file was done by NDIS
+ /// itself.) This value can be NULL for for any other application
+ /// interfacing to the Universal NIC Driver.
+ ///
+ IN UINT32 ProtocolIni;
+ UINT8 Reserved[8];
+} PXENV_UNDI_INITIALIZE_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN PXENV_UNDI_MCAST_ADDR_T R_Mcast_Buf; ///< multicast address list
+ /* see note below */
+} PXENV_UNDI_RESET_T;
+
+/*++
+ Note: The NIC driver does not remember the multicast
+ addresses provided in any call. So the application must
+ provide the multicast address list with all the calls that
+ reset the receive unit of the adapter.
+ --*/
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_SHUTDOWN_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is an input parameter and is adapter specific. This is
+ /// supported for Universal NDIS 2.0 driver to pass down the Open
+ /// flags provided by the protocol driver (See NDIS 2.0
+ /// specifications). This can be zero.
+ ///
+ IN UINT16 OpenFlag; ///< In: See description below
+ IN UINT16 PktFilter; ///< In: Filter for receiving
+
+ /* packet. It takes the following */
+
+ /* values, multiple values can be */
+
+ /* ORed together. */
+#define FLTR_DIRECTED 0x0001 ///< directed/multicast
+#define FLTR_BRDCST 0x0002 ///< broadcast packets
+#define FLTR_PRMSCS 0x0004 ///< any packet on LAN
+#define FLTR_SRC_RTG 0x0008 ///< source routing packet
+ IN PXENV_UNDI_MCAST_ADDR_T McastBuffer; /* In: */
+ /* See t_PXENV_UNDI_MCAST_ADDR. */
+} PXENV_UNDI_OPEN_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLOSE_T;
+
+#define MAX_DATA_BLKS 8
+
+typedef struct {
+ IN UINT16 ImmedLength; ///< In: Data buffer length in
+
+ /* bytes. */
+ UINT16 XmitOffset; ///< 16-bit segment & offset of the
+ UINT16 XmitSegment; ///< immediate data buffer.
+ UINT16 DataBlkCount; ///< In: Number of data blocks.
+ struct DataBlk {
+ UINT8 TDPtrType; ///< 0 => 32 bit Phys pointer in TDDataPtr, not supported in this version of LSA
+ ///< 1 => seg:offser in TDDataPtr which can be a real mode or 16-bit protected mode pointer
+ UINT8 TDRsvdByte; ///< Reserved, must be zero.
+ UINT16 TDDataLen; ///< Data block length in bytes.
+ UINT16 TDDataPtrOffset; ///< Far pointer to data buffer.
+ UINT16 TDDataPtrSegment; ///< Far pointer to data buffer.
+ } DataBlock[MAX_DATA_BLKS];
+}
+PXENV_UNDI_TBD_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+
+ ///
+ /// This is the protocol of the upper layer that is calling
+ /// NICTransmit call. If the upper layer has filled the media
+ /// header this field must be 0.
+ ///
+ IN UINT8 Protocol;
+#define P_UNKNOWN 0
+#define P_IP 1
+#define P_ARP 2
+#define P_RARP 3
+
+ ///
+ /// If this flag is 0, the NIC driver expects a pointer to the
+ /// destination media address in the field DestMediaAddr. If 1,
+ /// the NIC driver fills the broadcast address for the
+ /// destination.
+ ///
+ IN UINT8 XmitFlag;
+#define XMT_DESTADDR 0x0000 ///< destination address given
+#define XMT_BROADCAST 0x0001 ///< use broadcast address
+
+ ///
+ /// This is a pointer to the hardware address of the destination
+ /// media. It can be null if the destination is not known in
+ /// which case the XmitFlag contains 1 for broadcast. Destination
+ /// media address must be obtained by the upper level protocol
+ /// (with Address Resolution Protocol) and NIC driver does not do
+ /// any address resolution.
+ ///
+ IN UINT16 DestAddrOffset; ///< 16-bit segment & offset of the
+ IN UINT16 DestAddrSegment; ///< destination media address
+
+
+ IN UINT16 TBDOffset; ///< 16-bit segment & offset of the
+ IN UINT16 TBDSegment; ///< transmit buffer descriptor of type
+
+ /// XmitBufferDesc
+ IN UINT32 Reserved[2];
+} PXENV_UNDI_TRANSMIT_T;
+
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN PXENV_UNDI_MCAST_ADDR_T McastBuffer; ///< In:
+} PXENV_UNDI_SET_MCAST_ADDR_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT8 StationAddress[ADDR_LEN]; ///< new address to be set
+} PXENV_UNDI_SET_STATION_ADDR_T;
+
+typedef struct s_PXENV_UNDI_SET_PACKET_FILTER {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT8 Filter; ///< In: Receive filter value.
+} PXENV_UNDI_SET_PACKET_FILTER_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ OUT UINT16 BaseIo; ///< Out: Adapter's Base IO
+ OUT UINT16 IntNumber; ///< Out: IRQ number
+ OUT UINT16 MaxTranUnit; ///< Out: MTU
+ OUT UINT16 HwType; ///< Out: type of protocol at hardware level
+
+#define ETHER_TYPE 1
+#define EXP_ETHER_TYPE 2
+#define IEEE_TYPE 6
+#define ARCNET_TYPE 7
+ /*++
+ other numbers can be obtained from rfc1010 for "Assigned
+ Numbers". This number may not be validated by the application
+ and hence adding new numbers to the list should be fine at any
+ time.
+ --*/
+ OUT UINT16 HwAddrLen; ///< Out: actual length of hardware address
+ OUT UINT8 CurrentNodeAddress[ADDR_LEN]; ///< Out: Current hardware address
+ OUT UINT8 PermNodeAddress[ADDR_LEN]; ///< Out: Permanent hardware address
+ OUT UINT16 ROMAddress; ///< Out: ROM address
+ OUT UINT16 RxBufCt; ///< Out: receive Queue length
+ OUT UINT16 TxBufCt; ///< Out: Transmit Queue length
+} PXENV_UNDI_GET_INFORMATION_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ OUT UINT32 XmtGoodFrames; ///< Out: No. of good transmissions
+ OUT UINT32 RcvGoodFrames; ///< Out: No. of good frames received
+ OUT UINT32 RcvCRCErrors; ///< Out: No. of frames with CRC error
+ OUT UINT32 RcvResourceErrors; ///< Out: no. of frames discarded
+ /* Out: receive Queue full */
+} PXENV_UNDI_GET_STATISTICS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_CLEAR_STATISTICS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_INITIATE_DIAGS_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_UNDI_FORCE_INTERRUPT_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ IN UINT32 InetAddr; ///< In: IP Multicast Address
+ OUT UINT8 MediaAddr[ADDR_LEN]; ///< Out: corresponding hardware
+ /* multicast address */
+} PXENV_UNDI_GET_MCAST_ADDR_T;
+
+typedef struct {
+ OUT UINT16 Vendor_ID; ///< OUT:
+ OUT UINT16 Dev_ID; ///< OUT:
+ OUT UINT8 Base_Class; ///< OUT:
+ OUT UINT8 Sub_Class; ///< OUT:
+ OUT UINT8 Prog_Intf; ///< OUT: program interface
+ OUT UINT8 Rev; ///< OUT: Revision number
+ OUT UINT16 BusDevFunc; ///< OUT: Bus, Device & Function numbers
+ OUT UINT16 SubVendor_ID; ///< OUT:
+ OUT UINT16 SubDevice_ID; ///< OUT:
+} PCI_INFO_T;
+
+typedef struct {
+ OUT UINT32 EISA_Dev_ID; ///< Out:
+ OUT UINT8 Base_Class; ///< OUT:
+ OUT UINT8 Sub_Class; ///< OUT:
+ OUT UINT8 Prog_Intf; ///< OUT: program interface
+ OUT UINT16 CardSelNum; ///< OUT: Card Selector Number
+ OUT UINT8 Reserved; ///< to make it 10 bytes
+} PNP_INFO_T;
+
+
+typedef union {
+ PCI_INFO_T Pci;
+ PNP_INFO_T Pnp;
+} PCI_PNP_INFO_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ OUT UINT8 NicType; ///< OUT: 2=PCI, 3=PnP
+ PCI_PNP_INFO_T PciPnpInfo;
+} PXENV_UNDI_GET_NIC_TYPE_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ OUT UINT8 IfaceType[16]; ///< OUT: Type name of MAC, AsciiZ
+
+ /* format. This is used by the */
+
+ /* Universal NDIS Driver to fill */
+
+ /* the driver type in it's MAC */
+
+ /* Service specific */
+
+ /* characteristic table */
+ OUT UINT32 LinkSpeed; ///< OUT:
+ OUT UINT32 ServiceFlags; ///< OUT: as defined in NDIS Spec 2.0X
+ OUT UINT32 Reserved[4]; ///< OUT: will be filled with 0s till defined
+} PXENV_UNDI_GET_NDIS_INFO_T;
+
+typedef struct {
+ OUT UINT16 Status; ///< OUT: PXENV_STATUS_xxx
+ IN OUT UINT16 FuncFlag; ///< In: PXENV_UNDI_ISR_IN_xxx
+
+ /* Out: PXENV_UNDI_ISR_OUT_xxx */
+ OUT UINT16 BufferLength;
+ OUT UINT16 FrameLength;
+ OUT UINT16 FrameHeaderLength;
+ OUT UINT16 FrameOffset;
+ OUT UINT16 FrameSegSel;
+ OUT UINT8 ProtType;
+ OUT UINT8 PktType;
+} PXENV_UNDI_ISR_T;
+
+#define PXENV_UNDI_ISR_IN_START 1 /* This function must be first */
+
+/* when an interrupt is received. */
+
+/* It will tell us if the intr */
+
+/* was generated by our device. */
+#define PXENV_UNDI_ISR_IN_PROCESS 2 /* Call to start processing one of */
+
+/* our interrupts. */
+#define PXENV_UNDI_ISR_IN_GET_NEXT 3 /* Call to start/continue receiving */
+
+/* data from receive buffer(s). */
+
+/*++
+
+ Possible responses from PXENV_UNDI_ISR_IN_START
+
+ --*/
+#define PXENV_UNDI_ISR_OUT_OURS 0 ///< This is our interrupt. Deal with it.
+#define PXENV_UNDI_ISR_OUT_NOT_OURS 1 ///< This is not our interrupt.
+
+/*++
+
+ Possible responses from PXENV_UNDI_ISR_IN_PROCESS and
+ PXENV_UNDI_ISR_IN_PROCESS
+
+--*/
+#define PXENV_UNDI_ISR_OUT_DONE 0 ///< We are done processing this interrupt.
+#define PXENV_UNDI_ISR_OUT_TRANSMIT 2 ///< We completed a transmit interrupt.
+#define PXENV_UNDI_ISR_OUT_RECEIVE 3 ///< Get data from receive buffer.
+
+#define PXENV_UNDI_ISR_OUT_BUSY 4 /* ? */
+
+typedef struct {
+ UINT16 Status; ///< Out: PXENV_STATUS_xxx
+} PXENV_STOP_UNDI_T;
+
+#define PXENV_UNDI_STARTED 1 ///< not even initialized
+#define PXENV_UNDI_INITIALIZED 2 ///< initialized and closed (not opened)
+#define PXENV_UNDI_OPENED 3 ///< initialized & opened
+
+typedef struct {
+ OUT UINT16 Status; ///< Out: PXENV_STATUS_xxx
+ UINT16 UNDI_State;
+} PXENV_UNDI_GET_STATE_T;
+
+#pragma pack()
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c
new file mode 100644
index 0000000000..d35fc3f430
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/PxeUndi.c
@@ -0,0 +1,1254 @@
+/** @file
+ Wrapper routines that use a PXE-enabled NIC option ROM to
+ supply internal routines for an EFI SNI (Simple Network
+ Interface) Protocol.
+
+ This file relies upon the existence of a PXE-compliant ROM
+ in memory, as defined by the Preboot Execution Environment
+ Specification (PXE), Version 2.1, located at
+
+ http://developer.intel.com/ial/wfm/wfmspecs.htm
+
+Copyright (c) 1999 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosSnp16.h"
+
+/**
+ PXE
+ START UNDI
+ Op-Code: PXENV_START_UNDI (0000h)
+ Input: Far pointer to a PXENV_START_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This service is used to pass the BIOS parameter registers to the UNDI driver. The UNDI driver is
+ responsible for saving the information it needs to communicate with the hardware.
+ This service is also responsible for hooking the Int 1Ah service routine
+ Note: This API service must be called only once during UNDI Option ROM boot.
+ The UNDI driver is responsible for saving this information and using it every time
+ PXENV_UNDI_STARTUP is called.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 AX;
+ UINT16 BX;
+ UINT16 DX;
+ UINT16 DI;
+ UINT16 ES;
+ } PXENV_START_UNDI_T;
+ Set before calling API service
+ AX, BX, DX, DI, ES: BIOS initialization parameter registers. These
+ fields should contain the same information passed to the option ROM
+ initialization routine by the Host System BIOS. Information about the
+ contents of these registers can be found in the [PnP], [PCI] and
+ [BBS] specifications.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeStartUndi (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_START_UNDI_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_START_UNDI_T),
+ PXENV_START_UNDI
+ );
+}
+
+/**
+ PXE
+ UNDI STARTUP
+ Op-Code: PXENV_UNDI_STARTUP (0001h)
+ Input: Far pointer to a PXENV_UNDI_STARTUP_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This API is responsible for initializing the contents of the UNDI code & data segment for proper
+ operation. Information from the !PXE structure and the first PXENV_START_UNDI API call is used
+ to complete this initialization. The rest of the UNDI APIs will not be available until this call has
+ been completed.
+ Note: PXENV_UNDI_STARTUP must not be called again without first calling
+ PXENV_UNDI_SHUTDOWN.
+ PXENV_UNDI_STARTUP and PXENV_UNDI_SHUTDOWN are no longer responsible for
+ chaining interrupt 1Ah. This must be done by the PXENV_START_UNDI and
+ PXENV_STOP_UNDI API calls.
+ This service cannot be used in protected mode.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_STARTUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStartup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_STARTUP_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_STARTUP_T),
+ PXENV_UNDI_STARTUP
+ );
+}
+
+/**
+ PXE
+ UNDI CLEANUP
+ Op-Code: PXENV_UNDI_CLEANUP (0002h)
+ Input: Far pointer to a PXENV_UNDI_CLEANUP_T parameter structure.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field
+ in the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call will prepare the network adapter driver to be unloaded from memory. This call must be
+ made just before unloading the Universal NIC Driver. The rest of the API will not be available
+ after this call executes.
+ This service cannot be used in protected mode.
+ typedef struct {
+ PXENX_STATUS Status;
+ } PXENV_UNDI_CLEANUP_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiCleanup (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEANUP_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLEANUP_T),
+ PXENV_UNDI_CLEANUP
+ );
+}
+
+/**
+ PXE
+ UNDI INITIALIZE
+ Op-Code: PXENV_UNDI_INITIALIZE (0003h)
+ Input: Far pointer to a PXENV_UNDI_INITIALIZE_T parameter structure that has been initialized by the
+ caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter and programs it with default parameters. The default parameters used
+ are those supplied to the most recent UNDI_STARTUP call. This routine does not enable the
+ receive and transmit units of the network adapter to readily receive or transmit packets. The
+ application must call PXENV_UNDI_OPEN to logically connect the network adapter to the network.
+ This call must be made by an application to establish an interface to the network adapter driver.
+ Note: When the PXE code makes this call to initialize the network adapter, it passes a NULL pointer for
+ the Protocol field in the parameter structure.
+ typedef struct {
+ PXENV_STATUS Status;
+ ADDR32 ProtocolIni;
+ UINT8 reserved[8];
+ } PXENV_UNDI_INITIALIZE_T;
+ Set before calling API service
+ ProtocolIni: Physical address of a memory copy of the driver
+ module from the protocol.ini file obtained from the protocol manager
+ driver (refer to the NDIS 2.0 specification). This parameter is
+ supported for the universal NDIS driver to pass the information
+ contained in the protocol.ini file to the NIC driver for any specific
+ configuration of the NIC. (Note that the module identification in the
+ protocol.ini file was done by NDIS.) This value can be NULL for any
+ other application interfacing to the universal NIC driver
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitialize (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIALIZE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_INITIALIZE_T),
+ PXENV_UNDI_INITIALIZE
+ );
+}
+
+/**
+ Wrapper routine for reset adapter.
+
+ PXE
+ UNDI RESET ADAPTER
+ Op-Code: PXENV_UNDI_RESET_ADAPTER (0004h)
+ Input: Far pointer to a PXENV_UNDI_RESET_ADAPTER_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets and reinitializes the network adapter with the same set of parameters supplied to
+ Initialize Routine. Unlike Initialize, this call opens the adapter that is, it connects logically to the
+ network. This routine cannot be used to replace Initialize or Shutdown calls.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_RESET_T;
+
+ #define MAXNUM_MCADDR 8
+
+ typedef struct {
+ UINT16 MCastAddrCount;
+ MAC_ADDR McastAddr[MAXNUM_MCADDR];
+ } PXENV_UNDI_MCAST_ADDRESS_t;
+
+ Set before calling API service
+ R_Mcast_Buf: This is a structure of MCastAddrCount and
+ McastAddr.
+ MCastAddrCount: Number of multicast MAC addresses in the
+ buffer.
+ McastAddr: List of up to MAXNUM_MCADDR multicast MAC
+ addresses.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance.
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+ @param RxFilter Filter setting mask value for PXE recive .
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiResetNic (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_RESET_T *PxeUndiTable,
+ IN UINT16 RxFilter
+ )
+{
+ PXENV_UNDI_OPEN_T Open;
+ PXENV_UNDI_CLOSE_T Close;
+ UINTN Status;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_RESET_T),
+ PXENV_UNDI_RESET_NIC
+ );
+ if (!EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ Close.Status = PXENV_STATUS_SUCCESS;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ &Close,
+ sizeof (Close),
+ PXENV_UNDI_CLOSE
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_RESET_T),
+ PXENV_UNDI_RESET_NIC
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Open.Status = PXENV_STATUS_SUCCESS;
+ Open.OpenFlag = 0;
+ Open.PktFilter = RxFilter;
+ CopyMem (
+ &Open.McastBuffer,
+ &PxeUndiTable->R_Mcast_Buf,
+ sizeof (PXENV_UNDI_MCAST_ADDR_T)
+ );
+
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ &Open,
+ sizeof (Open),
+ PXENV_UNDI_OPEN
+ );
+ if (EFI_ERROR(Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ PXE
+ UNDI SHUTDOWN
+ Op-Code: PXENV_UNDI_SHUTDOWN (0005h)
+ Input: Far pointer to a PXENV_UNDI_SHUTDOWN_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the network adapter and leaves it in a safe state for another driver to program it.
+ Note: The contents of the PXENV_UNDI_STARTUP parameter structure need to be saved by the
+ Universal NIC Driver in case PXENV_UNDI_INITIALIZE is called again.
+ typedef struct
+ {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_SHUTDOWN_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiShutdown (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SHUTDOWN_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SHUTDOWN_T),
+ PXENV_UNDI_SHUTDOWN
+ );
+}
+
+/**
+ PXE
+ UNDI OPEN
+ Op-Code: PXENV_UNDI_OPEN (0006h)
+ Input: Far pointer to a PXENV_UNDI_OPEN_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call activates the adapter network connection and sets the adapter ready to accept packets
+ for transmit and receive.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 OpenFlag;
+ UINT16 PktFilter;
+ #define FLTR_DIRECTED 0x0001
+ #define FLTR_BRDCST 0x0002
+ #define FLTR_PRMSCS 0x0004
+ #define FLTR_SRC_RTG 0x0008
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_OPEN_T;
+ Set before calling API service
+ OpenFlag: This is an adapter specific input parameter. This is
+ supported for the universal NDIS 2.0 driver to pass in the open flags
+ provided by the protocol driver. (See the NDIS 2.0 specification.)
+ This can be zero.
+ PktFilter: Filter for receiving packets. This can be one, or more, of
+ the FLTR_xxx constants. Multiple values are arithmetically or-ed
+ together.
+ directed packets are packets that may come to your MAC address
+ or the multicast MAC address.
+ R_Mcast_Buf: See definition in UNDI RESET ADAPTER (0004h).
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiOpen (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_OPEN_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_OPEN_T),
+ PXENV_UNDI_OPEN
+ );
+}
+
+/**
+ PXE
+ UNDI CLOSE
+ Op-Code: PXENV_UNDI_CLOSE (0007h)
+ Input: Far pointer to a PXENV_UNDI_CLOSE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call disconnects the network adapter from the network. Packets cannot be transmitted or
+ received until the network adapter is open again.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLOSE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClose (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLOSE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLOSE_T),
+ PXENV_UNDI_CLOSE
+ );
+}
+
+/**
+ PXE
+ UNDI TRANSMIT PACKET
+ Op-Code: PXENV_UNDI_TRANSMIT (0008h)
+ Input: Far pointer to a PXENV_UNDI_TRANSMIT_T parameter structure that
+ has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX.
+ The status code must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call transmits a buffer to the network. The media header
+ for the packet can be filled by the calling protocol, but it might not be.
+ The network adapter driver will fill it if required by the values in the
+ parameter block. The packet is buffered for transmission provided there is
+ an available buffer, and the function returns PXENV_EXIT_SUCCESS. If no
+ buffer is available the function returns PXENV_EXIT_FAILURE with a status
+ code of PXE_UNDI_STATUS__OUT OF_RESOURCE. The number of buffers is
+ implementation-dependent. An interrupt is generated on completion of the
+ transmission of one or more packets. A call to PXENV_UNDI_TRANSMIT is
+ permitted in the context of a transmit complete interrupt.
+
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 Protocol;
+ #define P_UNKNOWN 0
+ #define P_IP 1
+ #define P_ARP 2
+ #define P_RARP 3
+ UINT8 XmitFlag;
+ #define XMT_DESTADDR 0x0000
+ #define XMT_BROADCAST 0x0001
+ SEGOFF16 DestAddr;
+ SEGOFF16 TBD;
+ UINT32 Reserved[2];
+ } t_PXENV_UNDI_TRANSMIT;
+
+ #define MAX_DATA_BLKS 8
+
+ typedef struct {
+ UINT16 ImmedLength;
+ SEGOFF16 Xmit;
+ UINT16 DataBlkCount;
+ struct DataBlk {
+ UINT8 TDPtrType;
+ UINT8 TDRsvdByte;
+ UINT16 TDDataLen;
+ SEGOFF16 TDDataPtr;
+ } DataBlock[MAX_DATA_BLKS];
+ } PXENV_UNDI_TBD_T
+
+ Set before calling API service
+ Protocol: This is the protocol of the upper layer that is calling UNDI
+ TRANSMIT call. If the upper layer has filled the media header, this
+ field must be P_UNKNOWN.
+ XmitFlag: If this flag is XMT_DESTADDR, the NIC driver expects a
+ pointer to the destination media address in the field DestAddr. If
+ XMT_BROADCAST, the NIC driver fills the broadcast address for the
+ destination.
+ TBD: Segment:Offset address of the transmit buffer descriptor.
+ ImmedLength: Length of the immediate transmit buffer: Xmit.
+ Xmit: Segment:Offset of the immediate transmit buffer.
+ DataBlkCount: Number of blocks in this transmit buffer.
+ TDPtrType:
+ 0 => 32-bit physical address in TDDataPtr (not supported in this
+ version of PXE)
+ 1 => segment:offset in TDDataPtr which can be a real mode or 16-bit
+ protected mode pointer
+ TDRsvdByte: Reserved must be zero.
+ TDDatalen: Data block length in bytes.
+ TDDataPtr: Segment:Offset of the transmit block.
+ DataBlock: Array of transmit data blocks.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiTransmit (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_TRANSMIT_T *PxeUndiTable
+ )
+{
+ EFI_STATUS Status;
+
+ Status = MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_TRANSMIT_T),
+ PXENV_UNDI_TRANSMIT
+ );
+ if (Status == EFI_SUCCESS) {
+ return EFI_SUCCESS;
+ }
+
+ switch (PxeUndiTable->Status) {
+ case PXENV_STATUS_OUT_OF_RESOURCES:
+ return EFI_NOT_READY;
+
+ default:
+ return EFI_DEVICE_ERROR;
+ }
+}
+
+/**
+ PXE
+ UNDI SET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_SET_MCAST_ADDRESS (0009h)
+ Input: Far pointer to a PXENV_TFTP_SET_MCAST_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call changes the current list of multicast addresses to the input list and resets the network
+ adapter to accept it. If the number of multicast addresses is zero, multicast is disabled.
+ typedef struct {
+ PXENV_STATUS Status;
+ PXENV_UNDI_MCAST_ADDRESS_t R_Mcast_Buf;
+ } PXENV_UNDI_SET_MCAST_ADDR_T;
+ Set before calling API service
+ R_Mcast_Buf: See description in the UNDI RESET ADAPTER
+ (0004h) API.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_MCAST_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_MCAST_ADDR_T),
+ PXENV_UNDI_SET_MCAST_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI SET STATION ADDRESS
+ Op-Code: PXENV_UNDI_SET_STATION_ADDRESS (000Ah)
+ Input: Far pointer to a PXENV_UNDI_SET_STATION_ADDRESS_t parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call sets the MAC address to be the input value and is called before opening the network
+ adapter. Later, the open call uses this variable as a temporary MAC address to program the
+ adapter individual address registers.
+ typedef struct {
+ PXENV_STATUS Status;
+ MAC_ADDR StationAddress;
+ } PXENV_UNDI_SET_STATION_ADDR_T;
+ Set before calling API service
+ StationAddress: Temporary MAC address to be used for
+ transmit and receive.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetStationAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_STATION_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_STATION_ADDR_T),
+ PXENV_UNDI_SET_STATION_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI SET PACKET FILTER
+ Op-Code: PXENV_UNDI_SET_PACKET_FILTER (000Bh)
+ Input: Far pointer to a PXENV_UNDI_SET_PACKET_FILTER_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call resets the adapter's receive unit to accept a new filter, different from the one provided with
+ the open call.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT8 filter;
+ } PXENV_UNDI_SET_PACKET_FILTER_T;
+ Set before calling API service
+ Filter: See the receive filter values in the UNDI OPEN
+ (0006h) API description.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiSetPacketFilter (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_SET_PACKET_FILTER_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_SET_PACKET_FILTER_T),
+ PXENV_UNDI_SET_PACKET_FILTER
+ );
+}
+
+/**
+ PXE
+ UNDI GET INFORMATION
+ Op-Code: PXENV_UNDI_GET_INFORMATION (000Ch)
+ Input: Far pointer to a PXENV_UNDI_GET_INFORMATION_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call copies the network adapter variables, including the MAC address, into the input buffer.
+ Note: The PermNodeAddress field must be valid after PXENV_START_UNDI and
+ PXENV_UNDI_STARTUP have been issued. All other fields must be valid after
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE have been
+ called.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT16 BaseIo;
+ UINT16 IntNumber;
+ UINT16 MaxTranUnit;
+ UINT16 HwType;
+ #define ETHER_TYPE 1
+ #define EXP_ETHER_TYPE 2
+ #define IEEE_TYPE 6
+ #define ARCNET_TYPE 7
+ UINT16 HwAddrLen;
+ MAC_ADDR CurrentNodeAddress;
+ MAC_ADDR PermNodeAddress;
+ SEGSEL ROMAddress;
+ UINT16 RxBufCt;
+ UINT16 TxBufCt;
+ } PXENV_UNDI_GET_INFORMATION_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ BaseIO: Adapter base I/O address.
+ IntNumber: Adapter IRQ number.
+ MaxTranUnit: Adapter maximum transmit unit.
+ HWType: Type of protocol at the hardware level.
+ HWAddrLen: Length of the hardware address.
+ CurrentNodeAddress: Current hardware address.
+ PermNodeAddress: Permanent hardware address.
+ ROMAddress: Real mode ROM segment address.
+ RxBufCnt: Receive queue length.
+ TxBufCnt: Transmit queue length.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetInformation (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_INFORMATION_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_INFORMATION_T),
+ PXENV_UNDI_GET_INFORMATION
+ );
+}
+
+/**
+ PXE
+ UNDI GET STATISTICS
+ Op-Code: PXENV_UNDI_GET_STATISTICS (000Dh)
+ Input: Far pointer to a PXENV_UNDI_GET_STATISTICS_T parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call reads statistical information from the network adapter, and returns.
+ typedef struct {
+ PXENV_STATUS Status;
+ UINT32 XmtGoodFrames;
+ UINT32 RcvGoodFrames;
+ UINT32 RcvCRCErrors;
+ UINT32 RcvResourceErrors;
+ } PXENV_UNDI_GET_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ XmtGoodFrames: Number of successful transmissions.
+ RcvGoodFrames: Number of good frames received.
+ RcvCRCErrors: Number of frames received with CRC
+ error.
+ RcvResourceErrors: Number of frames discarded
+ because receive queue was full.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATISTICS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_STATISTICS_T),
+ PXENV_UNDI_GET_STATISTICS
+ );
+}
+
+/**
+ PXE
+ UNDI CLEAR STATISTICS
+ Op-Code: PXENV_UNDI_CLEAR_STATISTICS (000Eh)
+ Input: Far pointer to a PXENV_UNDI_CLEAR_STATISTICS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call clears the statistical information from the network adapter.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_CLEAR_STATISTICS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiClearStatistics (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_CLEAR_STATISTICS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_CLEAR_STATISTICS_T),
+ PXENV_UNDI_CLEAR_STATISTICS
+ );
+}
+
+/**
+ PXE
+ UNDI INITIATE DIAGS
+ Op-Code: PXENV_UNDI_INITIATE_DIAGS (000Fh)
+ Input: Far pointer to a PXENV_UNDI_INITIATE_DIAGS_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the
+ PXENV_STATUS_xxx constants.
+ Description: This call can be used to initiate the run-time diagnostics. It causes the network adapter to run
+ hardware diagnostics and to update its status information.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_INITIATE_DIAGS_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiInitiateDiags (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_INITIATE_DIAGS_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_INITIATE_DIAGS_T),
+ PXENV_UNDI_INITIATE_DIAGS
+ );
+}
+
+/**
+ PXE
+ UNDI FORCE INTERRUPT
+ Op-Code: PXENV_UNDI_FORCE_INTERRUPT (0010h)
+ Input: Far pointer to a PXENV_UNDI_FORCE_INTERRUPT_T parameter structure that has been
+ initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call forces the network adapter to generate an interrupt. When a receive interrupt occurs, the
+ network adapter driver usually queues the packet and calls the application's callback receive
+ routine with a pointer to the packet received. Then, the callback routine either can copy the packet
+ to its buffer or can decide to delay the copy to a later time. If the packet is not immediately copied,
+ the network adapter driver does not remove it from the input queue. When the application wants to
+ copy the packet, it can call the PXENV_UNDI_FORCE_INTERRUPT routine to simulate the receive
+ interrupt.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_UNDI_FORCE_INTERRUPT_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiForceInterrupt (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_FORCE_INTERRUPT_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_FORCE_INTERRUPT_T),
+ PXENV_UNDI_FORCE_INTERRUPT
+ );
+}
+
+/**
+ PXE
+ UNDI GET MULTICAST ADDRESS
+ Op-Code: PXENV_UNDI_GET_MCAST_ADDRESS (0011h)
+ Input: Far pointer to a PXENV_GET_MCAST_ADDRESS_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This call converts the given IP multicast address to a hardware multicast address.
+ typedef struct {
+ PXENV_STATUS Status;
+ IP4 InetAddr;
+ MAC_ADDR MediaAddr;
+ } PXENV_UNDI_GET_MCAST_ADDR_T;
+ Set before calling API service
+ InetAddr: IP multicast address.
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ MediaAddr: MAC multicast address.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetMcastAddr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_MCAST_ADDR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_MCAST_ADDR_T),
+ PXENV_UNDI_GET_MCAST_ADDR
+ );
+}
+
+/**
+ PXE
+ UNDI GET NIC TYPE
+ Op-Code: PXENV_UNDI_GET_NIC_TYPE (0012h)
+ Input: Far pointer to a PXENV_UNDI_GET_NIC_TYPE parameter structure that has been initialized by
+ the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned the parameter structure must contain the
+ NIC information.
+ Description: This call, if successful, provides the NIC-specific information necessary to identify the network
+ adapter that is used to boot the system.
+ Note: The application first gets the DHCPDISCOVER packet using GET_CACHED_INFO and checks if
+ the UNDI is supported before making this call. If the UNDI is not supported, the NIC-specific
+ information can be obtained from the DHCPDISCOVER packet itself.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef {
+ PXENV_STATUS Status;
+ UINT8 NicType;
+ #define PCI_NIC 2
+ #define PnP_NIC 3
+ #define CardBus_NIC 4
+ Union {
+ Struct {
+ UINT16 Vendor_ID;
+ UINT16 Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT8 Rev;
+ UINT16 BusDevFunc;
+ UINT16 SubVendor_ID;
+ UINT16 SubDevice_ID;
+ } pci, cardbus;
+ struct {
+ UINT32 EISA_Dev_ID;
+ UINT8 Base_Class;
+ UINT8 Sub_Class;
+ UINT8 Prog_Intf;
+ UINT16 CardSelNum;
+ } pnp;
+ } info;
+ } PXENV_UNDI_GET_NIC_TYPE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ NICType: Type of NIC information stored in the parameter
+ structure.
+ Info: Information about the fields in this union can be found
+ in the [PnP] and [PCI] specifications
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNicType (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NIC_TYPE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_NIC_TYPE_T),
+ PXENV_UNDI_GET_NIC_TYPE
+ );
+}
+
+/**
+ PXE
+ UNDI GET IFACE INFO
+ Op-Code: PXENV_UNDI_GET_IFACE_INFO (0013h)
+ Input: Far pointer to a PXENV_UNDI_GET_IFACE_INFO_t parameter structure that has been initialized
+ by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. If the PXENV_EXIT_SUCCESS is returned, the parameter structure must contain the
+ interface specific information.
+ Description: This call, if successful, provides the network interface specific information such as the interface
+ type at the link layer (Ethernet, Tokenring) and the link speed. This information can be used in the
+ universal drivers such as NDIS or Miniport to communicate to the upper protocol modules.
+ Note: UNDI follows the NDIS2 specification in giving this information. It is the responsibility of the
+ universal driver to translate/convert this information into a format that is required in its specification
+ or to suit the expectation of the upper level protocol modules.
+ PXENV_START_UNDI, PXENV_UNDI_STARTUP and PXENV_UNDI_INITIALIZE must be called
+ before the information provided is valid.
+ typedef struct {
+ PXENV_STATUS Status
+ UINT8 IfaceType[16];
+ UINT32 LinkSpeed;
+ UINT32 ServiceFlags;
+ UINT32 Reserved[4];
+ } PXENV_UNDI_GET_NDIS_INFO_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ IfaceType: Name of MAC type in ASCIIZ format. This is
+ used by the universal NDIS driver to specify its driver type
+ to the protocol driver.
+ LinkSpeed: Defined in the NDIS 2.0 specification.
+ ServiceFlags: Defined in the NDIS 2.0 specification.
+ Reserved: Must be zero.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetNdisInfo (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_NDIS_INFO_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_NDIS_INFO_T),
+ PXENV_UNDI_GET_NDIS_INFO
+ );
+}
+
+/**
+ PXE
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a PXENV_UNDI_ISR_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+ Note: Interrupt Service Routine Operation:
+ In this design the UNDI does not hook the interrupt for the Network Interface. Instead, the
+ application or the protocol driver hooks the interrupt and calls UNDI with the PXENV_UNDI_ISR
+ API call for interrupt verification (PXENV_UNDI_ISR_IN_START) and processing
+ (PXENV_UNDI_ISR_IN_PROCESS and PXENV_UNDI_ISR_GET_NEXT).
+ When the Network Interface HW generates an interrupt the protocol driver interrupt service
+ routine (ISR) gets control and takes care of the interrupt processing at the PIC level. The ISR then
+ calls the UNDI using the PXENV_UNDI_ISR API with the value PXENV_UNDI_ISR_IN_START for
+ the FuncFlag parameter. At this time UNDI must disable the interrupts at the Network Interface
+ level and read any status values required to further process the interrupt. UNDI must return as
+ quickly as possible with one of the two values, PXENV_UNDI_ISR_OUT_OURS or
+ PXENV_UNDI_ISR_OUT_NOT_OURS, for the parameter FuncFlag depending on whether the
+ interrupt was generated by this particular Network Interface or not.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_NOT_OURS, then the interrupt was
+ not generated by our NIC, and interrupt processing is complete.
+ If the value returned in FuncFlag is PXENV_UNDI_ISR_OUT_OURS, the protocol driver must start
+ a handler thread and send an end-of-interrupt (EOI) command to the PIC. Interrupt processing is
+ now complete.
+ The protocol driver strategy routine will call UNDI using this same API with FuncFlag equal to
+ PXENV_UNDI_ISR_IN_PROCESS. At this time UNDI must find the cause of this interrupt and
+ return the status in the FuncFlag. It first checks if there is a frame received and if so it returns the
+ first buffer pointer of that frame in the parameter block.
+ The protocol driver calls UNDI repeatedly with the FuncFlag equal to
+ PXENV_UNDI_ISR_IN_GET_NEXT to get all the buffers in a frame and also all the received
+ frames in the queue. On this call, UNDI must remember the previous buffer given to the protoco,l
+ remove it from the receive queue and recycle it. In case of a multi-buffered frame, if the previous
+ buffer is not the last buffer in the frame it must return the next buffer in the frame in the parameter
+ block. Otherwise it must return the first buffer in the next frame.
+ If there is no received frame pending to be processed, UNDI processes the transmit completes and
+ if there is no other interrupt status to be processed, UNDI re-enables the interrupt at the
+ NETWORK INTERFACE level and returns PXENV_UNDI_ISR_OUT_DONE in the FuncFlag.
+ IMPORTANT: It is possible for the protocol driver to be interrupted again while in the
+ strategy routine when the UNDI re-enables interrupts.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiIsr (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_ISR_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_ISR_T),
+ PXENV_UNDI_ISR
+ );
+}
+
+/**
+ PXE
+ STOP UNDI
+ Op-Code: PXENV_STOP_UNDI (0015h)
+ Input: Far pointer to a PXENV_STOP_UNDI_T parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This routine is responsible for unhooking the Int 1Ah service routine.
+ Note: This API service must be called only once at the end of UNDI Option ROM boot. One of the valid
+ status codes is PXENV_STATUS_KEEP. If this status is returned, UNDI must not be removed from
+ base memory. Also, UNDI must not be removed from base memory if BC is not removed from base
+ memory.
+ Service cannot be used in protected mode.
+ typedef struct {
+ PXENV_STATUS Status;
+ } PXENV_STOP_UNDI_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiStop (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_STOP_UNDI_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_STOP_UNDI_T),
+ PXENV_STOP_UNDI
+ );
+}
+
+/**
+ PXE
+ UNDI GET STATE
+ Op-Code: PXENV_UNDI_GET_STATE (0015h)
+ Input: Far pointer to a PXENV_UNDI_GET_STATE_T parameter.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants. The UNDI_STATE field in the parameter structure must be set to one of the valid state
+ constants
+ Description: This call can be used to obtain state of the UNDI engine in order to avoid issuing adverse call
+ sequences
+ typedef struct {
+ #define PXE_UNDI_GET_STATE_STARTED 1
+ #define PXE_UNDI_GET_STATE_INITIALIZED 2
+ #define PXE_UNDI_GET_STATE_OPENED 3
+ PXENV_STATUS Status;
+ UINT8 UNDIstate;
+ } PXENV_UNDI_GET_STATE_T;
+ Set before calling API service
+ N/A
+ Returned from API service
+ Status: See the PXENV_STATUS_xxx constants.
+ State: See definitions of the state constants.
+ Note. UNDI implementation is responsible for maintaining
+ internal state machine.
+ UNDI ISR
+ Op-Code: PXENV_UNDI_ISR (0014h)
+ Input: Far pointer to a t_PXENV_UNDI_ISR parameter structure that has been initialized by the caller.
+ Output: PXENV_EXIT_SUCCESS or PXENV_EXIT_FAILURE must be returned in AX. The status field in
+ the parameter structure must be set to one of the values represented by the PXENV_STATUS_xxx
+ constants.
+ Description: This API function will be called at different levels of processing the interrupt. The FuncFlag field in
+ the parameter block indicates the operation to be performed for the call. This field is filled with the
+ status of that operation on return.
+
+ @param SimpleNetworkDevice Device instance
+ @param PxeUndiTable Point to structure which hold paramter and return value
+ for option ROM call.
+
+ @return Return value of PXE option ROM far call.
+**/
+EFI_STATUS
+PxeUndiGetState (
+ IN EFI_SIMPLE_NETWORK_DEV *SimpleNetworkDevice,
+ IN OUT PXENV_UNDI_GET_STATE_T *PxeUndiTable
+ )
+{
+ return MakePxeCall (
+ SimpleNetworkDevice,
+ PxeUndiTable,
+ sizeof (PXENV_UNDI_GET_STATE_T),
+ PXENV_UNDI_GET_STATE
+ );
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
new file mode 100644
index 0000000000..2e6b0c532d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
@@ -0,0 +1,73 @@
+## @file
+# SNP driver On Legacy NIC ROM.
+#
+# Thunk wrapper UEFI driver to produce EFI SNP protocol based on legacy 16 NIC ROM.
+#
+# Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ BASE_NAME = BiosSnp16
+ MODULE_UNI_FILE = BiosSnp16.uni
+ FILE_GUID = D0CAA91E-2DE4-4b0d-B3DC-09C67E854E34
+ MODULE_TYPE = UEFI_DRIVER
+ INF_VERSION = 0x00010005
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosSnp16DriverEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosSnp16DriverBinding
+# COMPONENT_NAME = gBiosSnp16ComponentName
+#
+
+[Sources]
+ BiosSnp16.h
+ BiosSnp16.c
+ Misc.c
+ Pxe.h
+ PxeUndi.c
+ ComponentName.c
+
+
+[Libraryclasses]
+ UefiDriverEntryPoint
+ DebugLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiLib
+ BaseLib
+ DevicePathLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ##CONSUMES ##Event
+
+[Protocols]
+ gEfiNetworkInterfaceIdentifierProtocolGuid ##BY_START
+ gEfiDevicePathProtocolGuid ##BY_START
+ gEfiDevicePathProtocolGuid ##TO_START
+ gEfiSimpleNetworkProtocolGuid ##BY_START
+ gEfiPciIoProtocolGuid ##TO_START
+ gEfiLegacyBiosProtocolGuid ##CONSUMES
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BiosSnp16Extra.uni
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
new file mode 100644
index 0000000000..f1c8b29508
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.c
@@ -0,0 +1,3296 @@
+/** @file
+ ConsoleOut Routines that speak VGA.
+
+Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosVideo.h"
+
+//
+// EFI Driver Binding Protocol Instance
+//
+EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding = {
+ BiosVideoDriverBindingSupported,
+ BiosVideoDriverBindingStart,
+ BiosVideoDriverBindingStop,
+ 0x3,
+ NULL,
+ NULL
+};
+
+//
+// Global lookup tables for VGA graphics modes
+//
+UINT8 mVgaLeftMaskTable[] = { 0xff, 0x7f, 0x3f, 0x1f, 0x0f, 0x07, 0x03, 0x01 };
+
+UINT8 mVgaRightMaskTable[] = { 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe, 0xff };
+
+UINT8 mVgaBitMaskTable[] = { 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02, 0x01 };
+
+//
+// Save controller attributes during first start
+//
+UINT64 mOriginalPciAttributes;
+BOOLEAN mPciAttributesSaved = FALSE;
+
+EFI_GRAPHICS_OUTPUT_BLT_PIXEL mVgaColorToGraphicsOutputColor[] = {
+ { 0x00, 0x00, 0x00, 0x00 },
+ { 0x98, 0x00, 0x00, 0x00 },
+ { 0x00, 0x98, 0x00, 0x00 },
+ { 0x98, 0x98, 0x00, 0x00 },
+ { 0x00, 0x00, 0x98, 0x00 },
+ { 0x98, 0x00, 0x98, 0x00 },
+ { 0x00, 0x98, 0x98, 0x00 },
+ { 0x98, 0x98, 0x98, 0x00 },
+ { 0x10, 0x10, 0x10, 0x00 },
+ { 0xff, 0x10, 0x10, 0x00 },
+ { 0x10, 0xff, 0x10, 0x00 },
+ { 0xff, 0xff, 0x10, 0x00 },
+ { 0x10, 0x10, 0xff, 0x00 },
+ { 0xf0, 0x10, 0xff, 0x00 },
+ { 0x10, 0xff, 0xff, 0x00 },
+ { 0xff, 0xff, 0xff, 0x00 }
+};
+
+//
+// Standard timing defined by VESA EDID
+//
+VESA_BIOS_EXTENSIONS_EDID_TIMING mEstablishedEdidTiming[] = {
+ //
+ // Established Timing I
+ //
+ {800, 600, 60},
+ {800, 600, 56},
+ {640, 480, 75},
+ {640, 480, 72},
+ {640, 480, 67},
+ {640, 480, 60},
+ {720, 400, 88},
+ {720, 400, 70},
+ //
+ // Established Timing II
+ //
+ {1280, 1024, 75},
+ {1024, 768, 75},
+ {1024, 768, 70},
+ {1024, 768, 60},
+ {1024, 768, 87},
+ {832, 624, 75},
+ {800, 600, 75},
+ {800, 600, 72},
+ //
+ // Established Timing III
+ //
+ {1152, 870, 75}
+};
+
+/**
+ Supported.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
+ driver, Otherwise, this controller cannot be
+ managed by this driver
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ EFI_DEV_PATH *Node;
+
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ if (Status == EFI_ALREADY_STARTED) {
+ //
+ // If VgaMiniPort protocol is installed, EFI_ALREADY_STARTED indicates failure,
+ // because VgaMiniPort protocol is installed on controller handle directly.
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ NULL,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ //
+ // See if this is a PCI Graphics Controller by looking at the Command register and
+ // Class Code Register
+ //
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ Status = EFI_UNSUPPORTED;
+ if (Pci.Hdr.ClassCode[2] == 0x03 || (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01)) {
+
+ Status = EFI_SUCCESS;
+ //
+ // If this is a graphics controller,
+ // go further check RemainingDevicePath validation
+ //
+ if (RemainingDevicePath != NULL) {
+ Node = (EFI_DEV_PATH *) RemainingDevicePath;
+ //
+ // Check if RemainingDevicePath is the End of Device Path Node,
+ // if yes, return EFI_SUCCESS
+ //
+ if (!IsDevicePathEnd (Node)) {
+ //
+ // If RemainingDevicePath isn't the End of Device Path Node,
+ // check its validation
+ //
+ if (Node->DevPath.Type != ACPI_DEVICE_PATH ||
+ Node->DevPath.SubType != ACPI_ADR_DP ||
+ DevicePathNodeLength(&Node->DevPath) < sizeof(ACPI_ADR_DEVICE_PATH)) {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+ }
+ }
+
+Done:
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return Status;
+}
+
+
+/**
+ Install Graphics Output Protocol onto VGA device handles.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Flags;
+ UINT64 Supports;
+
+ //
+ // Initialize local variables
+ //
+ PciIo = NULL;
+ ParentDevicePath = NULL;
+
+ //
+ //
+ // See if the Legacy BIOS Protocol is available
+ //
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Prepare for status code
+ //
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ParentDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Open the IO Abstraction(s) needed
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_ALREADY_STARTED)) {
+ return Status;
+ }
+
+ //
+ // Save original PCI attributes
+ //
+ if (!mPciAttributesSaved) {
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationGet,
+ 0,
+ &mOriginalPciAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ mPciAttributesSaved = TRUE;
+ }
+
+ //
+ // Get supported PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Supports &= (UINT64)(EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
+ if (Supports == 0 || Supports == (EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16)) {
+ Status = EFI_UNSUPPORTED;
+ goto Done;
+ }
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
+ ParentDevicePath
+ );
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | Supports,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_RESOURCE_CONFLICT,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+ //
+ // Check to see if there is a legacy option ROM image associated with this PCI device
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ //
+ // Post the legacy option ROM if it is available.
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_P_PC_RESET,
+ ParentDevicePath
+ );
+ Status = LegacyBios->InstallPciRom (
+ LegacyBios,
+ Controller,
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+
+ if (RemainingDevicePath != NULL) {
+ if (IsDevicePathEnd (RemainingDevicePath) &&
+ (FeaturePcdGet (PcdBiosVideoCheckVbeEnable) || FeaturePcdGet (PcdBiosVideoCheckVgaEnable))) {
+ //
+ // If RemainingDevicePath is the End of Device Path Node,
+ // don't create any child device and return EFI_SUCESS
+ Status = EFI_SUCCESS;
+ goto Done;
+ }
+ }
+
+ //
+ // Create child handle and install GraphicsOutputProtocol on it
+ //
+ Status = BiosVideoChildHandleInstall (
+ This,
+ Controller,
+ PciIo,
+ LegacyBios,
+ ParentDevicePath,
+ RemainingDevicePath
+ );
+
+Done:
+ if ((EFI_ERROR (Status)) && (Status != EFI_ALREADY_STARTED)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
+ ParentDevicePath
+ );
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_NOT_DETECTED,
+ ParentDevicePath
+ );
+ if (!HasChildHandle (Controller)) {
+ if (mPciAttributesSaved) {
+ //
+ // Restore original PCI attributes
+ //
+ PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ mOriginalPciAttributes,
+ NULL
+ );
+ }
+ }
+ //
+ // Release PCI I/O Protocols on the controller handle.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+ }
+
+ return Status;
+}
+
+
+/**
+ Stop.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param NumberOfChildren Number of children handle created by this driver
+ @param ChildHandleBuffer Buffer containing child handle created
+
+ @retval EFI_SUCCESS Driver disconnected successfully from controller
+ @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN AllChildrenStopped;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ AllChildrenStopped = TRUE;
+
+ if (NumberOfChildren == 0) {
+ //
+ // Close PCI I/O protocol on the controller handle
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ return EFI_SUCCESS;
+ }
+
+ for (Index = 0; Index < NumberOfChildren; Index++) {
+ Status = BiosVideoChildHandleUninstall (This, Controller, ChildHandleBuffer[Index]);
+
+ if (EFI_ERROR (Status)) {
+ AllChildrenStopped = FALSE;
+ }
+ }
+
+ if (!AllChildrenStopped) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (!HasChildHandle (Controller)) {
+ if (mPciAttributesSaved) {
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Restore original PCI attributes
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSet,
+ mOriginalPciAttributes,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param This Calling context.
+ @param ParentHandle Parent Handle
+ @param ParentPciIo Parent PciIo interface
+ @param ParentLegacyBios Parent LegacyBios interface
+ @param ParentDevicePath Parent Device Path
+ @param RemainingDevicePath Remaining Device Path
+
+ @retval EFI_SUCCESS If a child handle was added
+ @retval other A child handle was not added
+
+**/
+EFI_STATUS
+BiosVideoChildHandleInstall (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
+ IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ PCI_TYPE00 Pci;
+ ACPI_ADR_DEVICE_PATH AcpiDeviceNode;
+ BOOLEAN ProtocolInstalled;
+
+ //
+ // Allocate the private device structure for video device
+ //
+ BiosVideoPrivate = (BIOS_VIDEO_DEV *) AllocateZeroPool (
+ sizeof (BIOS_VIDEO_DEV)
+ );
+ if (NULL == BiosVideoPrivate) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // See if this is a VGA compatible controller or not
+ //
+ Status = ParentPciIo->Pci.Read (
+ ParentPciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+ if (EFI_ERROR (Status)) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
+ ParentDevicePath
+ );
+ goto Done;
+ }
+ BiosVideoPrivate->VgaCompatible = FALSE;
+ if (Pci.Hdr.ClassCode[2] == 0x00 && Pci.Hdr.ClassCode[1] == 0x01) {
+ BiosVideoPrivate->VgaCompatible = TRUE;
+ }
+
+ if (Pci.Hdr.ClassCode[2] == 0x03 && Pci.Hdr.ClassCode[1] == 0x00 && Pci.Hdr.ClassCode[0] == 0x00) {
+ BiosVideoPrivate->VgaCompatible = TRUE;
+ }
+
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
+ //
+ // Create EXIT_BOOT_SERIVES Event
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ BiosVideoNotifyExitBootServices,
+ BiosVideoPrivate,
+ &gEfiEventExitBootServicesGuid,
+ &BiosVideoPrivate->ExitBootServicesEvent
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Initialize the child private structure
+ //
+ BiosVideoPrivate->Signature = BIOS_VIDEO_DEV_SIGNATURE;
+
+ //
+ // Fill in Graphics Output specific mode structures
+ //
+ BiosVideoPrivate->HardwareNeedsStarting = TRUE;
+ BiosVideoPrivate->ModeData = NULL;
+ BiosVideoPrivate->LineBuffer = NULL;
+ BiosVideoPrivate->VgaFrameBuffer = NULL;
+ BiosVideoPrivate->VbeFrameBuffer = NULL;
+
+ //
+ // Fill in the Graphics Output Protocol
+ //
+ BiosVideoPrivate->GraphicsOutput.QueryMode = BiosVideoGraphicsOutputQueryMode;
+ BiosVideoPrivate->GraphicsOutput.SetMode = BiosVideoGraphicsOutputSetMode;
+
+
+ //
+ // Allocate buffer for Graphics Output Protocol mode information
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode = (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_PROTOCOL_MODE)
+ );
+ if (NULL == BiosVideoPrivate->GraphicsOutput.Mode) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+ );
+ if (NULL == BiosVideoPrivate->GraphicsOutput.Mode->Info) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ //
+ // Assume that Graphics Output Protocol will be produced until proven otherwise
+ //
+ BiosVideoPrivate->ProduceGraphicsOutput = TRUE;
+
+ //
+ // Set Gop Device Path, here RemainingDevicePath will not be one End of Device Path Node.
+ //
+ if ((RemainingDevicePath == NULL) || (!IsDevicePathEnd (RemainingDevicePath))) {
+ if (RemainingDevicePath == NULL) {
+ ZeroMem (&AcpiDeviceNode, sizeof (ACPI_ADR_DEVICE_PATH));
+ AcpiDeviceNode.Header.Type = ACPI_DEVICE_PATH;
+ AcpiDeviceNode.Header.SubType = ACPI_ADR_DP;
+ AcpiDeviceNode.ADR = ACPI_DISPLAY_ADR (1, 0, 0, 1, 0, ACPI_ADR_DISPLAY_TYPE_VGA, 0, 0);
+ SetDevicePathNodeLength (&AcpiDeviceNode.Header, sizeof (ACPI_ADR_DEVICE_PATH));
+
+ BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (
+ ParentDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &AcpiDeviceNode
+ );
+ } else {
+ BiosVideoPrivate->GopDevicePath = AppendDevicePathNode (ParentDevicePath, RemainingDevicePath);
+ }
+
+ //
+ // Creat child handle and device path protocol firstly
+ //
+ BiosVideoPrivate->Handle = NULL;
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosVideoPrivate->Handle,
+ &gEfiDevicePathProtocolGuid,
+ BiosVideoPrivate->GopDevicePath,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ }
+
+ //
+ // Fill in the VGA Mini Port Protocol fields
+ //
+ BiosVideoPrivate->VgaMiniPort.SetMode = BiosVideoVgaMiniPortSetMode;
+ BiosVideoPrivate->VgaMiniPort.VgaMemoryOffset = 0xb8000;
+ BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterOffset = 0x3d4;
+ BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterOffset = 0x3d5;
+ BiosVideoPrivate->VgaMiniPort.VgaMemoryBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ BiosVideoPrivate->VgaMiniPort.CrtcAddressRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+ BiosVideoPrivate->VgaMiniPort.CrtcDataRegisterBar = EFI_PCI_IO_PASS_THROUGH_BAR;
+
+ //
+ // Child handle need to consume the Legacy Bios protocol
+ //
+ BiosVideoPrivate->LegacyBios = ParentLegacyBios;
+
+ //
+ // When check for VBE, PCI I/O protocol is needed, so use parent's protocol interface temporally
+ //
+ BiosVideoPrivate->PciIo = ParentPciIo;
+
+ //
+ // Check for VESA BIOS Extensions for modes that are compatible with Graphics Output
+ //
+ if (FeaturePcdGet (PcdBiosVideoCheckVbeEnable)) {
+ Status = BiosVideoCheckForVbe (BiosVideoPrivate);
+ DEBUG ((EFI_D_INFO, "BiosVideoCheckForVbe - %r\n", Status));
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ if (EFI_ERROR (Status)) {
+ //
+ // The VESA BIOS Extensions are not compatible with Graphics Output, so check for support
+ // for the standard 640x480 16 color VGA mode
+ //
+ DEBUG ((EFI_D_INFO, "VgaCompatible - %x\n", BiosVideoPrivate->VgaCompatible));
+ if (BiosVideoPrivate->VgaCompatible) {
+ if (FeaturePcdGet (PcdBiosVideoCheckVgaEnable)) {
+ Status = BiosVideoCheckForVga (BiosVideoPrivate);
+ DEBUG ((EFI_D_INFO, "BiosVideoCheckForVga - %r\n", Status));
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Free GOP mode structure if it is not freed before
+ // VgaMiniPort does not need this structure any more
+ //
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ BiosVideoPrivate->GraphicsOutput.Mode = NULL;
+ }
+
+ //
+ // Neither VBE nor the standard 640x480 16 color VGA mode are supported, so do
+ // not produce the Graphics Output protocol. Instead, produce the VGA MiniPort Protocol.
+ //
+ BiosVideoPrivate->ProduceGraphicsOutput = FALSE;
+
+ //
+ // INT services are available, so on the 80x25 and 80x50 text mode are supported
+ //
+ BiosVideoPrivate->VgaMiniPort.MaxMode = 2;
+ }
+ }
+
+ ProtocolInstalled = FALSE;
+
+ if (BiosVideoPrivate->ProduceGraphicsOutput) {
+ //
+ // Creat child handle and install Graphics Output Protocol,EDID Discovered/Active Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BiosVideoPrivate->Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ &BiosVideoPrivate->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &BiosVideoPrivate->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &BiosVideoPrivate->EdidActive,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Open the Parent Handle for the child
+ //
+ Status = gBS->OpenProtocol (
+ ParentHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &BiosVideoPrivate->PciIo,
+ This->DriverBindingHandle,
+ BiosVideoPrivate->Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ProtocolInstalled = TRUE;
+ }
+ }
+
+ if (!ProtocolInstalled) {
+ //
+ // Install VGA Mini Port Protocol
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &ParentHandle,
+ &gEfiVgaMiniPortProtocolGuid,
+ &BiosVideoPrivate->VgaMiniPort,
+ NULL
+ );
+ }
+
+Done:
+ if (EFI_ERROR (Status)) {
+ if ((BiosVideoPrivate != NULL) && (BiosVideoPrivate->ExitBootServicesEvent != NULL)) {
+ gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
+ }
+ //
+ // Free private data structure
+ //
+ BiosVideoDeviceReleaseResource (BiosVideoPrivate);
+ }
+
+ return Status;
+}
+
+
+/**
+ Deregister an video child handle and free resources.
+
+ @param This Protocol instance pointer.
+ @param Controller Video controller handle
+ @param Handle Video child handle
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+BiosVideoChildHandleUninstall (
+ EFI_DRIVER_BINDING_PROTOCOL *This,
+ EFI_HANDLE Controller,
+ EFI_HANDLE Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ BiosVideoPrivate = NULL;
+ GraphicsOutput = NULL;
+ PciIo = NULL;
+ Status = EFI_UNSUPPORTED;
+
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (GraphicsOutput);
+ }
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiVgaMiniPortProtocolGuid,
+ (VOID **) &VgaMiniPort,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (!EFI_ERROR (Status)) {
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (VgaMiniPort);
+ }
+ }
+
+ if (BiosVideoPrivate == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x03;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x14;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // Close PCI I/O protocol that opened by child handle
+ //
+ Status = gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Handle
+ );
+
+ //
+ // Uninstall protocols on child handle
+ //
+ if (BiosVideoPrivate->ProduceGraphicsOutput) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ BiosVideoPrivate->Handle,
+ &gEfiDevicePathProtocolGuid,
+ BiosVideoPrivate->GopDevicePath,
+ &gEfiGraphicsOutputProtocolGuid,
+ &BiosVideoPrivate->GraphicsOutput,
+ &gEfiEdidDiscoveredProtocolGuid,
+ &BiosVideoPrivate->EdidDiscovered,
+ &gEfiEdidActiveProtocolGuid,
+ &BiosVideoPrivate->EdidActive,
+ NULL
+ );
+ }
+ if (!BiosVideoPrivate->ProduceGraphicsOutput) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ &BiosVideoPrivate->VgaMiniPort,
+ NULL
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Handle,
+ EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER
+ );
+ return Status;
+ }
+
+ if (PcdGetBool (PcdBiosVideoSetTextVgaModeEnable)) {
+ //
+ // Close EXIT_BOOT_SERIVES Event
+ //
+ gBS->CloseEvent (BiosVideoPrivate->ExitBootServicesEvent);
+ }
+
+ //
+ // Release all allocated resources
+ //
+ BiosVideoDeviceReleaseResource (BiosVideoPrivate);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ if (BiosVideoPrivate == NULL) {
+ return ;
+ }
+
+ //
+ // Release all the resourses occupied by the BIOS_VIDEO_DEV
+ //
+
+ //
+ // Free VGA Frame Buffer
+ //
+ if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VgaFrameBuffer);
+ }
+ //
+ // Free VBE Frame Buffer
+ //
+ if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VbeFrameBuffer);
+ }
+ //
+ // Free line buffer
+ //
+ if (BiosVideoPrivate->LineBuffer != NULL) {
+ FreePool (BiosVideoPrivate->LineBuffer);
+ }
+ //
+ // Free mode data
+ //
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ }
+ //
+ // Free memory allocated below 1MB
+ //
+ if (BiosVideoPrivate->PagesBelow1MB != 0) {
+ gBS->FreePages (BiosVideoPrivate->PagesBelow1MB, BiosVideoPrivate->NumberOfPagesBelow1MB);
+ }
+
+ if (BiosVideoPrivate->VbeSaveRestorePages != 0) {
+ gBS->FreePages (BiosVideoPrivate->VbeSaveRestoreBuffer, BiosVideoPrivate->VbeSaveRestorePages);
+ }
+
+ //
+ // Free graphics output protocol occupied resource
+ //
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ BiosVideoPrivate->GraphicsOutput.Mode = NULL;
+ }
+ //
+ // Free EDID discovered protocol occupied resource
+ //
+ if (BiosVideoPrivate->EdidDiscovered.Edid != NULL) {
+ FreePool (BiosVideoPrivate->EdidDiscovered.Edid);
+ }
+ //
+ // Free EDID active protocol occupied resource
+ //
+ if (BiosVideoPrivate->EdidActive.Edid != NULL) {
+ FreePool (BiosVideoPrivate->EdidActive.Edid);
+ }
+
+ if (BiosVideoPrivate->GopDevicePath!= NULL) {
+ FreePool (BiosVideoPrivate->GopDevicePath);
+ }
+
+ FreePool (BiosVideoPrivate);
+
+ return ;
+}
+
+
+/**
+ Generate a search key for a specified timing data.
+
+ @param EdidTiming Pointer to EDID timing
+
+ @return The 32 bit unique key for search.
+
+**/
+UINT32
+CalculateEdidKey (
+ VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Key;
+
+ //
+ // Be sure no conflicts for all standard timing defined by VESA.
+ //
+ Key = (EdidTiming->HorizontalResolution * 2) + EdidTiming->VerticalResolution;
+ return Key;
+}
+
+
+/**
+ Parse the Established Timing and Standard Timing in EDID data block.
+
+ @param EdidBuffer Pointer to EDID data block
+ @param ValidEdidTiming Valid EDID timing information
+
+ @retval TRUE The EDID data is valid.
+ @retval FALSE The EDID data is invalid.
+
+**/
+BOOLEAN
+ParseEdidData (
+ UINT8 *EdidBuffer,
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming
+ )
+{
+ UINT8 CheckSum;
+ UINT32 Index;
+ UINT32 ValidNumber;
+ UINT32 TimingBits;
+ UINT8 *BufferIndex;
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT8 AspectRatio;
+ UINT8 RefreshRate;
+ VESA_BIOS_EXTENSIONS_EDID_TIMING TempTiming;
+ VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *EdidDataBlock;
+
+ EdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) EdidBuffer;
+
+ //
+ // Check the checksum of EDID data
+ //
+ CheckSum = 0;
+ for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE; Index ++) {
+ CheckSum = (UINT8) (CheckSum + EdidBuffer[Index]);
+ }
+ if (CheckSum != 0) {
+ return FALSE;
+ }
+
+ ValidNumber = 0;
+ gBS->SetMem (ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING), 0);
+
+ if ((EdidDataBlock->EstablishedTimings[0] != 0) ||
+ (EdidDataBlock->EstablishedTimings[1] != 0) ||
+ (EdidDataBlock->EstablishedTimings[2] != 0)
+ ) {
+ //
+ // Established timing data
+ //
+ TimingBits = EdidDataBlock->EstablishedTimings[0] |
+ (EdidDataBlock->EstablishedTimings[1] << 8) |
+ ((EdidDataBlock->EstablishedTimings[2] & 0x80) << 9) ;
+ for (Index = 0; Index < VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER; Index ++) {
+ if ((TimingBits & 0x1) != 0) {
+ DEBUG ((EFI_D_INFO, "Established Timing: %d x %d\n",
+ mEstablishedEdidTiming[Index].HorizontalResolution, mEstablishedEdidTiming[Index].VerticalResolution));
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&mEstablishedEdidTiming[Index]);
+ ValidNumber ++;
+ }
+ TimingBits = TimingBits >> 1;
+ }
+ }
+
+ //
+ // Parse the standard timing data
+ //
+ BufferIndex = &EdidDataBlock->StandardTimingIdentification[0];
+ for (Index = 0; Index < 8; Index ++) {
+ //
+ // Check if this is a valid Standard Timing entry
+ // VESA documents unused fields should be set to 01h
+ //
+ if ((BufferIndex[0] != 0x1) && (BufferIndex[1] != 0x1)){
+ //
+ // A valid Standard Timing
+ //
+ HorizontalResolution = (UINT16) (BufferIndex[0] * 8 + 248);
+ AspectRatio = (UINT8) (BufferIndex[1] >> 6);
+ switch (AspectRatio) {
+ case 0:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 10);
+ break;
+ case 1:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ case 2:
+ VerticalResolution = (UINT16) (HorizontalResolution / 5 * 4);
+ break;
+ case 3:
+ VerticalResolution = (UINT16) (HorizontalResolution / 16 * 9);
+ break;
+ default:
+ VerticalResolution = (UINT16) (HorizontalResolution / 4 * 3);
+ break;
+ }
+ RefreshRate = (UINT8) ((BufferIndex[1] & 0x1f) + 60);
+ DEBUG ((EFI_D_INFO, "Standard Timing: %d x %d\n", HorizontalResolution, VerticalResolution));
+ TempTiming.HorizontalResolution = HorizontalResolution;
+ TempTiming.VerticalResolution = VerticalResolution;
+ TempTiming.RefreshRate = RefreshRate;
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
+ ValidNumber ++;
+ }
+ BufferIndex += 2;
+ }
+
+ //
+ // Parse the Detailed Timing data
+ //
+ BufferIndex = &EdidDataBlock->DetailedTimingDescriptions[0];
+ for (Index = 0; Index < 4; Index ++, BufferIndex += VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE) {
+ if ((BufferIndex[0] == 0x0) && (BufferIndex[1] == 0x0)) {
+ //
+ // Check if this is a valid Detailed Timing Descriptor
+ // If first 2 bytes are zero, it is monitor descriptor other than detailed timing descriptor
+ //
+ continue;
+ }
+ //
+ // Calculate Horizontal and Vertical resolution
+ //
+ TempTiming.HorizontalResolution = ((UINT16)(BufferIndex[4] & 0xF0) << 4) | (BufferIndex[2]);
+ TempTiming.VerticalResolution = ((UINT16)(BufferIndex[7] & 0xF0) << 4) | (BufferIndex[5]);
+ DEBUG ((EFI_D_INFO, "Detailed Timing %d: %d x %d\n",
+ Index, TempTiming.HorizontalResolution, TempTiming.VerticalResolution));
+ ValidEdidTiming->Key[ValidNumber] = CalculateEdidKey (&TempTiming);
+ ValidNumber ++;
+ }
+
+ ValidEdidTiming->ValidNumber = ValidNumber;
+ return TRUE;
+}
+
+
+/**
+ Search a specified Timing in all the valid EDID timings.
+
+ @param ValidEdidTiming All valid EDID timing information.
+ @param EdidTiming The Timing to search for.
+
+ @retval TRUE Found.
+ @retval FALSE Not found.
+
+**/
+BOOLEAN
+SearchEdidTiming (
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING *ValidEdidTiming,
+ VESA_BIOS_EXTENSIONS_EDID_TIMING *EdidTiming
+ )
+{
+ UINT32 Index;
+ UINT32 Key;
+
+ Key = CalculateEdidKey (EdidTiming);
+
+ for (Index = 0; Index < ValidEdidTiming->ValidNumber; Index ++) {
+ if (Key == ValidEdidTiming->Key[Index]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ Check if all video child handles have been uninstalled.
+
+ @param Controller Video controller handle
+
+ @return TRUE Child handles exist.
+ @return FALSE All video child handles have been uninstalled.
+
+**/
+BOOLEAN
+HasChildHandle (
+ IN EFI_HANDLE Controller
+ )
+{
+ UINTN Index;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ BOOLEAN HasChild;
+
+ EntryCount = 0;
+ HasChild = FALSE;
+ gBS->OpenProtocolInformation (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ HasChild = TRUE;
+ }
+ }
+
+ return HasChild;
+}
+
+/**
+ Check for VBE device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS VBE device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVbe (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 *ModeNumberPtr;
+ UINT16 VbeModeNumber;
+ BOOLEAN ModeFound;
+ BOOLEAN EdidFound;
+ BIOS_VIDEO_MODE_DATA *ModeBuffer;
+ BIOS_VIDEO_MODE_DATA *CurrentModeData;
+ UINTN PreferMode;
+ UINTN ModeNumber;
+ VESA_BIOS_EXTENSIONS_EDID_TIMING Timing;
+ VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING ValidEdidTiming;
+ EFI_EDID_OVERRIDE_PROTOCOL *EdidOverride;
+ UINT32 EdidAttributes;
+ BOOLEAN EdidOverrideFound;
+ UINTN EdidOverrideDataSize;
+ UINT8 *EdidOverrideDataBlock;
+ UINTN EdidActiveDataSize;
+ UINT8 *EdidActiveDataBlock;
+ UINT32 HighestHorizontalResolution;
+ UINT32 HighestVerticalResolution;
+ UINTN HighestResolutionMode;
+
+ EdidFound = TRUE;
+ EdidOverrideFound = FALSE;
+ EdidOverrideDataBlock = NULL;
+ EdidActiveDataSize = 0;
+ EdidActiveDataBlock = NULL;
+ HighestHorizontalResolution = 0;
+ HighestVerticalResolution = 0;
+ HighestResolutionMode = 0;
+
+ //
+ // Allocate buffer under 1MB for VBE data structures
+ //
+ BiosVideoPrivate->NumberOfPagesBelow1MB = EFI_SIZE_TO_PAGES (
+ sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK) +
+ sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK)
+ );
+
+ BiosVideoPrivate->PagesBelow1MB = 0x00100000 - 1;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesData,
+ BiosVideoPrivate->NumberOfPagesBelow1MB,
+ &BiosVideoPrivate->PagesBelow1MB
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&ValidEdidTiming, sizeof (VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING));
+
+ //
+ // Fill in the VBE related data structures
+ //
+ BiosVideoPrivate->VbeInformationBlock = (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *) (UINTN) (BiosVideoPrivate->PagesBelow1MB);
+ BiosVideoPrivate->VbeModeInformationBlock = (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeInformationBlock + 1);
+ BiosVideoPrivate->VbeEdidDataBlock = (VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *) (BiosVideoPrivate->VbeModeInformationBlock + 1);
+ BiosVideoPrivate->VbeCrtcInformationBlock = (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *) (BiosVideoPrivate->VbeEdidDataBlock + 1);
+ BiosVideoPrivate->VbeSaveRestorePages = 0;
+ BiosVideoPrivate->VbeSaveRestoreBuffer = 0;
+
+ //
+ // Test to see if the Video Adapter is compliant with VBE 3.0
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION;
+ gBS->SetMem (BiosVideoPrivate->VbeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK), 0);
+ BiosVideoPrivate->VbeInformationBlock->VESASignature = VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE;
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeInformationBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Status = EFI_DEVICE_ERROR;
+
+ //
+ // See if the VESA call succeeded
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ return Status;
+ }
+ //
+ // Check for 'VESA' signature
+ //
+ if (BiosVideoPrivate->VbeInformationBlock->VESASignature != VESA_BIOS_EXTENSIONS_VESA_SIGNATURE) {
+ return Status;
+ }
+ //
+ // Check to see if this is VBE 2.0 or higher
+ //
+ if (BiosVideoPrivate->VbeInformationBlock->VESAVersion < VESA_BIOS_EXTENSIONS_VERSION_2_0) {
+ return Status;
+ }
+
+ EdidFound = FALSE;
+ EdidAttributes = 0xff;
+ EdidOverrideDataSize = 0;
+
+ //
+ // Find EDID Override protocol firstly, this protocol is installed by platform if needed.
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiEdidOverrideProtocolGuid,
+ NULL,
+ (VOID **) &EdidOverride
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Allocate double size of VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE to avoid overflow
+ //
+ EdidOverrideDataBlock = AllocatePool (VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE * 2);
+ if (NULL == EdidOverrideDataBlock) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ Status = EdidOverride->GetEdid (
+ EdidOverride,
+ BiosVideoPrivate->Handle,
+ &EdidAttributes,
+ &EdidOverrideDataSize,
+ (UINT8 **) &EdidOverrideDataBlock
+ );
+ if (!EFI_ERROR (Status) &&
+ EdidAttributes == 0 &&
+ EdidOverrideDataSize != 0) {
+ //
+ // Succeeded to get EDID Override Data
+ //
+ EdidOverrideFound = TRUE;
+ }
+ }
+
+ if (!EdidOverrideFound || EdidAttributes == EFI_EDID_OVERRIDE_DONT_OVERRIDE) {
+ //
+ // If EDID Override data doesn't exist or EFI_EDID_OVERRIDE_DONT_OVERRIDE returned,
+ // read EDID information through INT10 call
+ //
+
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_EDID;
+ Regs.X.BX = 1;
+ Regs.X.CX = 0;
+ Regs.X.DX = 0;
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeEdidDataBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ //
+ // See if the VESA call succeeded
+ //
+ if (Regs.X.AX == VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ //
+ // Set EDID Discovered Data
+ //
+ BiosVideoPrivate->EdidDiscovered.SizeOfEdid = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
+ BiosVideoPrivate->EdidDiscovered.Edid = (UINT8 *) AllocateCopyPool (
+ VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE,
+ BiosVideoPrivate->VbeEdidDataBlock
+ );
+
+ if (NULL == BiosVideoPrivate->EdidDiscovered.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ EdidFound = TRUE;
+ }
+ }
+
+ if (EdidFound) {
+ EdidActiveDataSize = VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE;
+ EdidActiveDataBlock = BiosVideoPrivate->EdidDiscovered.Edid;
+ } else if (EdidOverrideFound) {
+ EdidActiveDataSize = EdidOverrideDataSize;
+ EdidActiveDataBlock = EdidOverrideDataBlock;
+ EdidFound = TRUE;
+ }
+
+ if (EdidFound) {
+ //
+ // Parse EDID data structure to retrieve modes supported by monitor
+ //
+ if (ParseEdidData ((UINT8 *) EdidActiveDataBlock, &ValidEdidTiming)) {
+ //
+ // Copy EDID Override Data to EDID Active Data
+ //
+ BiosVideoPrivate->EdidActive.SizeOfEdid = (UINT32) EdidActiveDataSize;
+ BiosVideoPrivate->EdidActive.Edid = (UINT8 *) AllocateCopyPool (
+ EdidActiveDataSize,
+ EdidActiveDataBlock
+ );
+ if (NULL == BiosVideoPrivate->EdidActive.Edid) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ } else {
+ BiosVideoPrivate->EdidActive.SizeOfEdid = 0;
+ BiosVideoPrivate->EdidActive.Edid = NULL;
+ EdidFound = FALSE;
+ }
+
+ //
+ // Walk through the mode list to see if there is at least one mode the is compatible with the EDID mode
+ //
+ ModeNumberPtr = (UINT16 *)
+ (
+ (((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0xffff0000) >> 12) |
+ ((UINTN) BiosVideoPrivate->VbeInformationBlock->VideoModePtr & 0x0000ffff)
+ );
+
+ PreferMode = 0;
+ ModeNumber = 0;
+
+ //
+ // ModeNumberPtr may be not 16-byte aligned, so ReadUnaligned16 is used to access the buffer pointed by ModeNumberPtr.
+ //
+ for (VbeModeNumber = ReadUnaligned16 (ModeNumberPtr);
+ VbeModeNumber != VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST;
+ VbeModeNumber = ReadUnaligned16 (++ModeNumberPtr)) {
+ //
+ // Make sure this is a mode number defined by the VESA VBE specification. If it isn'tm then skip this mode number.
+ //
+ if ((VbeModeNumber & VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA) == 0) {
+ continue;
+ }
+ //
+ // Get the information about the mode
+ //
+ gBS->SetMem (&Regs, sizeof (Regs), 0);
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION;
+ Regs.X.CX = VbeModeNumber;
+ gBS->SetMem (BiosVideoPrivate->VbeModeInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK), 0);
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeModeInformationBlock);
+
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // See if the call succeeded. If it didn't, then try the next mode.
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ continue;
+ }
+ //
+ // See if the mode supports color. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports graphics. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports a linear frame buffer. If it doesn't then try the next mode.
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->ModeAttributes & VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER) == 0) {
+ continue;
+ }
+ //
+ // See if the mode supports 32 bit color. If it doesn't then try the next mode.
+ // 32 bit mode can be implemented by 24 Bits Per Pixels. Also make sure the
+ // number of bits per pixel is a multiple of 8 or more than 32 bits per pixel
+ //
+ if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel < 24) {
+ continue;
+ }
+
+ if (BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel > 32) {
+ continue;
+ }
+
+ if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel % 8) != 0) {
+ continue;
+ }
+ //
+ // See if the physical base pointer for the linear mode is valid. If it isn't then try the next mode.
+ //
+ if (BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr == 0) {
+ continue;
+ }
+
+ DEBUG ((EFI_D_INFO, "Video Controller Mode 0x%x: %d x %d\n",
+ VbeModeNumber, BiosVideoPrivate->VbeModeInformationBlock->XResolution, BiosVideoPrivate->VbeModeInformationBlock->YResolution));
+
+ if (EdidFound && (ValidEdidTiming.ValidNumber > 0)) {
+ //
+ // EDID exist, check whether this mode match with any mode in EDID
+ //
+ Timing.HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
+ Timing.VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
+ if (!SearchEdidTiming (&ValidEdidTiming, &Timing)) {
+ //
+ // When EDID comes from INT10 call, EDID does not include 800x600, 640x480 and 1024x768,
+ // but INT10 can support these modes, we add them into GOP mode.
+ //
+ if ((BiosVideoPrivate->EdidDiscovered.SizeOfEdid != 0) &&
+ !((Timing.HorizontalResolution) == 1024 && (Timing.VerticalResolution == 768)) &&
+ !((Timing.HorizontalResolution) == 800 && (Timing.VerticalResolution == 600)) &&
+ !((Timing.HorizontalResolution) == 640 && (Timing.VerticalResolution == 480))) {
+ continue;
+ }
+ }
+ }
+
+ //
+ // Select a reasonable mode to be set for current display mode
+ //
+ ModeFound = FALSE;
+
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 1024 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 768
+ ) {
+ ModeFound = TRUE;
+ }
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 800 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 600
+ ) {
+ ModeFound = TRUE;
+ PreferMode = ModeNumber;
+ }
+ if (BiosVideoPrivate->VbeModeInformationBlock->XResolution == 640 &&
+ BiosVideoPrivate->VbeModeInformationBlock->YResolution == 480
+ ) {
+ ModeFound = TRUE;
+ }
+
+ if ((!EdidFound) && (!ModeFound)) {
+ //
+ // When no EDID exist, only select three possible resolutions, i.e. 1024x768, 800x600, 640x480
+ //
+ continue;
+ }
+
+ //
+ // Record the highest resolution mode to set later
+ //
+ if ((BiosVideoPrivate->VbeModeInformationBlock->XResolution > HighestHorizontalResolution) ||
+ ((BiosVideoPrivate->VbeModeInformationBlock->XResolution == HighestHorizontalResolution) &&
+ (BiosVideoPrivate->VbeModeInformationBlock->YResolution > HighestVerticalResolution))) {
+ HighestHorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
+ HighestVerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
+ HighestResolutionMode = ModeNumber;
+ }
+
+ //
+ // Add mode to the list of available modes
+ //
+ ModeNumber ++;
+ ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
+ ModeNumber * sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ if (NULL == ModeBuffer) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ if (ModeNumber > 1) {
+ CopyMem (
+ ModeBuffer,
+ BiosVideoPrivate->ModeData,
+ (ModeNumber - 1) * sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ }
+
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ }
+
+ CurrentModeData = &ModeBuffer[ModeNumber - 1];
+ CurrentModeData->VbeModeNumber = VbeModeNumber;
+ if (BiosVideoPrivate->VbeInformationBlock->VESAVersion >= VESA_BIOS_EXTENSIONS_VERSION_3_0) {
+ CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->LinBytesPerScanLine;
+ CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRedFieldPosition;
+ CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRedMaskSize) - 1);
+ CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->LinBlueFieldPosition;
+ CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinBlueMaskSize) - 1);
+ CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->LinGreenFieldPosition;
+ CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinGreenMaskSize) - 1);
+ CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->LinRsvdFieldPosition;
+ CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->LinRsvdMaskSize) - 1);
+ } else {
+ CurrentModeData->BytesPerScanLine = BiosVideoPrivate->VbeModeInformationBlock->BytesPerScanLine;
+ CurrentModeData->Red.Position = BiosVideoPrivate->VbeModeInformationBlock->RedFieldPosition;
+ CurrentModeData->Red.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RedMaskSize) - 1);
+ CurrentModeData->Blue.Position = BiosVideoPrivate->VbeModeInformationBlock->BlueFieldPosition;
+ CurrentModeData->Blue.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->BlueMaskSize) - 1);
+ CurrentModeData->Green.Position = BiosVideoPrivate->VbeModeInformationBlock->GreenFieldPosition;
+ CurrentModeData->Green.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->GreenMaskSize) - 1);
+ CurrentModeData->Reserved.Position = BiosVideoPrivate->VbeModeInformationBlock->RsvdFieldPosition;
+ CurrentModeData->Reserved.Mask = (UINT8) ((1 << BiosVideoPrivate->VbeModeInformationBlock->RsvdMaskSize) - 1);
+ }
+
+ CurrentModeData->PixelFormat = PixelBitMask;
+ if ((BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel == 32) &&
+ (CurrentModeData->Red.Mask == 0xff) && (CurrentModeData->Green.Mask == 0xff) && (CurrentModeData->Blue.Mask == 0xff)) {
+ if ((CurrentModeData->Red.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Blue.Position == 16)) {
+ CurrentModeData->PixelFormat = PixelRedGreenBlueReserved8BitPerColor;
+ } else if ((CurrentModeData->Blue.Position == 0) && (CurrentModeData->Green.Position == 8) && (CurrentModeData->Red.Position == 16)) {
+ CurrentModeData->PixelFormat = PixelBlueGreenRedReserved8BitPerColor;
+ }
+ }
+
+ CurrentModeData->PixelBitMask.RedMask = ((UINT32) CurrentModeData->Red.Mask) << CurrentModeData->Red.Position;
+ CurrentModeData->PixelBitMask.GreenMask = ((UINT32) CurrentModeData->Green.Mask) << CurrentModeData->Green.Position;
+ CurrentModeData->PixelBitMask.BlueMask = ((UINT32) CurrentModeData->Blue.Mask) << CurrentModeData->Blue.Position;
+ CurrentModeData->PixelBitMask.ReservedMask = ((UINT32) CurrentModeData->Reserved.Mask) << CurrentModeData->Reserved.Position;
+
+ CurrentModeData->LinearFrameBuffer = (VOID *) (UINTN)BiosVideoPrivate->VbeModeInformationBlock->PhysBasePtr;
+ CurrentModeData->HorizontalResolution = BiosVideoPrivate->VbeModeInformationBlock->XResolution;
+ CurrentModeData->VerticalResolution = BiosVideoPrivate->VbeModeInformationBlock->YResolution;
+
+ CurrentModeData->BitsPerPixel = BiosVideoPrivate->VbeModeInformationBlock->BitsPerPixel;
+ CurrentModeData->FrameBufferSize = CurrentModeData->BytesPerScanLine * CurrentModeData->VerticalResolution;
+ //
+ // Make sure the FrameBufferSize does not exceed the max available frame buffer size reported by VEB.
+ //
+ ASSERT (CurrentModeData->FrameBufferSize <= (UINTN)(BiosVideoPrivate->VbeInformationBlock->TotalMemory * 64 * 1024));
+
+ BiosVideoPrivate->ModeData = ModeBuffer;
+ }
+ //
+ // Check to see if we found any modes that are compatible with GRAPHICS OUTPUT
+ //
+ if (ModeNumber == 0) {
+ Status = EFI_DEVICE_ERROR;
+ goto Done;
+ }
+
+ //
+ // Assign Gop's Blt function
+ //
+ BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVbeBlt;
+
+ BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = (UINT32) ModeNumber;
+ //
+ // Current mode is unknow till now, set it to an invalid mode.
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+
+ //
+ // Find the best mode to initialize
+ //
+ if ((PcdGet32 (PcdVideoHorizontalResolution) == 0x0) || (PcdGet32 (PcdVideoVerticalResolution) == 0x0)) {
+ DEBUG_CODE (
+ BIOS_VIDEO_MODE_DATA *ModeData;
+ ModeData = &BiosVideoPrivate->ModeData[HighestResolutionMode];
+ DEBUG ((EFI_D_INFO, "BiosVideo set highest resolution %d x %d\n",
+ ModeData->HorizontalResolution, ModeData->VerticalResolution));
+ );
+ PreferMode = HighestResolutionMode;
+ }
+ Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, (UINT32) PreferMode);
+ if (EFI_ERROR (Status)) {
+ for (PreferMode = 0; PreferMode < ModeNumber; PreferMode ++) {
+ Status = BiosVideoGraphicsOutputSetMode (
+ &BiosVideoPrivate->GraphicsOutput,
+ (UINT32) PreferMode
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ }
+ if (PreferMode == ModeNumber) {
+ //
+ // None mode is set successfully.
+ //
+ goto Done;
+ }
+ }
+
+Done:
+ //
+ // If there was an error, then free the mode structure
+ //
+ if (EFI_ERROR (Status)) {
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ BiosVideoPrivate->ModeData = NULL;
+ BiosVideoPrivate->MaxMode = 0;
+ }
+ if (EdidOverrideDataBlock != NULL) {
+ FreePool (EdidOverrideDataBlock);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Check for VGA device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS Standard VGA device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVga (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_MODE_DATA *ModeBuffer;
+
+ Status = EFI_UNSUPPORTED;
+
+ //
+ // Assign Gop's Blt function
+ //
+ BiosVideoPrivate->GraphicsOutput.Blt = BiosVideoGraphicsOutputVgaBlt;
+
+ //
+ // Add mode to the list of available modes
+ // caller should guarantee that Mode has been allocated.
+ //
+ ASSERT (BiosVideoPrivate->GraphicsOutput.Mode != NULL);
+ BiosVideoPrivate->GraphicsOutput.Mode->MaxMode = 1;
+
+ ModeBuffer = (BIOS_VIDEO_MODE_DATA *) AllocatePool (
+ sizeof (BIOS_VIDEO_MODE_DATA)
+ );
+ if (NULL == ModeBuffer) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+
+ ModeBuffer->VbeModeNumber = 0x0012;
+ ModeBuffer->BytesPerScanLine = 640;
+ ModeBuffer->LinearFrameBuffer = (VOID *) (UINTN) (0xa0000);
+ ModeBuffer->HorizontalResolution = 640;
+ ModeBuffer->VerticalResolution = 480;
+ ModeBuffer->PixelFormat = PixelBltOnly;
+ ModeBuffer->BitsPerPixel = 8;
+ ModeBuffer->ColorDepth = 32;
+ ModeBuffer->RefreshRate = 60;
+
+ BiosVideoPrivate->ModeData = ModeBuffer;
+
+ //
+ // Test to see if the Video Adapter support the 640x480 16 color mode
+ //
+ BiosVideoPrivate->GraphicsOutput.Mode->Mode = GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER;
+ Status = BiosVideoGraphicsOutputSetMode (&BiosVideoPrivate->GraphicsOutput, 0);
+
+Done:
+ //
+ // If there was an error, then free the mode structure
+ //
+ if (EFI_ERROR (Status)) {
+ if (BiosVideoPrivate->ModeData != NULL) {
+ FreePool (BiosVideoPrivate->ModeData);
+ BiosVideoPrivate->ModeData = NULL;
+ }
+ if (BiosVideoPrivate->GraphicsOutput.Mode != NULL) {
+ if (BiosVideoPrivate->GraphicsOutput.Mode->Info != NULL) {
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode->Info);
+ BiosVideoPrivate->GraphicsOutput.Mode->Info = NULL;
+ }
+ FreePool (BiosVideoPrivate->GraphicsOutput.Mode);
+ BiosVideoPrivate->GraphicsOutput.Mode = NULL;
+ }
+ }
+ return Status;
+}
+
+//
+// Graphics Output Protocol Member Functions for VESA BIOS Extensions
+//
+
+/**
+ Graphics Output protocol interface to get video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info
+ buffer.
+ @param Info Caller allocated buffer that returns information
+ about ModeNumber.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
+ video mode.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_INVALID_PARAMETER One of the input args was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ if (BiosVideoPrivate->HardwareNeedsStarting) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
+ BiosVideoPrivate->GopDevicePath
+ );
+ return EFI_NOT_STARTED;
+ }
+
+ if (This == NULL || Info == NULL || SizeOfInfo == NULL || ModeNumber >= This->Mode->MaxMode) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Info = (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *) AllocatePool (
+ sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION)
+ );
+ if (NULL == *Info) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *SizeOfInfo = sizeof (EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+
+ ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
+ (*Info)->Version = 0;
+ (*Info)->HorizontalResolution = ModeData->HorizontalResolution;
+ (*Info)->VerticalResolution = ModeData->VerticalResolution;
+ (*Info)->PixelFormat = ModeData->PixelFormat;
+ CopyMem (&((*Info)->PixelInformation), &(ModeData->PixelBitMask), sizeof(ModeData->PixelBitMask));
+
+ (*Info)->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function to set video mode.
+
+ @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV.
+ @param ModeData The mode data to be set.
+ @param DevicePath Pointer to Device Path Protocol.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+BiosVideoSetModeWorker (
+ IN BIOS_VIDEO_DEV *BiosVideoPrivate,
+ IN BIOS_VIDEO_MODE_DATA *ModeData,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_IA32_REGISTER_SET Regs;
+
+ if (BiosVideoPrivate->LineBuffer != NULL) {
+ FreePool (BiosVideoPrivate->LineBuffer);
+ }
+
+ if (BiosVideoPrivate->VgaFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VgaFrameBuffer);
+ }
+
+ if (BiosVideoPrivate->VbeFrameBuffer != NULL) {
+ FreePool (BiosVideoPrivate->VbeFrameBuffer);
+ }
+
+ BiosVideoPrivate->LineBuffer = (UINT8 *) AllocatePool (
+ ModeData->BytesPerScanLine
+ );
+ if (NULL == BiosVideoPrivate->LineBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Clear all registers
+ //
+ ZeroMem (&Regs, sizeof (Regs));
+
+ if (ModeData->VbeModeNumber < 0x100) {
+ //
+ // Allocate a working buffer for BLT operations to the VGA frame buffer
+ //
+ BiosVideoPrivate->VgaFrameBuffer = (UINT8 *) AllocatePool (4 * 480 * 80);
+ if (NULL == BiosVideoPrivate->VgaFrameBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set VGA Mode
+ //
+ Regs.X.AX = ModeData->VbeModeNumber;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ } else {
+ //
+ // Allocate a working buffer for BLT operations to the VBE frame buffer
+ //
+ BiosVideoPrivate->VbeFrameBuffer =
+ (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) AllocatePool (
+ ModeData->BytesPerScanLine * ModeData->VerticalResolution
+ );
+ if (NULL == BiosVideoPrivate->VbeFrameBuffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Set VBE mode
+ //
+ Regs.X.AX = VESA_BIOS_EXTENSIONS_SET_MODE;
+ Regs.X.BX = (UINT16) (ModeData->VbeModeNumber | VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER);
+ ZeroMem (BiosVideoPrivate->VbeCrtcInformationBlock, sizeof (VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK));
+ Regs.X.ES = EFI_SEGMENT ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
+ Regs.X.DI = EFI_OFFSET ((UINTN) BiosVideoPrivate->VbeCrtcInformationBlock);
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ //
+ // Check to see if the call succeeded
+ //
+ if (Regs.X.AX != VESA_BIOS_EXTENSIONS_STATUS_SUCCESS) {
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_OUTPUT_ERROR,
+ DevicePath
+ );
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Initialize the state of the VbeFrameBuffer
+ //
+ Status = BiosVideoPrivate->PciIo->Mem.Read (
+ BiosVideoPrivate->PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) ModeData->LinearFrameBuffer,
+ (ModeData->BytesPerScanLine * ModeData->VerticalResolution) >> 2,
+ BiosVideoPrivate->VbeFrameBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Graphics Output protocol interface to set video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to be set.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ )
+{
+ EFI_STATUS Status;
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ ModeData = &BiosVideoPrivate->ModeData[ModeNumber];
+
+ if (ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (ModeNumber == This->Mode->Mode) {
+ //
+ // Clear screen to black
+ //
+ ZeroMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ BiosVideoGraphicsOutputVbeBlt (
+ This,
+ &Background,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ 0,
+ ModeData->HorizontalResolution,
+ ModeData->VerticalResolution,
+ 0
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = BiosVideoSetModeWorker (BiosVideoPrivate, ModeData, BiosVideoPrivate->GopDevicePath);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ This->Mode->Mode = ModeNumber;
+ This->Mode->Info->Version = 0;
+ This->Mode->Info->HorizontalResolution = ModeData->HorizontalResolution;
+ This->Mode->Info->VerticalResolution = ModeData->VerticalResolution;
+ This->Mode->Info->PixelFormat = ModeData->PixelFormat;
+ CopyMem (&(This->Mode->Info->PixelInformation), &(ModeData->PixelBitMask), sizeof (ModeData->PixelBitMask));
+ This->Mode->Info->PixelsPerScanLine = (ModeData->BytesPerScanLine * 8) / ModeData->BitsPerPixel;
+ This->Mode->SizeOfInfo = sizeof(EFI_GRAPHICS_OUTPUT_MODE_INFORMATION);
+ This->Mode->FrameBufferSize = ModeData->FrameBufferSize;
+ This->Mode->FrameBufferBase = (EFI_PHYSICAL_ADDRESS) (UINTN) ModeData->LinearFrameBuffer;
+
+ BiosVideoPrivate->HardwareNeedsStarting = FALSE;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update physical frame buffer, copy 4 bytes block, then copy remaining bytes.
+
+ @param PciIo The pointer of EFI_PCI_IO_PROTOCOL
+ @param VbeBuffer The data to transfer to screen
+ @param MemAddress Physical frame buffer base address
+ @param DestinationX The X coordinate of the destination for BltOperation
+ @param DestinationY The Y coordinate of the destination for BltOperation
+ @param TotalBytes The total bytes of copy
+ @param VbePixelWidth Bytes per pixel
+ @param BytesPerScanLine Bytes per scan line
+
+**/
+VOID
+CopyVideoBuffer (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 *VbeBuffer,
+ IN VOID *MemAddress,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN TotalBytes,
+ IN UINT32 VbePixelWidth,
+ IN UINTN BytesPerScanLine
+ )
+{
+ UINTN FrameBufferAddr;
+ UINTN CopyBlockNum;
+ UINTN RemainingBytes;
+ UINTN UnalignedBytes;
+ EFI_STATUS Status;
+
+ FrameBufferAddr = (UINTN) MemAddress + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth;
+
+ //
+ // If TotalBytes is less than 4 bytes, only start byte copy.
+ //
+ if (TotalBytes < 4) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ TotalBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ return;
+ }
+
+ //
+ // If VbeBuffer is not 4-byte aligned, start byte copy.
+ //
+ UnalignedBytes = (4 - ((UINTN) VbeBuffer & 0x3)) & 0x3;
+
+ if (UnalignedBytes != 0) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ UnalignedBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ FrameBufferAddr += UnalignedBytes;
+ VbeBuffer += UnalignedBytes;
+ }
+
+ //
+ // Calculate 4-byte block count and remaining bytes.
+ //
+ CopyBlockNum = (TotalBytes - UnalignedBytes) >> 2;
+ RemainingBytes = (TotalBytes - UnalignedBytes) & 3;
+
+ //
+ // Copy 4-byte block and remaining bytes to physical frame buffer.
+ //
+ if (CopyBlockNum != 0) {
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint32,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ CopyBlockNum,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (RemainingBytes != 0) {
+ FrameBufferAddr += (CopyBlockNum << 2);
+ VbeBuffer += (CopyBlockNum << 2);
+ Status = PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) FrameBufferAddr,
+ RemainingBytes,
+ VbeBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Worker function to block transfer for VBE device.
+
+ @param BiosVideoPrivate Instance of BIOS_VIDEO_DEV
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+ @param Mode Mode data.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+BiosVideoVbeBltWorker (
+ IN BIOS_VIDEO_DEV *BiosVideoPrivate,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta,
+ IN BIOS_VIDEO_MODE_DATA *Mode
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_TPL OriginalTPL;
+ UINTN DstY;
+ UINTN SrcY;
+ UINTN DstX;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ VOID *MemAddress;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
+ UINTN BytesPerScanLine;
+ UINTN Index;
+ UINT8 *VbeBuffer;
+ UINT8 *VbeBuffer1;
+ UINT8 *BltUint8;
+ UINT32 VbePixelWidth;
+ UINT32 Pixel;
+ UINTN TotalBytes;
+
+ PciIo = BiosVideoPrivate->PciIo;
+
+ VbeFrameBuffer = BiosVideoPrivate->VbeFrameBuffer;
+ MemAddress = Mode->LinearFrameBuffer;
+ BytesPerScanLine = Mode->BytesPerScanLine;
+ VbePixelWidth = Mode->BitsPerPixel / 8;
+ BltUint8 = (UINT8 *) BltBuffer;
+ TotalBytes = Width * VbePixelWidth;
+
+ if (((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We need to fill the Virtual Screen buffer with the blt data.
+ // The virtual screen is upside down, as the first row is the bootom row of
+ // the image.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ if (SourceY + Height > Mode->VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > Mode->HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > Mode->VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > Mode->HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+ for (SrcY = SourceY, DstY = DestinationY; DstY < (Height + DestinationY); SrcY++, DstY++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + DstY * Delta + DestinationX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ //
+ // Shuffle the packed bytes in the hardware buffer to match EFI_GRAPHICS_OUTPUT_BLT_PIXEL
+ //
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (SrcY * BytesPerScanLine + SourceX * VbePixelWidth));
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ Pixel = VbeBuffer[0] | VbeBuffer[1] << 8 | VbeBuffer[2] << 16 | VbeBuffer[3] << 24;
+ Blt->Red = (UINT8) ((Pixel >> Mode->Red.Position) & Mode->Red.Mask);
+ Blt->Blue = (UINT8) ((Pixel >> Mode->Blue.Position) & Mode->Blue.Mask);
+ Blt->Green = (UINT8) ((Pixel >> Mode->Green.Position) & Mode->Green.Mask);
+ Blt->Reserved = 0;
+ Blt++;
+ VbeBuffer += VbePixelWidth;
+ }
+
+ }
+ break;
+
+ case EfiBltVideoToVideo:
+ for (Index = 0; Index < Height; Index++) {
+ if (DestinationY <= SourceY) {
+ SrcY = SourceY + Index;
+ DstY = DestinationY + Index;
+ } else {
+ SrcY = SourceY + Height - Index - 1;
+ DstY = DestinationY + Height - Index - 1;
+ }
+
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + DstY * BytesPerScanLine + DestinationX * VbePixelWidth);
+ VbeBuffer1 = ((UINT8 *) VbeFrameBuffer + SrcY * BytesPerScanLine + SourceX * VbePixelWidth);
+
+ gBS->CopyMem (
+ VbeBuffer,
+ VbeBuffer1,
+ TotalBytes
+ );
+
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ case EfiBltVideoFill:
+ VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) BltUint8;
+ //
+ // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
+ //
+ Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
+ (
+ (Blt->Green & Mode->Green.Mask) <<
+ Mode->Green.Position
+ ) |
+ ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
+
+ for (Index = 0; Index < Width; Index++) {
+ gBS->CopyMem (
+ VbeBuffer,
+ &Pixel,
+ VbePixelWidth
+ );
+ VbeBuffer += VbePixelWidth;
+ }
+
+ VbeBuffer = (UINT8 *) ((UINTN) VbeFrameBuffer + (DestinationY * BytesPerScanLine) + DestinationX * VbePixelWidth);
+ for (DstY = DestinationY + 1; DstY < (Height + DestinationY); DstY++) {
+ gBS->CopyMem (
+ (VOID *) ((UINTN) VbeFrameBuffer + (DstY * BytesPerScanLine) + DestinationX * VbePixelWidth),
+ VbeBuffer,
+ TotalBytes
+ );
+ }
+
+ for (DstY = DestinationY; DstY < (Height + DestinationY); DstY++) {
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ for (SrcY = SourceY, DstY = DestinationY; SrcY < (Height + SourceY); SrcY++, DstY++) {
+ Blt = (EFI_GRAPHICS_OUTPUT_BLT_PIXEL *) (BltUint8 + (SrcY * Delta) + (SourceX) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
+ for (DstX = DestinationX; DstX < (Width + DestinationX); DstX++) {
+ //
+ // Shuffle the RGB fields in EFI_GRAPHICS_OUTPUT_BLT_PIXEL to match the hardware buffer
+ //
+ Pixel = ((Blt->Red & Mode->Red.Mask) << Mode->Red.Position) |
+ ((Blt->Green & Mode->Green.Mask) << Mode->Green.Position) |
+ ((Blt->Blue & Mode->Blue.Mask) << Mode->Blue.Position);
+ gBS->CopyMem (
+ VbeBuffer,
+ &Pixel,
+ VbePixelWidth
+ );
+ Blt++;
+ VbeBuffer += VbePixelWidth;
+ }
+
+ VbeBuffer = ((UINT8 *) VbeFrameBuffer + (DstY * BytesPerScanLine + DestinationX * VbePixelWidth));
+
+ //
+ // Update physical frame buffer.
+ //
+ CopyVideoBuffer (
+ PciIo,
+ VbeBuffer,
+ MemAddress,
+ DestinationX,
+ DstY,
+ TotalBytes,
+ VbePixelWidth,
+ BytesPerScanLine
+ );
+ }
+ break;
+
+ default: ;
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Graphics Output protocol instance to block transfer for VBE device.
+
+ @param This Pointer to Graphics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVbeBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ BIOS_VIDEO_MODE_DATA *Mode;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+ Mode = &BiosVideoPrivate->ModeData[This->Mode->Mode];
+
+ return BiosVideoVbeBltWorker (
+ BiosVideoPrivate,
+ BltBuffer,
+ BltOperation,
+ SourceX,
+ SourceY,
+ DestinationX,
+ DestinationY,
+ Width,
+ Height,
+ Delta,
+ Mode
+ );
+}
+
+/**
+ Write graphics controller registers.
+
+ @param PciIo Pointer to PciIo protocol instance of the
+ controller
+ @param Address Register address
+ @param Data Data to be written to register
+
+ @return None
+
+**/
+VOID
+WriteGraphicsController (
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINTN Address,
+ IN UINTN Data
+ )
+{
+ Address = Address | (Data << 8);
+ PciIo->Io.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER,
+ 1,
+ &Address
+ );
+}
+
+
+/**
+ Read the four bit plane of VGA frame buffer.
+
+ @param PciIo Pointer to PciIo protocol instance of the
+ controller
+ @param HardwareBuffer Hardware VGA frame buffer address
+ @param MemoryBuffer Memory buffer address
+ @param WidthInBytes Number of bytes in a line to read
+ @param Height Height of the area to read
+
+ @return None
+
+**/
+VOID
+VgaReadBitPlanes (
+ EFI_PCI_IO_PROTOCOL *PciIo,
+ UINT8 *HardwareBuffer,
+ UINT8 *MemoryBuffer,
+ UINTN WidthInBytes,
+ UINTN Height
+ )
+{
+ UINTN BitPlane;
+ UINTN Rows;
+ UINTN FrameBufferOffset;
+ UINT8 *Source;
+ UINT8 *Destination;
+
+ //
+ // Program the Mode Register Write mode 0, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0
+ );
+
+ for (BitPlane = 0, FrameBufferOffset = 0;
+ BitPlane < VGA_NUMBER_OF_BIT_PLANES;
+ BitPlane++, FrameBufferOffset += VGA_BYTES_PER_BIT_PLANE
+ ) {
+ //
+ // Program the Read Map Select Register to select the correct bit plane
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER,
+ BitPlane
+ );
+
+ Source = HardwareBuffer;
+ Destination = MemoryBuffer + FrameBufferOffset;
+
+ for (Rows = 0; Rows < Height; Rows++, Source += VGA_BYTES_PER_SCAN_LINE, Destination += VGA_BYTES_PER_SCAN_LINE) {
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Source,
+ WidthInBytes,
+ (VOID *) Destination
+ );
+ }
+ }
+}
+
+
+/**
+ Internal routine to convert VGA color to Grahpics Output color.
+
+ @param MemoryBuffer Buffer containing VGA color
+ @param CoordinateX The X coordinate of pixel on screen
+ @param CoordinateY The Y coordinate of pixel on screen
+ @param BltBuffer Buffer to contain converted Grahpics Output color
+
+ @return None
+
+**/
+VOID
+VgaConvertToGraphicsOutputColor (
+ UINT8 *MemoryBuffer,
+ UINTN CoordinateX,
+ UINTN CoordinateY,
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
+ )
+{
+ UINTN Mask;
+ UINTN Bit;
+ UINTN Color;
+
+ MemoryBuffer += ((CoordinateY << 6) + (CoordinateY << 4) + (CoordinateX >> 3));
+ Mask = mVgaBitMaskTable[CoordinateX & 0x07];
+ for (Bit = 0x01, Color = 0; Bit < 0x10; Bit <<= 1, MemoryBuffer += VGA_BYTES_PER_BIT_PLANE) {
+ if ((*MemoryBuffer & Mask) != 0) {
+ Color |= Bit;
+ }
+ }
+
+ *BltBuffer = mVgaColorToGraphicsOutputColor[Color];
+}
+
+/**
+ Internal routine to convert Grahpics Output color to VGA color.
+
+ @param BltBuffer buffer containing Grahpics Output color
+
+ @return Converted VGA color
+
+**/
+UINT8
+VgaConvertColor (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer
+ )
+{
+ UINT8 Color;
+
+ Color = (UINT8) ((BltBuffer->Blue >> 7) | ((BltBuffer->Green >> 6) & 0x02) | ((BltBuffer->Red >> 5) & 0x04));
+ if ((BltBuffer->Red + BltBuffer->Green + BltBuffer->Blue) > 0x180) {
+ Color |= 0x08;
+ }
+
+ return Color;
+}
+
+
+/**
+ Grahpics Output protocol instance to block transfer for VGA device.
+
+ @param This Pointer to Grahpics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVgaBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_TPL OriginalTPL;
+ UINT8 *MemAddress;
+ UINTN BytesPerScanLine;
+ UINTN Bit;
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartAddress;
+ UINTN Bytes;
+ UINTN Offset;
+ UINT8 LeftMask;
+ UINT8 RightMask;
+ UINTN Address;
+ UINTN AddressFix;
+ UINT8 *Address1;
+ UINT8 *SourceAddress;
+ UINT8 *DestinationAddress;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Data;
+ UINT8 PixelColor;
+ UINT8 *VgaFrameBuffer;
+ UINTN SourceOffset;
+ UINTN SourceWidth;
+ UINTN Rows;
+ UINTN Columns;
+ UINTN CoordinateX;
+ UINTN CoordinateY;
+ UINTN CurrentMode;
+
+ if (This == NULL || ((UINTN) BltOperation) >= EfiGraphicsOutputBltOperationMax) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS (This);
+
+ CurrentMode = This->Mode->Mode;
+ PciIo = BiosVideoPrivate->PciIo;
+ MemAddress = BiosVideoPrivate->ModeData[CurrentMode].LinearFrameBuffer;
+ BytesPerScanLine = BiosVideoPrivate->ModeData[CurrentMode].BytesPerScanLine >> 3;
+ VgaFrameBuffer = BiosVideoPrivate->VgaFrameBuffer;
+
+
+ if (Width == 0 || Height == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // We need to fill the Virtual Screen buffer with the blt data.
+ // The virtual screen is upside down, as the first row is the bootom row of
+ // the image.
+ //
+ if (BltOperation == EfiBltVideoToBltBuffer) {
+ //
+ // Video to BltBuffer: Source is Video, destination is BltBuffer
+ //
+ if (SourceY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (SourceX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ } else {
+ //
+ // BltBuffer to Video: Source is BltBuffer, destination is Video
+ //
+ if (DestinationY + Height > BiosVideoPrivate->ModeData[CurrentMode].VerticalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (DestinationX + Width > BiosVideoPrivate->ModeData[CurrentMode].HorizontalResolution) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // If Delta is zero, then the entire BltBuffer is being used, so Delta
+ // is the number of bytes in each row of BltBuffer. Since BltBuffer is Width pixels size,
+ // the number of bytes in each row can be computed.
+ //
+ if (Delta == 0) {
+ Delta = Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL);
+ }
+ //
+ // We have to raise to TPL Notify, so we make an atomic write the frame buffer.
+ // We would not want a timer based event (Cursor, ...) to come in while we are
+ // doing this operation.
+ //
+ OriginalTPL = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Compute some values we need for VGA
+ //
+ switch (BltOperation) {
+ case EfiBltVideoToBltBuffer:
+
+ SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
+ SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
+
+ //
+ // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
+ //
+ VgaReadBitPlanes (
+ PciIo,
+ MemAddress + SourceOffset,
+ VgaFrameBuffer + SourceOffset,
+ SourceWidth,
+ Height
+ );
+
+ //
+ // Convert VGA Bit Planes to a Graphics Output 32-bit color value
+ //
+ BltBuffer += (DestinationY * (Delta >> 2) + DestinationX);
+ for (Rows = 0, CoordinateY = SourceY; Rows < Height; Rows++, CoordinateY++, BltBuffer += (Delta >> 2)) {
+ for (Columns = 0, CoordinateX = SourceX; Columns < Width; Columns++, CoordinateX++, BltBuffer++) {
+ VgaConvertToGraphicsOutputColor (VgaFrameBuffer, CoordinateX, CoordinateY, BltBuffer);
+ }
+
+ BltBuffer -= Width;
+ }
+
+ break;
+
+ case EfiBltVideoToVideo:
+ //
+ // Check for an aligned Video to Video operation
+ //
+ if ((SourceX & 0x07) == 0x00 && (DestinationX & 0x07) == 0x00 && (Width & 0x07) == 0x00) {
+ //
+ // Program the Mode Register Write mode 1, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1
+ );
+
+ SourceAddress = (UINT8 *) (MemAddress + (SourceY << 6) + (SourceY << 4) + (SourceX >> 3));
+ DestinationAddress = (UINT8 *) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ Bytes = Width >> 3;
+ for (Index = 0, Offset = 0; Index < Height; Index++, Offset += BytesPerScanLine) {
+ PciIo->CopyMem (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) (DestinationAddress + Offset),
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) (SourceAddress + Offset),
+ Bytes
+ );
+ }
+ } else {
+ SourceOffset = (SourceY << 6) + (SourceY << 4) + (SourceX >> 3);
+ SourceWidth = ((SourceX + Width - 1) >> 3) - (SourceX >> 3) + 1;
+
+ //
+ // Read all the pixels in the 4 bit planes into a memory buffer that looks like the VGA buffer
+ //
+ VgaReadBitPlanes (
+ PciIo,
+ MemAddress + SourceOffset,
+ VgaFrameBuffer + SourceOffset,
+ SourceWidth,
+ Height
+ );
+ }
+
+ break;
+
+ case EfiBltVideoFill:
+ StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ Bytes = ((DestinationX + Width - 1) >> 3) - (DestinationX >> 3);
+ LeftMask = mVgaLeftMaskTable[DestinationX & 0x07];
+ RightMask = mVgaRightMaskTable[(DestinationX + Width - 1) & 0x07];
+ if (Bytes == 0) {
+ LeftMask = (UINT8) (LeftMask & RightMask);
+ RightMask = 0;
+ }
+
+ if (LeftMask == 0xff) {
+ StartAddress--;
+ Bytes++;
+ LeftMask = 0;
+ }
+
+ if (RightMask == 0xff) {
+ Bytes++;
+ RightMask = 0;
+ }
+
+ PixelColor = VgaConvertColor (BltBuffer);
+
+ //
+ // Program the Mode Register Write mode 2, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
+ );
+
+ //
+ // Program the Data Rotate/Function Select Register to replace
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
+ );
+
+ if (LeftMask != 0) {
+ //
+ // Program the BitMask register with the Left column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ LeftMask
+ );
+
+ for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &Data
+ );
+ //
+ // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &PixelColor
+ );
+ }
+ }
+
+ if (Bytes > 1) {
+ //
+ // Program the BitMask register with the middle column mask of 0xff
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ 0xff
+ );
+
+ for (Index = 0, Address = StartAddress + 1; Index < Height; Index++, Address += BytesPerScanLine) {
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthFillUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ Bytes - 1,
+ &PixelColor
+ );
+ }
+ }
+
+ if (RightMask != 0) {
+ //
+ // Program the BitMask register with the Right column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ RightMask
+ );
+
+ for (Index = 0, Address = StartAddress + Bytes; Index < Height; Index++, Address += BytesPerScanLine) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &Data
+ );
+ //
+ // Write the lower 4 bits of PixelColor to the bit planes in the pixels enabled by BitMask
+ //
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address,
+ 1,
+ &PixelColor
+ );
+ }
+ }
+ break;
+
+ case EfiBltBufferToVideo:
+ StartAddress = (UINTN) (MemAddress + (DestinationY << 6) + (DestinationY << 4) + (DestinationX >> 3));
+ LeftMask = mVgaBitMaskTable[DestinationX & 0x07];
+
+ //
+ // Program the Mode Register Write mode 2, Read mode 0
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_MODE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_READ_MODE_0 | VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2
+ );
+
+ //
+ // Program the Data Rotate/Function Select Register to replace
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER,
+ VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE
+ );
+
+ for (Index = 0, Address = StartAddress; Index < Height; Index++, Address += BytesPerScanLine) {
+ for (Index1 = 0; Index1 < Width; Index1++) {
+ BiosVideoPrivate->LineBuffer[Index1] = VgaConvertColor (&BltBuffer[(SourceY + Index) * (Delta >> 2) + SourceX + Index1]);
+ }
+ AddressFix = Address;
+
+ for (Bit = 0; Bit < 8; Bit++) {
+ //
+ // Program the BitMask register with the Left column mask
+ //
+ WriteGraphicsController (
+ PciIo,
+ VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER,
+ LeftMask
+ );
+
+ for (Index1 = Bit, Address1 = (UINT8 *) AddressFix; Index1 < Width; Index1 += 8, Address1++) {
+ //
+ // Read data from the bit planes into the latches
+ //
+ PciIo->Mem.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address1,
+ 1,
+ &Data
+ );
+
+ PciIo->Mem.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ EFI_PCI_IO_PASS_THROUGH_BAR,
+ (UINT64) (UINTN) Address1,
+ 1,
+ &BiosVideoPrivate->LineBuffer[Index1]
+ );
+ }
+
+ LeftMask = (UINT8) (LeftMask >> 1);
+ if (LeftMask == 0) {
+ LeftMask = 0x80;
+ AddressFix++;
+ }
+ }
+ }
+
+ break;
+
+ default: ;
+ }
+
+ gBS->RestoreTPL (OriginalTPL);
+
+ return EFI_SUCCESS;
+}
+
+//
+// VGA Mini Port Protocol Functions
+//
+
+/**
+ VgaMiniPort protocol interface to set mode.
+
+ @param This Pointer to VgaMiniPort protocol instance
+ @param ModeNumber The index of the mode
+
+ @retval EFI_UNSUPPORTED The requested mode is not supported
+ @retval EFI_SUCCESS The requested mode is set successfully
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+
+ if (This == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Make sure the ModeNumber is a valid value
+ //
+ if (ModeNumber >= This->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Get the device structure for this device
+ //
+ BiosVideoPrivate = BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS (This);
+
+ switch (ModeNumber) {
+ case 0:
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x14;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ break;
+
+ case 1:
+ //
+ // Set the 80x50 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x12;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Event handler for Exit Boot Service.
+
+ @param Event The event that be siganlled when exiting boot service.
+ @param Context Pointer to instance of BIOS_VIDEO_DEV.
+
+**/
+VOID
+EFIAPI
+BiosVideoNotifyExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ BIOS_VIDEO_DEV *BiosVideoPrivate;
+ EFI_IA32_REGISTER_SET Regs;
+
+ BiosVideoPrivate = (BIOS_VIDEO_DEV *)Context;
+
+ //
+ // Set the 80x25 Text VGA Mode
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x03;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x00;
+ Regs.H.AL = 0x83;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+
+ Regs.H.AH = 0x11;
+ Regs.H.AL = 0x04;
+ Regs.H.BL = 0;
+ BiosVideoPrivate->LegacyBios->Int86 (BiosVideoPrivate->LegacyBios, 0x10, &Regs);
+}
+
+/**
+ The user Entry Point for module UefiBiosVideo. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoEntryPoint(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gBiosVideoDriverBinding,
+ ImageHandle,
+ &gBiosVideoComponentName,
+ &gBiosVideoComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ //
+ return gBS->InstallMultipleProtocolInterfaces (
+ &ImageHandle,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ NULL
+ );
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h
new file mode 100644
index 0000000000..88ab1d7cf4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideo.h
@@ -0,0 +1,539 @@
+/** @file
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BIOS_GRAPHICS_OUTPUT_H_
+#define _BIOS_GRAPHICS_OUTPUT_H_
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/PciIo.h>
+#include <Protocol/EdidActive.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/EdidDiscovered.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/EdidOverride.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <IndustryStandard/Pci.h>
+#include "VesaBiosExtensions.h"
+
+//
+// Packed format support: The number of bits reserved for each of the colors and the actual
+// position of RGB in the frame buffer is specified in the VBE Mode information
+//
+typedef struct {
+ UINT8 Position; // Position of the color
+ UINT8 Mask; // The number of bits expressed as a mask
+} BIOS_VIDEO_COLOR_PLACEMENT;
+
+//
+// BIOS Graphics Output Graphical Mode Data
+//
+typedef struct {
+ UINT16 VbeModeNumber;
+ UINT16 BytesPerScanLine;
+ VOID *LinearFrameBuffer;
+ UINTN FrameBufferSize;
+ UINT32 HorizontalResolution;
+ UINT32 VerticalResolution;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ UINT32 BitsPerPixel;
+ BIOS_VIDEO_COLOR_PLACEMENT Red;
+ BIOS_VIDEO_COLOR_PLACEMENT Green;
+ BIOS_VIDEO_COLOR_PLACEMENT Blue;
+ BIOS_VIDEO_COLOR_PLACEMENT Reserved;
+ EFI_GRAPHICS_PIXEL_FORMAT PixelFormat;
+ EFI_PIXEL_BITMASK PixelBitMask;
+} BIOS_VIDEO_MODE_DATA;
+
+//
+// BIOS video child handle private data Structure
+//
+#define BIOS_VIDEO_DEV_SIGNATURE SIGNATURE_32 ('B', 'V', 'M', 'p')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+
+ //
+ // Consumed Protocols
+ //
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ //
+ // Produced Protocols
+ //
+ EFI_GRAPHICS_OUTPUT_PROTOCOL GraphicsOutput;
+ EFI_EDID_DISCOVERED_PROTOCOL EdidDiscovered;
+ EFI_EDID_ACTIVE_PROTOCOL EdidActive;
+ EFI_VGA_MINI_PORT_PROTOCOL VgaMiniPort;
+
+ //
+ // General fields
+ //
+ BOOLEAN VgaCompatible;
+ BOOLEAN ProduceGraphicsOutput;
+
+ //
+ // Graphics Output Protocol related fields
+ //
+ BOOLEAN HardwareNeedsStarting;
+ UINTN CurrentMode;
+ UINTN MaxMode;
+ BIOS_VIDEO_MODE_DATA *ModeData;
+ UINT8 *LineBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *VbeFrameBuffer;
+ UINT8 *VgaFrameBuffer;
+
+ //
+ // VESA Bios Extensions related fields
+ //
+ UINTN NumberOfPagesBelow1MB; // Number of 4KB pages in PagesBelow1MB
+ EFI_PHYSICAL_ADDRESS PagesBelow1MB; // Buffer for all VBE Information Blocks
+ VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK *VbeInformationBlock; // 0x200 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK *VbeModeInformationBlock; // 0x100 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK *VbeEdidDataBlock; // 0x80 bytes. Must be allocated below 1MB
+ VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK *VbeCrtcInformationBlock; // 59 bytes. Must be allocated below 1MB
+ UINTN VbeSaveRestorePages; // Number of 4KB pages in VbeSaveRestoreBuffer
+ EFI_PHYSICAL_ADDRESS VbeSaveRestoreBuffer; // Must be allocated below 1MB
+ //
+ // Status code
+ //
+ EFI_DEVICE_PATH_PROTOCOL *GopDevicePath;
+
+ EFI_EVENT ExitBootServicesEvent;
+} BIOS_VIDEO_DEV;
+
+#define BIOS_VIDEO_DEV_FROM_PCI_IO_THIS(a) CR (a, BIOS_VIDEO_DEV, PciIo, BIOS_VIDEO_DEV_SIGNATURE)
+#define BIOS_VIDEO_DEV_FROM_GRAPHICS_OUTPUT_THIS(a) CR (a, BIOS_VIDEO_DEV, GraphicsOutput, BIOS_VIDEO_DEV_SIGNATURE)
+#define BIOS_VIDEO_DEV_FROM_VGA_MINI_PORT_THIS(a) CR (a, BIOS_VIDEO_DEV, VgaMiniPort, BIOS_VIDEO_DEV_SIGNATURE)
+
+#define GRAPHICS_OUTPUT_INVALIDE_MODE_NUMBER 0xffff
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gBiosVideoDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2;
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Supported.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @retval EFI_STATUS EFI_SUCCESS:This controller can be managed by this
+ driver, Otherwise, this controller cannot be
+ managed by this driver
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Install Graphics Output Protocol onto VGA device handles.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param RemainingDevicePath A pointer to the remaining portion of a device
+ path
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+/**
+ Stop.
+
+ @param This Pointer to driver binding protocol
+ @param Controller Controller handle to connect
+ @param NumberOfChildren Number of children handle created by this driver
+ @param ChildHandleBuffer Buffer containing child handle created
+
+ @retval EFI_SUCCESS Driver disconnected successfully from controller
+ @retval EFI_UNSUPPORTED Cannot find BIOS_VIDEO_DEV structure
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer
+ );
+
+//
+// Private worker functions
+//
+
+/**
+ Check for VBE device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS VBE device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVbe (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+
+/**
+ Check for VGA device.
+
+ @param BiosVideoPrivate Pointer to BIOS_VIDEO_DEV structure
+
+ @retval EFI_SUCCESS Standard VGA device found
+
+**/
+EFI_STATUS
+BiosVideoCheckForVga (
+ IN OUT BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+
+
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+//
+// BIOS Graphics Output Protocol functions
+//
+
+/**
+ Graphics Output protocol interface to get video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to return information on.
+ @param SizeOfInfo A pointer to the size, in bytes, of the Info
+ buffer.
+ @param Info Caller allocated buffer that returns information
+ about ModeNumber.
+
+ @retval EFI_SUCCESS Mode information returned.
+ @retval EFI_BUFFER_TOO_SMALL The Info buffer was too small.
+ @retval EFI_DEVICE_ERROR A hardware error occurred trying to retrieve the
+ video mode.
+ @retval EFI_NOT_STARTED Video display is not initialized. Call SetMode ()
+ @retval EFI_INVALID_PARAMETER One of the input args was NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputQueryMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN UINT32 ModeNumber,
+ OUT UINTN *SizeOfInfo,
+ OUT EFI_GRAPHICS_OUTPUT_MODE_INFORMATION **Info
+ );
+
+
+/**
+ Graphics Output protocol interface to set video mode.
+
+ @param This Protocol instance pointer.
+ @param ModeNumber The mode number to be set.
+
+ @retval EFI_SUCCESS Graphics mode was changed.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the
+ request.
+ @retval EFI_UNSUPPORTED ModeNumber is not supported by this device.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputSetMode (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL * This,
+ IN UINT32 ModeNumber
+ );
+
+
+/**
+ Graphics Output protocol instance to block transfer for VBE device.
+
+ @param This Pointer to Graphics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVbeBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ );
+
+
+/**
+ Grahpics Output protocol instance to block transfer for VGA device.
+
+ @param This Pointer to Grahpics Output protocol instance
+ @param BltBuffer The data to transfer to screen
+ @param BltOperation The operation to perform
+ @param SourceX The X coordinate of the source for BltOperation
+ @param SourceY The Y coordinate of the source for BltOperation
+ @param DestinationX The X coordinate of the destination for
+ BltOperation
+ @param DestinationY The Y coordinate of the destination for
+ BltOperation
+ @param Width The width of a rectangle in the blt rectangle in
+ pixels
+ @param Height The height of a rectangle in the blt rectangle in
+ pixels
+ @param Delta Not used for EfiBltVideoFill and
+ EfiBltVideoToVideo operation. If a Delta of 0 is
+ used, the entire BltBuffer will be operated on. If
+ a subrectangle of the BltBuffer is used, then
+ Delta represents the number of bytes in a row of
+ the BltBuffer.
+
+ @retval EFI_INVALID_PARAMETER Invalid parameter passed in
+ @retval EFI_SUCCESS Blt operation success
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoGraphicsOutputVgaBlt (
+ IN EFI_GRAPHICS_OUTPUT_PROTOCOL *This,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer, OPTIONAL
+ IN EFI_GRAPHICS_OUTPUT_BLT_OPERATION BltOperation,
+ IN UINTN SourceX,
+ IN UINTN SourceY,
+ IN UINTN DestinationX,
+ IN UINTN DestinationY,
+ IN UINTN Width,
+ IN UINTN Height,
+ IN UINTN Delta
+ );
+
+//
+// BIOS VGA Mini Port Protocol functions
+//
+
+/**
+ VgaMiniPort protocol interface to set mode.
+
+ @param This Pointer to VgaMiniPort protocol instance
+ @param ModeNumber The index of the mode
+
+ @retval EFI_UNSUPPORTED The requested mode is not supported
+ @retval EFI_SUCCESS The requested mode is set successfully
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoVgaMiniPortSetMode (
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+/**
+ Event handler for Exit Boot Service.
+
+ @param Event The event that be siganlled when exiting boot service.
+ @param Context Pointer to instance of BIOS_VIDEO_DEV.
+
+**/
+VOID
+EFIAPI
+BiosVideoNotifyExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+//
+// Standard VGA Definitions
+//
+#define VGA_HORIZONTAL_RESOLUTION 640
+#define VGA_VERTICAL_RESOLUTION 480
+#define VGA_NUMBER_OF_BIT_PLANES 4
+#define VGA_PIXELS_PER_BYTE 8
+#define VGA_BYTES_PER_SCAN_LINE (VGA_HORIZONTAL_RESOLUTION / VGA_PIXELS_PER_BYTE)
+#define VGA_BYTES_PER_BIT_PLANE (VGA_VERTICAL_RESOLUTION * VGA_BYTES_PER_SCAN_LINE)
+
+#define VGA_GRAPHICS_CONTROLLER_ADDRESS_REGISTER 0x3ce
+#define VGA_GRAPHICS_CONTROLLER_DATA_REGISTER 0x3cf
+
+#define VGA_GRAPHICS_CONTROLLER_SET_RESET_REGISTER 0x00
+
+#define VGA_GRAPHICS_CONTROLLER_ENABLE_SET_RESET_REGISTER 0x01
+
+#define VGA_GRAPHICS_CONTROLLER_COLOR_COMPARE_REGISTER 0x02
+
+#define VGA_GRAPHICS_CONTROLLER_DATA_ROTATE_REGISTER 0x03
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_REPLACE 0x00
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_AND 0x08
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_OR 0x10
+#define VGA_GRAPHICS_CONTROLLER_FUNCTION_XOR 0x18
+
+#define VGA_GRAPHICS_CONTROLLER_READ_MAP_SELECT_REGISTER 0x04
+
+#define VGA_GRAPHICS_CONTROLLER_MODE_REGISTER 0x05
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_0 0x00
+#define VGA_GRAPHICS_CONTROLLER_READ_MODE_1 0x08
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_0 0x00
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_1 0x01
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_2 0x02
+#define VGA_GRAPHICS_CONTROLLER_WRITE_MODE_3 0x03
+
+#define VGA_GRAPHICS_CONTROLLER_MISCELLANEOUS_REGISTER 0x06
+
+#define VGA_GRAPHICS_CONTROLLER_COLOR_DONT_CARE_REGISTER 0x07
+
+#define VGA_GRAPHICS_CONTROLLER_BIT_MASK_REGISTER 0x08
+
+/**
+ Install child handles if the Handle supports MBR format.
+
+ @param This Calling context.
+ @param ParentHandle Parent Handle
+ @param ParentPciIo Parent PciIo interface
+ @param ParentLegacyBios Parent LegacyBios interface
+ @param ParentDevicePath Parent Device Path
+ @param RemainingDevicePath Remaining Device Path
+
+ @retval EFI_SUCCESS If a child handle was added
+ @retval other A child handle was not added
+
+**/
+EFI_STATUS
+BiosVideoChildHandleInstall (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE ParentHandle,
+ IN EFI_PCI_IO_PROTOCOL *ParentPciIo,
+ IN EFI_LEGACY_BIOS_PROTOCOL *ParentLegacyBios,
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+/**
+ Deregister an video child handle and free resources.
+
+ @param This Protocol instance pointer.
+ @param Controller Video controller handle
+ @param Handle Video child handle
+
+ @return EFI_STATUS
+
+**/
+EFI_STATUS
+BiosVideoChildHandleUninstall (
+ EFI_DRIVER_BINDING_PROTOCOL *This,
+ EFI_HANDLE Controller,
+ EFI_HANDLE Handle
+ );
+
+/**
+ Release resource for biso video instance.
+
+ @param BiosVideoPrivate Video child device private data structure
+
+**/
+VOID
+BiosVideoDeviceReleaseResource (
+ BIOS_VIDEO_DEV *BiosVideoPrivate
+ );
+
+/**
+ Check if all video child handles have been uninstalled.
+
+ @param Controller Video controller handle
+
+ @return TRUE Child handles exist.
+ @return FALSE All video child handles have been uninstalled.
+
+**/
+BOOLEAN
+HasChildHandle (
+ IN EFI_HANDLE Controller
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni
new file mode 100644
index 0000000000..db9c068146
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni
new file mode 100644
index 0000000000..50334d82c4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/BiosVideoDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c
new file mode 100644
index 0000000000..d9bd0a9238
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/ComponentName.c
@@ -0,0 +1,313 @@
+/** @file
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BiosVideo.h"
+
+//
+// EFI Component Name Functions
+//
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gBiosVideoComponentName = {
+ BiosVideoComponentNameGetDriverName,
+ BiosVideoComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gBiosVideoComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) BiosVideoComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) BiosVideoComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mBiosVideoDriverNameTable[] = {
+ {
+ "eng;en",
+ L"BIOS[INT10] Video Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+
+ @param DriverName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mBiosVideoDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gBiosVideoComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This[in] A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+
+ @param ControllerHandle[in] The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+
+ @param ChildHandle[in] The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+
+ @param Language[in] A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+
+ @param ControllerName[out] A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+BiosVideoComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h
new file mode 100644
index 0000000000..25eee6921d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VesaBiosExtensions.h
@@ -0,0 +1,466 @@
+/** @file
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _VESA_BIOS_EXTENSIONS_H_
+#define _VESA_BIOS_EXTENSIONS_H_
+
+//
+// Turn on byte packing of data structures
+//
+#pragma pack(1)
+//
+// VESA BIOS Extensions status codes
+//
+#define VESA_BIOS_EXTENSIONS_STATUS_SUCCESS 0x004f
+
+//
+// VESA BIOS Extensions Services
+//
+#define VESA_BIOS_EXTENSIONS_RETURN_CONTROLLER_INFORMATION 0x4f00
+
+/*++
+
+ Routine Description:
+ Function 00 : Return Controller Information
+
+ Arguments:
+ Inputs:
+ AX = 0x4f00
+ ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_RETURN_MODE_INFORMATION 0x4f01
+
+/*++
+
+ Routine Description:
+ Function 01 : Return Mode Information
+
+ Arguments:
+ Inputs:
+ AX = 0x4f01
+ CX = Mode Number
+ ES:DI = Pointer to buffer to place VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_SET_MODE 0x4f02
+
+/*++
+
+ Routine Description:
+ Function 02 : Set Mode
+
+ Arguments:
+ Inputs:
+ AX = 0x4f02
+ BX = Desired mode to set
+ D0-D8 = Mode Number
+ D9-D10 = Reserved (must be 0)
+ D11 = 0 - Use current default refresh rate
+ = 1 - Use user specfieid CRTC values for refresh rate
+ D12-D13 = Reserved (must be 0)
+ D14 = 0 - Use windowed frame buffer model
+ = 1 - Use linear/flat frame buffer model
+ D15 = 0 - Clear display memory
+ = 1 - Don't clear display memory
+ ES:DI = Pointer to buffer to the VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK structure
+ Outputs:
+ AX = Return Status
+
+--*/
+#define VESA_BIOS_EXTENSIONS_RETURN_CURRENT_MODE 0x4f03
+
+/*++
+
+ Routine Description:
+ Function 03 : Return Current Mode
+
+ Arguments:
+ Inputs:
+ AX = 0x4f03
+ Outputs:
+ AX = Return Status
+ BX = Current mode
+ D0-D13 = Mode Number
+ D14 = 0 - Windowed frame buffer model
+ = 1 - Linear/flat frame buffer model
+ D15 = 0 - Memory cleared at last mode set
+ = 1 - Memory not cleared at last mode set
+
+--*/
+#define VESA_BIOS_EXTENSIONS_SAVE_RESTORE_STATE 0x4f04
+
+/*++
+
+ Routine Description:
+ Function 04 : Save/Restore State
+
+ Arguments:
+ Inputs:
+ AX = 0x4f03
+ DL = 0x00 - Return Save/Restore State buffer size
+ = 0x01 - Save State
+ = 0x02 - Restore State
+ CX = Requested Status
+ D0 = Save/Restore controller hardware state
+ D1 = Save/Restore BIOS data state
+ D2 = Save/Restore DAC state
+ D3 = Save/Restore Regsiter state
+ ES:BX = Pointer to buffer if DL=1 or DL=2
+ Outputs:
+ AX = Return Status
+ BX = Number of 64 byte blocks to hold the state buffer if DL=0
+
+--*/
+#define VESA_BIOS_EXTENSIONS_EDID 0x4f15
+
+/*++
+
+ Routine Description:
+ Function 15 : implement VBE/DDC service
+
+ Arguments:
+ Inputs:
+ AX = 0x4f15
+ BL = 0x00 - Report VBE/DDC Capabilities
+ CX = 0x00 - Controller unit number (00 = primary controller)
+ ES:DI = Null pointer, must be 0:0 in version 1.0
+ Outputs:
+ AX = Return Status
+ BH = Approx. time in seconds, rounded up, to transfer one EDID block(128 bytes)
+ BL = DDC level supported
+ D0 = 0 DDC1 not supported
+ = 1 DDC1 supported
+ D1 = 0 DDC2 not supported
+ = 1 DDC2 supported
+ D2 = 0 Screen not blanked during data transfer
+ = 1 Screen blanked during data transfer
+
+ Inputs:
+ AX = 0x4f15
+ BL = 0x01 - Read EDID
+ CX = 0x00 - Controller unit number (00 = primary controller)
+ DX = 0x00 - EDID block number
+ ES:DI = Pointer to buffer in which the EDID block is returned
+ Outputs:
+ AX = Return Status
+--*/
+
+//
+// Timing data from EDID data block
+//
+#define VESA_BIOS_EXTENSIONS_EDID_BLOCK_SIZE 128
+#define VESA_BIOS_EXTENSIONS_EDID_ESTABLISHED_TIMING_MAX_NUMBER 17
+
+//
+// Established Timings: 24 possible resolutions
+// Standard Timings: 8 possible resolutions
+// Detailed Timings: 4 possible resolutions
+//
+#define VESA_BIOS_EXTENSIONS_EDID_TIMING_MAX_NUMBER 36
+
+//
+// Timing data size for Established Timings, Standard Timings and Detailed Timings
+//
+#define VESA_BIOS_EXTENSIONS_ESTABLISHED_TIMING_SIZE 3
+#define VESA_BIOS_EXTENSIONS_STANDARD_TIMING_SIZE 16
+#define VESA_BIOS_EXTENSIONS_DETAILED_TIMING_EACH_DESCRIPTOR_SIZE 18
+#define VESA_BIOS_EXTENSIONS_DETAILED_TIMING_DESCRIPTOR_MAX_SIZE 72
+
+typedef struct {
+ UINT16 HorizontalResolution;
+ UINT16 VerticalResolution;
+ UINT16 RefreshRate;
+} VESA_BIOS_EXTENSIONS_EDID_TIMING;
+
+typedef struct {
+ UINT32 ValidNumber;
+ UINT32 Key[VESA_BIOS_EXTENSIONS_EDID_TIMING_MAX_NUMBER];
+} VESA_BIOS_EXTENSIONS_VALID_EDID_TIMING;
+
+typedef struct {
+ UINT8 Header[8]; //EDID header "00 FF FF FF FF FF FF 00"
+ UINT16 ManufactureName; //EISA 3-character ID
+ UINT16 ProductCode; //Vendor assigned code
+ UINT32 SerialNumber; //32-bit serial number
+ UINT8 WeekOfManufacture; //Week number
+ UINT8 YearOfManufacture; //Year
+ UINT8 EdidVersion; //EDID Structure Version
+ UINT8 EdidRevision; //EDID Structure Revision
+ UINT8 VideoInputDefinition;
+ UINT8 MaxHorizontalImageSize; //cm
+ UINT8 MaxVerticalImageSize; //cm
+ UINT8 DisplayTransferCharacteristic;
+ UINT8 FeatureSupport;
+ UINT8 RedGreenLowBits; //Rx1 Rx0 Ry1 Ry0 Gx1 Gx0 Gy1Gy0
+ UINT8 BlueWhiteLowBits; //Bx1 Bx0 By1 By0 Wx1 Wx0 Wy1 Wy0
+ UINT8 RedX; //Red-x Bits 9 - 2
+ UINT8 RedY; //Red-y Bits 9 - 2
+ UINT8 GreenX; //Green-x Bits 9 - 2
+ UINT8 GreenY; //Green-y Bits 9 - 2
+ UINT8 BlueX; //Blue-x Bits 9 - 2
+ UINT8 BlueY; //Blue-y Bits 9 - 2
+ UINT8 WhiteX; //White-x Bits 9 - 2
+ UINT8 WhiteY; //White-x Bits 9 - 2
+ UINT8 EstablishedTimings[VESA_BIOS_EXTENSIONS_ESTABLISHED_TIMING_SIZE];
+ UINT8 StandardTimingIdentification[VESA_BIOS_EXTENSIONS_STANDARD_TIMING_SIZE];
+ UINT8 DetailedTimingDescriptions[VESA_BIOS_EXTENSIONS_DETAILED_TIMING_DESCRIPTOR_MAX_SIZE];
+ UINT8 ExtensionFlag; //Number of (optional) 128-byte EDID extension blocks to follow
+ UINT8 Checksum;
+} VESA_BIOS_EXTENSIONS_EDID_DATA_BLOCK;
+
+//
+// Super VGA Information Block
+//
+typedef struct {
+ UINT32 VESASignature; // 'VESA' 4 byte signature
+ UINT16 VESAVersion; // VBE version number
+ UINT32 OEMStringPtr; // Pointer to OEM string
+ UINT32 Capabilities; // Capabilities of video card
+ UINT32 VideoModePtr; // Pointer to an array of 16-bit supported modes values terminated by 0xFFFF
+ UINT16 TotalMemory; // Number of 64kb memory blocks
+ UINT16 OemSoftwareRev; // VBE implementation Software revision
+ UINT32 OemVendorNamePtr; // VbeFarPtr to Vendor Name String
+ UINT32 OemProductNamePtr; // VbeFarPtr to Product Name String
+ UINT32 OemProductRevPtr; // VbeFarPtr to Product Revision String
+ UINT8 Reserved[222]; // Reserved for VBE implementation scratch area
+ UINT8 OemData[256]; // Data area for OEM strings. Pad to 512 byte block size
+} VESA_BIOS_EXTENSIONS_INFORMATION_BLOCK;
+
+//
+// Super VGA Information Block VESASignature values
+//
+#define VESA_BIOS_EXTENSIONS_VESA_SIGNATURE SIGNATURE_32 ('V', 'E', 'S', 'A')
+#define VESA_BIOS_EXTENSIONS_VBE2_SIGNATURE SIGNATURE_32 ('V', 'B', 'E', '2')
+
+//
+// Super VGA Information Block VESAVersion values
+//
+#define VESA_BIOS_EXTENSIONS_VERSION_1_2 0x0102
+#define VESA_BIOS_EXTENSIONS_VERSION_2_0 0x0200
+#define VESA_BIOS_EXTENSIONS_VERSION_3_0 0x0300
+
+//
+// Super VGA Information Block Capabilities field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_8_BIT_DAC 0x01 // 0: DAC width is fixed at 6 bits/color
+// 1: DAC width switchable to 8 bits/color
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_VGA 0x02 // 0: Controller is VGA compatible
+// 1: Controller is not VGA compatible
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_NOT_NORMAL_RAMDAC 0x04 // 0: Normal RAMDAC operation
+// 1: Use blank bit in function 9 to program RAMDAC
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_STEREOSCOPIC 0x08 // 0: No hardware stereoscopic signal support
+// 1: Hardware stereoscopic signal support
+//
+#define VESA_BIOS_EXTENSIONS_CAPABILITY_VESA_EVC 0x10 // 0: Stero signaling supported via external VESA stereo connector
+// 1: Stero signaling supported via VESA EVC connector
+//
+// Super VGA mode number bite field definitions
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_VESA 0x0100 // 0: Not a VESA defined VBE mode
+// 1: A VESA defined VBE mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_REFRESH_CONTROL_USER 0x0800 // 0: Use current BIOS default referesh rate
+// 1: Use the user specified CRTC values for refresh rate
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_LINEAR_FRAME_BUFFER 0x4000 // 0: Use a banked/windowed frame buffer
+// 1: Use a linear/flat frame buffer
+//
+#define VESA_BIOS_EXTENSIONS_MODE_NUMBER_PRESERVE_MEMORY 0x8000 // 0: Clear display memory
+// 1: Preseve display memory
+//
+// Super VGA Information Block mode list terminator value
+//
+#define VESA_BIOS_EXTENSIONS_END_OF_MODE_LIST 0xffff
+
+//
+// Window Function
+//
+typedef
+VOID
+(*VESA_BIOS_EXTENSIONS_WINDOW_FUNCTION) (
+ VOID
+ );
+
+//
+// Super VGA Mode Information Block
+//
+typedef struct {
+ //
+ // Manadory fields for all VESA Bios Extensions revisions
+ //
+ UINT16 ModeAttributes; // Mode attributes
+ UINT8 WinAAttributes; // Window A attributes
+ UINT8 WinBAttributes; // Window B attributes
+ UINT16 WinGranularity; // Window granularity in k
+ UINT16 WinSize; // Window size in k
+ UINT16 WinASegment; // Window A segment
+ UINT16 WinBSegment; // Window B segment
+ UINT32 WindowFunction; // Pointer to window function
+ UINT16 BytesPerScanLine; // Bytes per scanline
+ //
+ // Manadory fields for VESA Bios Extensions 1.2 and above
+ //
+ UINT16 XResolution; // Horizontal resolution
+ UINT16 YResolution; // Vertical resolution
+ UINT8 XCharSize; // Character cell width
+ UINT8 YCharSize; // Character cell height
+ UINT8 NumberOfPlanes; // Number of memory planes
+ UINT8 BitsPerPixel; // Bits per pixel
+ UINT8 NumberOfBanks; // Number of CGA style banks
+ UINT8 MemoryModel; // Memory model type
+ UINT8 BankSize; // Size of CGA style banks
+ UINT8 NumberOfImagePages; // Number of images pages
+ UINT8 Reserved1; // Reserved
+ UINT8 RedMaskSize; // Size of direct color red mask
+ UINT8 RedFieldPosition; // Bit posn of lsb of red mask
+ UINT8 GreenMaskSize; // Size of direct color green mask
+ UINT8 GreenFieldPosition; // Bit posn of lsb of green mask
+ UINT8 BlueMaskSize; // Size of direct color blue mask
+ UINT8 BlueFieldPosition; // Bit posn of lsb of blue mask
+ UINT8 RsvdMaskSize; // Size of direct color res mask
+ UINT8 RsvdFieldPosition; // Bit posn of lsb of res mask
+ UINT8 DirectColorModeInfo; // Direct color mode attributes
+ //
+ // Manadory fields for VESA Bios Extensions 2.0 and above
+ //
+ UINT32 PhysBasePtr; // Physical Address for flat memory frame buffer
+ UINT32 Reserved2; // Reserved
+ UINT16 Reserved3; // Reserved
+ //
+ // Manadory fields for VESA Bios Extensions 3.0 and above
+ //
+ UINT16 LinBytesPerScanLine; // Bytes/scan line for linear modes
+ UINT8 BnkNumberOfImagePages; // Number of images for banked modes
+ UINT8 LinNumberOfImagePages; // Number of images for linear modes
+ UINT8 LinRedMaskSize; // Size of direct color red mask (linear mode)
+ UINT8 LinRedFieldPosition; // Bit posiiton of lsb of red mask (linear modes)
+ UINT8 LinGreenMaskSize; // Size of direct color green mask (linear mode)
+ UINT8 LinGreenFieldPosition; // Bit posiiton of lsb of green mask (linear modes)
+ UINT8 LinBlueMaskSize; // Size of direct color blue mask (linear mode)
+ UINT8 LinBlueFieldPosition; // Bit posiiton of lsb of blue mask (linear modes)
+ UINT8 LinRsvdMaskSize; // Size of direct color reserved mask (linear mode)
+ UINT8 LinRsvdFieldPosition; // Bit posiiton of lsb of reserved mask (linear modes)
+ UINT32 MaxPixelClock; // Maximum pixel clock (in Hz) for graphics mode
+ UINT8 Pad[190]; // Pad to 256 byte block size
+} VESA_BIOS_EXTENSIONS_MODE_INFORMATION_BLOCK;
+
+//
+// Super VGA Mode Information Block ModeAttributes field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_HARDWARE 0x0001 // 0: Mode not supported in handware
+// 1: Mode supported in handware
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_TTY 0x0004 // 0: TTY Output functions not supported by BIOS
+// 1: TTY Output functions supported by BIOS
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_COLOR 0x0008 // 0: Monochrome mode
+// 1: Color mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_GRAPHICS 0x0010 // 0: Text mode
+// 1: Graphics mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_VGA 0x0020 // 0: VGA compatible mode
+// 1: Not a VGA compatible mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NOT_WINDOWED 0x0040 // 0: VGA compatible windowed memory mode
+// 1: Not a VGA compatible windowed memory mode
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_LINEAR_FRAME_BUFFER 0x0080 // 0: No linear fram buffer mode available
+// 1: Linear frame buffer mode available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DOUBLE_SCAN 0x0100 // 0: No double scan mode available
+// 1: Double scan mode available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_INTERLACED 0x0200 // 0: No interlaced mode is available
+// 1: Interlaced mode is available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_NO_TRIPPLE_BUFFER 0x0400 // 0: No hardware triple buffer mode support available
+// 1: Hardware triple buffer mode support available
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_STEREOSCOPIC 0x0800 // 0: No hardware steroscopic display support
+// 1: Hardware steroscopic display support
+//
+#define VESA_BIOS_EXTENSIONS_MODE_ATTRIBUTE_DUAL_DISPLAY 0x1000 // 0: No dual display start address support
+// 1: Dual display start address support
+//
+// Super VGA Mode Information Block WinAAttribite/WinBAttributes field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_RELOCATABLE 0x01 // 0: Single non-relocatable window only
+// 1: Relocatable window(s) are supported
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_READABLE 0x02 // 0: Window is not readable
+// 1: Window is readable
+//
+#define VESA_BIOS_EXTENSIONS_WINX_ATTRIBUTE_WRITABLE 0x04 // 0: Window is not writable
+// 1: Window is writable
+//
+// Super VGA Mode Information Block DirectColorMode field bit defintions
+//
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_PROG_COLOR_RAMP 0x01 // 0: Color ram is fixed
+// 1: Color ramp is programmable
+//
+#define VESA_BIOS_EXTENSIONS_DIRECT_COLOR_MODE_RSVD_USABLE 0x02 // 0: Bits in Rsvd field are reserved
+// 1: Bits in Rsdv field are usable
+//
+// Super VGA Memory Models
+//
+typedef enum {
+ MemPL = 3, // Planar memory model
+ MemPK = 4, // Packed pixel memory model
+ MemRGB= 6, // Direct color RGB memory model
+ MemYUV= 7 // Direct color YUV memory model
+} VESA_BIOS_EXTENSIONS_MEMORY_MODELS;
+
+//
+// Super VGA CRTC Information Block
+//
+typedef struct {
+ UINT16 HorizontalTotal; // Horizontal total in pixels
+ UINT16 HorizontalSyncStart; // Horizontal sync start in pixels
+ UINT16 HorizontalSyncEnd; // Horizontal sync end in pixels
+ UINT16 VericalTotal; // Vertical total in pixels
+ UINT16 VericalSyncStart; // Vertical sync start in pixels
+ UINT16 VericalSyncEnd; // Vertical sync end in pixels
+ UINT8 Flags; // Flags (Interlaced/DoubleScan/etc).
+ UINT32 PixelClock; // Pixel clock in units of Hz
+ UINT16 RefreshRate; // Refresh rate in units of 0.01 Hz
+ UINT8 Reserved[40]; // Pad
+} VESA_BIOS_EXTENSIONS_CRTC_INFORMATION_BLOCK;
+
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGS_DOUBLE_SCAN 0x01 // 0: Graphics mode is not souble scanned
+// 1: Graphics mode is double scanned
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_FLAGSINTERLACED 0x02 // 0: Graphics mode is not interlaced
+// 1: Graphics mode is interlaced
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_HORIZONTAL_SYNC_NEGATIVE 0x04 // 0: Horizontal sync polarity is positive(+)
+// 0: Horizontal sync polarity is negative(-)
+//
+#define VESA_BIOS_EXTENSIONS_CRTC_VERITICAL_SYNC_NEGATIVE 0x08 // 0: Verical sync polarity is positive(+)
+// 0: Verical sync polarity is negative(-)
+//
+// Turn off byte packing of data structures
+//
+#pragma pack()
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
new file mode 100644
index 0000000000..7b1764acfc
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
@@ -0,0 +1,87 @@
+## @file
+# Video driver based on legacy bios.
+#
+# This driver by using Legacy Bios protocol service to support csm Video
+# and produce Graphics Output Protocol.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BiosVideoDxe
+ MODULE_UNI_FILE = BiosVideoDxe.uni
+ FILE_GUID = 0B04B2ED-861C-42cd-A22F-C3AAFACCB896
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = BiosVideoEntryPoint
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gBiosVideoDriverBinding
+# COMPONENT_NAME = gBiosVideoComponentName
+#
+
+[Sources]
+ BiosVideo.c
+ BiosVideo.h
+ ComponentName.c
+ VesaBiosExtensions.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ MemoryAllocationLib
+ DevicePathLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ ReportStatusCodeLib
+ DebugLib
+ PcdLib
+
+
+[Guids]
+ gEfiLegacyBiosGuid ## PRODUCES ##GUID # Install Legacy BIOS GUID to mark this driver as a BIOS Thunk Driver
+ gEfiEventExitBootServicesGuid ## CONSUMES ##Event
+
+[Protocols]
+ gEfiVgaMiniPortProtocolGuid ## BY_START
+ gEfiEdidDiscoveredProtocolGuid ## BY_START
+ gEfiGraphicsOutputProtocolGuid ## BY_START
+ gEfiEdidActiveProtocolGuid ## BY_START
+ gEfiLegacyBiosProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## BY_START
+ gEfiEdidOverrideProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## SOMETIMES_CONSUMES
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BiosVideoDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S
new file mode 100644
index 0000000000..a785256052
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.S
@@ -0,0 +1,67 @@
+## @file
+# Interrupt Redirection Template
+#
+# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)
+
+#----------------------------------------------------------------------------
+# Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+#
+# Input: None
+#
+# Output: None
+#
+# Prototype: VOID
+# InterruptRedirectionTemplate (
+# VOID
+# );
+#
+# Saves: None
+#
+# Modified: None
+#
+# Description: Contains the code that is copied into low memory (below 640K).
+# This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+# This template must be copied into low memory, and the IDT entries
+# 0x68-0x6F must be point to the low memory copy of this code. Each
+# entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+# computed.
+#
+#----------------------------------------------------------------------------
+ASM_PFX(InterruptRedirectionTemplate):
+ int $0x8
+ .byte 0xcf
+ nop
+ int $0x9
+ .byte 0xcf
+ nop
+ int $0xa
+ .byte 0xcf
+ nop
+ int $0xb
+ .byte 0xcf
+ nop
+ int $0xc
+ .byte 0xcf
+ nop
+ int $0xd
+ .byte 0xcf
+ nop
+ int $0xe
+ .byte 0xcf
+ nop
+ int $0xf
+ .byte 0xcf
+ nop
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm
new file mode 100644
index 0000000000..410ce5be6e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/IA32/InterruptTable.asm
@@ -0,0 +1,73 @@
+;; @file
+; Interrupt Redirection Template
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions
+; of the BSD License which accompanies this distribution. The
+; full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+;;
+
+.686P
+.MODEL FLAT, C
+.CODE
+
+;----------------------------------------------------------------------------
+; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: VOID
+; InterruptRedirectionTemplate (
+; VOID
+; );
+;
+; Saves: None
+;
+; Modified: None
+;
+; Description: Contains the code that is copied into low memory (below 640K).
+; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+; This template must be copied into low memory, and the IDT entries
+; 0x68-0x6F must be point to the low memory copy of this code. Each
+; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+; computed.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC C
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+END \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c
new file mode 100644
index 0000000000..8c8f6d321b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfBootSupport.c
@@ -0,0 +1,277 @@
+/** @file
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ //
+ // Shadow All Opion ROM
+ //
+ LegacyBiosShadowAllLegacyOproms (This);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the
+ parent device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ return EFI_INVALID_PARAMETER;
+}
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ *Size = 0;
+ return EFI_SUCCESS;
+}
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ UINTN NumberOfPages;
+ EFI_PHYSICAL_ADDRESS LoadedImageBase;
+ PE_COFF_LOADER_IMAGE_CONTEXT ImageContext;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ EFI_HANDLE NewImageHandle;
+
+ Status = gBS->HandleProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID *) &LoadedImage
+ );
+
+ if (!EFI_ERROR (Status)) {
+ LoadedImageBase = (EFI_PHYSICAL_ADDRESS) (UINTN) LoadedImage->ImageBase;
+ if (LoadedImageBase > 0xffffffff) {
+ NumberOfPages = (UINTN) (DivU64x32(LoadedImage->ImageSize, EFI_PAGE_SIZE) + 1);
+
+ //
+ // Allocate buffer below 4GB here
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x7FFFFFFF,
+ NumberOfPages, // do we have to convert this to pages??
+ &MemoryAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&ImageContext, sizeof (PE_COFF_LOADER_IMAGE_CONTEXT));
+ ImageContext.Handle = (VOID *)(UINTN)LoadedImageBase;
+ ImageContext.ImageRead = PeCoffLoaderImageReadFromMemory;
+
+ //
+ // Get information about the image being loaded
+ //
+ Status = PeCoffLoaderGetImageInfo (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ImageContext.ImageAddress = (PHYSICAL_ADDRESS)MemoryAddress;
+ //
+ // Align buffer on section boundry
+ //
+ ImageContext.ImageAddress += ImageContext.SectionAlignment - 1;
+ ImageContext.ImageAddress &= ~((PHYSICAL_ADDRESS)ImageContext.SectionAlignment - 1);
+
+ //
+ // Load the image to our new buffer
+ //
+ Status = PeCoffLoaderLoadImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Relocate the image in our new buffer
+ //
+ Status = PeCoffLoaderRelocateImage (&ImageContext);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+
+ //
+ // Create a new handle with gEfiCallerIdGuid to be used as the ImageHandle fore the reloaded image
+ //
+ NewImageHandle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &NewImageHandle,
+ &gEfiCallerIdGuid,
+ EFI_NATIVE_INTERFACE,
+ NULL
+ );
+
+ //
+ // Flush the instruction cache so the image data is written before we execute it
+ //
+ InvalidateInstructionCacheRange ((VOID *)(UINTN)ImageContext.ImageAddress, (UINTN)ImageContext.ImageSize);
+
+ Status = ((EFI_IMAGE_ENTRY_POINT)(UINTN)(ImageContext.EntryPoint)) (NewImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (MemoryAddress, NumberOfPages);
+ return Status;
+ }
+ //
+ // return error directly the BS will unload this image
+ //
+ return EFI_ABORTED;
+ }
+ }
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h
new file mode 100644
index 0000000000..26aa3a694b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.h
@@ -0,0 +1,102 @@
+/** @file
+
+Copyright (c) 2007 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _IPF_THUNK_H_
+#define _IPF_THUNK_H_
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Sal.h>
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Register physical address of Esal Data Area
+
+ @param ReverseThunkCodeAddress Reverse Thunk Address
+ @param IntThunkAddress IntThunk Address
+
+ @retval EFI_SUCCESS ESAL data area set successfully.
+
+**/
+EFI_STATUS
+EsalSetSalDataArea (
+ IN UINTN ReverseThunkCodeAddress,
+ IN UINTN IntThunkAddress
+ );
+
+/**
+ Get address of reverse thunk.
+
+ @retval EFI_SAL_SUCCESS Address of reverse thunk returned successfully.
+
+**/
+SAL_RETURN_REGS
+EsalGetReverseThunkAddress (
+ VOID
+ );
+
+typedef struct {
+ UINT32 Eax; // 0
+ UINT32 Ecx; // 4
+ UINT32 Edx; // 8
+ UINT32 Ebx; // 12
+ UINT32 Esp; // 16
+ UINT32 Ebp; // 20
+ UINT32 Esi; // 24
+ UINT32 Edi; // 28
+ UINT32 Eflag; // 32
+ UINT32 Eip; // 36
+ UINT16 Cs; // 40
+ UINT16 Ds; // 42
+ UINT16 Es; // 44
+ UINT16 Fs; // 46
+ UINT16 Gs; // 48
+ UINT16 Ss; // 50
+} IPF_DWORD_REGS;
+
+/**
+ Entrypoint of IA32 code.
+
+ @param CallTypeData Data of call type
+ @param DwordRegister Register set of IA32 general registers
+ and segment registers
+ @param StackPointer Stack pointer.
+ @param StackSize Size of stack.
+
+**/
+VOID
+EfiIaEntryPoint (
+ UINT64 CallTypeData,
+ IPF_DWORD_REGS *DwordRegister,
+ UINT64 StackPointer,
+ UINT64 StackSize
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i
new file mode 100644
index 0000000000..441bb25e3d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.i
@@ -0,0 +1,89 @@
+//// @file
+//
+// Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution. The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+////
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define LOW_STACK_SIZE (8*1024) // 8k?
+
+//
+// Low memory Thunk Structure
+//
+#define Code 0
+#define LowReverseThunkStart Code + 4096
+#define GdtDesc LowReverseThunkStart + 4
+#define IdtDesc GdtDesc + 6
+#define FlatSs IdtDesc + 6
+#define FlatEsp FlatSs + 4
+#define LowCodeSelector FlatEsp + 4
+#define LowDataSelector LowCodeSelector + 4
+#define LowStack LowDataSelector + 4
+#define RealModeIdtDesc LowStack + 4
+#define RealModeGdt RealModeIdtDesc + 6
+#define RealModeGdtDesc RealModeGdt + (8 * NUM_REAL_GDT_ENTRIES)
+#define RevRealDs RealModeGdtDesc + 6
+#define RevRealSs RevRealDs + 2
+#define RevRealEsp RevRealSs + 2
+#define RevRealIdtDesc RevRealEsp + 4
+#define RevFlatDataSelector RevRealIdtDesc + 6
+#define RevFlatStack RevFlatDataSelector + 2
+#define Stack RevFlatStack + 4
+#define RevThunkStack Stack + LOW_STACK_SIZE
+
+#define EfiToLegacy16InitTable RevThunkStack + LOW_STACK_SIZE
+#define InitTableBiosLessThan1MB EfiToLegacy16InitTable
+#define InitTableHiPmmMemory InitTableBiosLessThan1MB + 4
+#define InitTablePmmMemorySizeInBytes InitTableHiPmmMemory + 4
+#define InitTableReverseThunkCallSegment InitTablePmmMemorySizeInBytes + 4
+#define InitTableReverseThunkCallOffset InitTableReverseThunkCallSegment + 2
+#define InitTableNumberE820Entries InitTableReverseThunkCallOffset + 2
+#define InitTableOsMemoryAbove1Mb InitTableNumberE820Entries + 4
+#define InitTableThunkStart InitTableOsMemoryAbove1Mb + 4
+#define InitTableThunkSizeInBytes InitTableThunkStart + 4
+#define InitTable16InitTableEnd InitTableThunkSizeInBytes + 4
+
+#define EfiToLegacy16BootTable InitTable16InitTableEnd
+#define BootTableBiosLessThan1MB EfiToLegacy16BootTable
+#define BootTableHiPmmMemory BootTableBiosLessThan1MB + 4
+#define BootTablePmmMemorySizeInBytes BootTableHiPmmMemory + 4
+#define BootTableReverseThunkCallSegment BootTablePmmMemorySizeInBytes + 4
+#define BootTableReverseThunkCallOffset BootTableReverseThunkCallSegment + 2
+#define BootTableNumberE820Entries BootTableReverseThunkCallOffset + 2
+#define BootTableOsMemoryAbove1Mb BootTableNumberE820Entries + 4
+#define BootTableThunkStart BootTableOsMemoryAbove1Mb + 4
+#define BootTableThunkSizeInBytes BootTableThunkStart + 4
+#define EfiToLegacy16BootTableEnd BootTableThunkSizeInBytes + 4
+
+#define InterruptRedirectionCode EfiToLegacy16BootTableEnd
+#define PciHandler InterruptRedirectionCode + 32
+
+
+//
+// Register Sets (16 Bit)
+//
+
+#define AX 0
+#define BX 2
+#define CX 4
+#define DX 6
+#define SI 8
+#define DI 10
+#define Flags 12
+#define ES 14
+#define CS 16
+#define SS 18
+#define DS 20
+#define BP 22
+
+
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s
new file mode 100644
index 0000000000..fc56176934
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/IpfThunk.s
@@ -0,0 +1,524 @@
+//// @file
+//
+// Copyright (c) 1999 - 2008, Intel Corporation. All rights reserved.<BR>
+//
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions
+// of the BSD License which accompanies this distribution. The
+// full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+////
+
+.file "IpfThunk.s"
+
+#include "IpfMacro.i"
+#include "Ipf/IpfThunk.i"
+
+.align 0x10
+//-----------------------------------------------------------------------------
+//++
+// EfiIaEntryPoint
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+// in1 = ptr to legacy bios reg
+// in2 = ptr to Call Stack
+// in3 = Call Stack Size
+//
+// Return Value:
+// r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+PROCEDURE_ENTRY(EfiIaEntryPoint)
+
+ alloc loc0 = 8,10,8,0;;
+
+ mov out0 = r0;;
+ mov out1 = r0;;
+ mov out2 = r0;;
+ mov out3 = r0;;
+ mov out4 = r0;;
+ mov out5 = r0;;
+ mov out6 = r0;;
+ mov out7 = r0;;
+
+ mov loc1 = b0;; // save efi (b0)
+ mov loc2 = psr;; // save efi (PSR)
+ mov loc3 = gp;; // save efi (GP)
+ mov loc4 = pr;; // save efi (PR)
+ mov loc5 = sp;; // save efi (SP)
+ mov loc6 = r13;; // save efi (TP)
+ mov loc7 = ar.lc;; // save efi (LC)
+ mov loc8 = ar.fpsr;; // save efi (FPSR)
+
+ mov r8 = r0;; // return status
+ mov r9 = r0;; // return value
+ mov r10 = r0;; // return value
+ mov r11 = r0;; // return value
+
+bios_int_func::
+ rsm 0x4000;; // i(14)=0, disable interrupt
+ srlz.d;;
+ srlz.i;;
+
+//---------------------//
+// save fp registers //
+//---------------------//
+
+ dep sp = 0,sp,0,4;; // align 16
+ add sp = -16,sp;; // post decrement
+
+int_ip_1x::
+ mov r2 = ip;;
+ add r2 = (int_ip_1y - int_ip_1x),r2;;
+ mov b7 = r2;;
+ br save_fp_registers;;
+
+int_ip_1y::
+ add sp = 16,sp;; // adjust (SP)
+ mov loc9 = sp;; // save (SP)
+ adds sp = 0x10,in1;; // in1 + 0x10 = SP
+ ld4 sp = [sp];; // SP
+ adds r17 = 0x32,in1;; // in1 + 0x32 = SS
+ ld2 r17 = [r17];; // SS
+ movl r2 = 0xffffffff;; // if no SS:SP, then define new SS:SP
+ cmp.ne p6,p0 = sp,r2;;
+ movl r2 = 0xffff;;
+ cmp.ne.or p6,p0 = r17,r2;;
+ (p6) br.sptk bif_1;;
+
+ mov sp = in3;; // 16-bit stack pointer
+ mov r2 = psr;;
+ tbit.z p6,p7 = r2,17;; // psr.dt (Physical OR Virtual)
+
+bif_ip1x::
+ mov r2 = in2;; // ia32 callback stack top
+ mov r3 = in3;; // 16-bit stack pointer
+ sub r2 = r2,r3;;
+ shr.u r17 = r2,4;; // 16-bit stack segment
+
+bif_1::
+ extr.u sp = sp,0,16;; // SP (16-bit sp for legacy code)
+ dep sp = 0,sp,0,3;; // align 8
+ cmp.eq p6,p0 = 0,sp;; // if SP=0000 then wrap to 0x10000
+ (p6) dep sp = -1,sp,16,1;;
+ shladd r2 = r17,4,sp;; // ESP = SS<<4+SP
+ add r2 = -8,r2;; // post decrement 64 bit pointer
+ add sp = -8,sp;; // post decrement SP
+
+sale_ip1x::
+ mov r18 = ip;;
+ adds r18 = (sale_ip1y - sale_ip1x),r18;;
+ sub r18 = r18,r2;; // return address - CS base
+ add r18 = r18,sp;; // adjustment for stack
+ shl r18 = r18,32;;
+ movl r19 = 0xb80f66fa;; // CLI, JMPE xxxxxxxx
+ or r18 = r18,r19;;
+ st8 [r2] = r18;; // (FA,66,0F,B8,xx,xx,xx,xx)
+
+ cmp.eq p6,p0 = 0,sp;; // if SP=0000 then wrap to 0x10000
+ (p6) dep sp = -1,sp,16,1;;
+ shladd r2 = r17,4,sp;; // ESP=SS<<4+SP
+ add r2 = -2,r2;; // post decrement 64 bit pointer
+ add sp = -2,sp;; // post decrement SP
+
+ movl r18 = 0x8000000000000100;; // CALL FAR function
+ cmp.eq p6,p7 = in0,r18;;
+ (p6) add r19 = 0x28,in1;; // in1 + 0x28 = CS
+ (p6) ld2 r18 = [r19],-4;; // CS
+ (p6) st2 [r2] = r18,-2;; // in1 + 0x24 = EIP
+ (p6) ld2 r18 = [r19];; // EIP
+ (p6) st2 [r2] = r18,-2;; //
+ (p6) movl r18 = 0x9a90;; // nop, CALLFAR xxxx:yyyy
+
+ (p7) movl r18 = 0xcd;; // INT xx
+ (p7) dep r18 = in0,r18,8,8;;
+ st2 [r2] = r18;; // (CD,xx)
+
+ mov r18 = r2;; // EIP for legacy execution
+
+//------------------------------//
+// flush 32 bytes legacy code //
+//------------------------------//
+
+ dep r2 = 0,r2,0,5;; // align to 32
+ fc r2;;
+ sync.i;;
+ srlz.i;;
+ srlz.d;;
+
+//------------------------------//
+// load legacy registers //
+//------------------------------//
+ mov r2 = in1;; // IA32 BIOS register state
+ ld4 r8 = [r2],4;; // in1 + 0 = EAX
+ ld4 r9 = [r2],4;; // in1 + 4 = ECX
+ ld4 r10 = [r2],4;; // in1 + 8 = EDX
+ ld4 r11 = [r2],4;; // in1 + 12 = EBX
+
+ add r2 = 4,r2;; // in1 + 16 = ESP (skip)
+
+ ld4 r13 = [r2],4;; // in1 + 20 = EBP
+ ld4 r14 = [r2],4;; // in1 + 24 = ESI
+ ld4 r15 = [r2],4;; // in1 + 28 = EDI
+ ld4 r3 = [r2],4;; // in1 + 32 = EFLAGS
+ mov ar.eflag = r3;;
+
+ add r2 = 4,r2;; // in1 + 36 = EIP (skip)
+ add r2 = 2,r2;; // in1 + 40 = CS (skip)
+
+ ld2 r16 = [r2],2;; // in1 + 42 = DS, (r16 = GS,FS,ES,DS)
+ movl r27 = 0xc93fffff00000000;;
+ dep r27 = r16,r27,4,16;; // r27 = DSD
+
+ ld2 r19 = [r2],2;; // in1 + 44 = ES
+ dep r16 = r19,r16,16,16;;
+ movl r24 = 0xc93fffff00000000;;
+ dep r24 = r19,r24,4,16;; // r24 = ESD
+
+ ld2 r19 = [r2],2;; // in1 + 46 = FS
+ dep r16 = r19,r16,32,16;;
+ movl r28 = 0xc93fffff00000000;;
+ dep r28 = r19,r28,4,16;; // r28 = FSD
+
+ ld2 r19 = [r2],2;; // in1 + 48 = GS
+ dep r16 = r19,r16,48,16;;
+ movl r29 = 0xc93fffff00000000;;
+ dep r29 = r19,r29,4,16;; // r29 = GSD
+
+ mov r30 = r0;; // r30 = LDTD, clear NaT
+ mov r31 = r0;; // r31 = GDTD, clear NaT
+
+ dep r17 = r17,r17,16,16;; // CS = SS, (r17 = TSS,LDT,SS,CS)
+
+ movl r3 = 0x0930ffff00000000;;
+ dep r3 = r17,r3,4,16;;
+ mov ar.csd = r3;; // ar25 = CSD
+ mov ar.ssd = r3;; // ar26 = SSD
+
+//------------------------------//
+// give control to INT function //
+//------------------------------//
+
+ br.call.sptk b0 = execute_int_function;;
+
+//------------------------------//
+// store legacy registers //
+//------------------------------//
+
+ mov r2 = in1;;
+ st4 [r2] = r8,4;; // EAX
+ st4 [r2] = r9,4;; // ECX
+ st4 [r2] = r10,4;; // EDX
+ st4 [r2] = r11,4;; // EBX
+
+ add r2 = 4,r2;; // ESP (skip)
+
+ st4 [r2] = r13,4;; // EBP
+ st4 [r2] = r14,4;; // ESI
+ st4 [r2] = r15,4;; // EDI
+
+ mov r3 = ar.eflag;;
+ st4 [r2] = r3,4;; // EFLAGS
+
+ add r2 = 4,r2;; // EIP (skip)
+ add r2 = 2,r2;; // CS (skip)
+
+ st2 [r2] = r16,2;; // DS, (r16 = GS,FS,ES,DS)
+
+ extr.u r3 = r16,16,16;;
+ st2 [r2] = r3,2;; // ES
+
+ extr.u r3 = r16,32,16;;
+ st2 [r2] = r3,2;; // FS
+
+ extr.u r3 = r16,48,16;;
+ st2 [r2] = r3,2;; // GS
+
+//------------------------------//
+// restore fp registers //
+//------------------------------//
+ mov sp = loc9;; // restore (SP)
+int_ip_2x::
+ mov r2 = ip;;
+ add r2 = (int_ip_2y - int_ip_2x),r2;;
+ mov b7 = r2;;
+ br restore_fp_registers;;
+
+int_ip_2y::
+ mov r8 = r0;; // return status
+ mov r9 = r0;; // return value
+ mov r10 = r0;; // return value
+ mov r11 = r0;; // return value
+
+ mov ar.fpsr = loc8;; // restore efi (FPSR)
+ mov ar.lc = loc7;; // restore efi (LC)
+ mov r13 = loc6;; // restore efi (TP)
+ mov sp = loc5;; // restore efi (SP)
+ mov pr = loc4;; // restore efi (PR)
+ mov gp = loc3;; // restore efi (GP)
+ mov psr.l = loc2;; // restore efi (PSR)
+ srlz.d;;
+ srlz.i;;
+ mov b0 = loc1;; // restore efi (b0)
+ mov ar.pfs = loc0;;
+ br.ret.sptk b0;; // return to efi
+
+PROCEDURE_EXIT (EfiIaEntryPoint)
+
+//==============================//
+// EXECUTE_INT_FUNCTION //
+//==============================//
+// switch to virtual address //
+//------------------------------//
+
+execute_int_function::
+
+ alloc r2 = 0,0,0,0;; // cfm.sof=0
+ flushrs;;
+
+ rsm 0x2000;; // ic(13)=0 for control register programming
+ srlz.d;;
+ srlz.i;;
+
+ mov r2 = psr;;
+ dep r2 = -1,r2,34,1;; // set is(34)
+ dep r2 = -1,r2,44,1;; // set bn(44)
+ dep r2 = -1,r2,36,1;; // set it(36)
+ dep r2 = -1,r2,27,1;; // set rt(27)
+ dep r2 = -1,r2,17,1;; // set dt(17)
+ dep r2 = 0,r2,3,1;; // reset ac(3)
+ dep r2 = -1,r2,13,1;; // set ic(13)
+
+ mov cr.ipsr = r2;;
+ mov cr.ifs = r0;; // clear interruption function state register
+ mov cr.iip = r18;;
+
+ rfi;; // go to legacy code execution
+
+//------------------------------//
+// back from legacy code //
+//------------------------------//
+// switch to physical address //
+//------------------------------//
+
+sale_ip1y::
+ rsm 0x6000;; // i(14)=0,ic(13)=0 for control reg programming
+ srlz.d;;
+ srlz.i;;
+
+ mov r2 = psr;;
+ dep r2 = -1,r2,44,1;; // set bn(44)
+ dep r2 = 0,r2,36,1;; // reset it(36)
+ dep r2 = 0,r2,27,1;; // reset rt(27)
+ dep r2 = 0,r2,17,1;; // reset dt(17)
+ dep r2 = -1,r2,13,1;; // set ic(13)
+ mov cr.ipsr = r2;;
+
+sale_ip2x::
+ mov r2 = ip;;
+ add r2 = (sale_ip2y - sale_ip2x),r2;;
+ mov cr.ifs = r0;; // clear interruption function state register
+ mov cr.iip = r2;;
+ rfi;;
+
+sale_ip2y::
+ br.ret.sptk b0;; // return to SAL
+
+//------------------------------//
+// store fp registers //
+//------------------------------//
+save_fp_registers::
+ stf.spill [sp]=f2,-16;; stf.spill [sp]=f3,-16;;
+ stf.spill [sp]=f4,-16;; stf.spill [sp]=f5,-16;; stf.spill [sp]=f6,-16;; stf.spill [sp]=f7,-16;;
+ stf.spill [sp]=f8,-16;; stf.spill [sp]=f9,-16;; stf.spill [sp]=f10,-16;; stf.spill [sp]=f11,-16;;
+ stf.spill [sp]=f12,-16;; stf.spill [sp]=f13,-16;; stf.spill [sp]=f14,-16;; stf.spill [sp]=f15,-16;;
+ stf.spill [sp]=f16,-16;; stf.spill [sp]=f17,-16;; stf.spill [sp]=f18,-16;; stf.spill [sp]=f19,-16;;
+ stf.spill [sp]=f20,-16;; stf.spill [sp]=f21,-16;; stf.spill [sp]=f22,-16;; stf.spill [sp]=f23,-16;;
+ stf.spill [sp]=f24,-16;; stf.spill [sp]=f25,-16;; stf.spill [sp]=f26,-16;; stf.spill [sp]=f27,-16;;
+ stf.spill [sp]=f28,-16;; stf.spill [sp]=f29,-16;; stf.spill [sp]=f30,-16;; stf.spill [sp]=f31,-16;;
+ stf.spill [sp]=f32,-16;; stf.spill [sp]=f33,-16;; stf.spill [sp]=f34,-16;; stf.spill [sp]=f35,-16;;
+ stf.spill [sp]=f36,-16;; stf.spill [sp]=f37,-16;; stf.spill [sp]=f38,-16;; stf.spill [sp]=f39,-16;;
+ stf.spill [sp]=f40,-16;; stf.spill [sp]=f41,-16;; stf.spill [sp]=f42,-16;; stf.spill [sp]=f43,-16;;
+ stf.spill [sp]=f44,-16;; stf.spill [sp]=f45,-16;; stf.spill [sp]=f46,-16;; stf.spill [sp]=f47,-16;;
+ stf.spill [sp]=f48,-16;; stf.spill [sp]=f49,-16;; stf.spill [sp]=f50,-16;; stf.spill [sp]=f51,-16;;
+ stf.spill [sp]=f52,-16;; stf.spill [sp]=f53,-16;; stf.spill [sp]=f54,-16;; stf.spill [sp]=f55,-16;;
+ stf.spill [sp]=f56,-16;; stf.spill [sp]=f57,-16;; stf.spill [sp]=f58,-16;; stf.spill [sp]=f59,-16;;
+ stf.spill [sp]=f60,-16;; stf.spill [sp]=f61,-16;; stf.spill [sp]=f62,-16;; stf.spill [sp]=f63,-16;;
+ stf.spill [sp]=f64,-16;; stf.spill [sp]=f65,-16;; stf.spill [sp]=f66,-16;; stf.spill [sp]=f67,-16;;
+ stf.spill [sp]=f68,-16;; stf.spill [sp]=f69,-16;; stf.spill [sp]=f70,-16;; stf.spill [sp]=f71,-16;;
+ stf.spill [sp]=f72,-16;; stf.spill [sp]=f73,-16;; stf.spill [sp]=f74,-16;; stf.spill [sp]=f75,-16;;
+ stf.spill [sp]=f76,-16;; stf.spill [sp]=f77,-16;; stf.spill [sp]=f78,-16;; stf.spill [sp]=f79,-16;;
+ stf.spill [sp]=f80,-16;; stf.spill [sp]=f81,-16;; stf.spill [sp]=f82,-16;; stf.spill [sp]=f83,-16;;
+ stf.spill [sp]=f84,-16;; stf.spill [sp]=f85,-16;; stf.spill [sp]=f86,-16;; stf.spill [sp]=f87,-16;;
+ stf.spill [sp]=f88,-16;; stf.spill [sp]=f89,-16;; stf.spill [sp]=f90,-16;; stf.spill [sp]=f91,-16;;
+ stf.spill [sp]=f92,-16;; stf.spill [sp]=f93,-16;; stf.spill [sp]=f94,-16;; stf.spill [sp]=f95,-16;;
+ stf.spill [sp]=f96,-16;; stf.spill [sp]=f97,-16;; stf.spill [sp]=f98,-16;; stf.spill [sp]=f99,-16;;
+ stf.spill [sp]=f100,-16;;stf.spill [sp]=f101,-16;;stf.spill [sp]=f102,-16;;stf.spill [sp]=f103,-16;;
+ stf.spill [sp]=f104,-16;;stf.spill [sp]=f105,-16;;stf.spill [sp]=f106,-16;;stf.spill [sp]=f107,-16;;
+ stf.spill [sp]=f108,-16;;stf.spill [sp]=f109,-16;;stf.spill [sp]=f110,-16;;stf.spill [sp]=f111,-16;;
+ stf.spill [sp]=f112,-16;;stf.spill [sp]=f113,-16;;stf.spill [sp]=f114,-16;;stf.spill [sp]=f115,-16;;
+ stf.spill [sp]=f116,-16;;stf.spill [sp]=f117,-16;;stf.spill [sp]=f118,-16;;stf.spill [sp]=f119,-16;;
+ stf.spill [sp]=f120,-16;;stf.spill [sp]=f121,-16;;stf.spill [sp]=f122,-16;;stf.spill [sp]=f123,-16;;
+ stf.spill [sp]=f124,-16;;stf.spill [sp]=f125,-16;;stf.spill [sp]=f126,-16;;stf.spill [sp]=f127,-16;;
+ invala;;
+ br b7;;
+
+//------------------------------//
+// restore fp registers //
+//------------------------------//
+restore_fp_registers::
+ ldf.fill f127=[sp],16;;ldf.fill f126=[sp],16;;ldf.fill f125=[sp],16;;ldf.fill f124=[sp],16;;
+ ldf.fill f123=[sp],16;;ldf.fill f122=[sp],16;;ldf.fill f121=[sp],16;;ldf.fill f120=[sp],16;;
+ ldf.fill f119=[sp],16;;ldf.fill f118=[sp],16;;ldf.fill f117=[sp],16;;ldf.fill f116=[sp],16;;
+ ldf.fill f115=[sp],16;;ldf.fill f114=[sp],16;;ldf.fill f113=[sp],16;;ldf.fill f112=[sp],16;;
+ ldf.fill f111=[sp],16;;ldf.fill f110=[sp],16;;ldf.fill f109=[sp],16;;ldf.fill f108=[sp],16;;
+ ldf.fill f107=[sp],16;;ldf.fill f106=[sp],16;;ldf.fill f105=[sp],16;;ldf.fill f104=[sp],16;;
+ ldf.fill f103=[sp],16;;ldf.fill f102=[sp],16;;ldf.fill f101=[sp],16;;ldf.fill f100=[sp],16;;
+ ldf.fill f99=[sp],16;; ldf.fill f98=[sp],16;; ldf.fill f97=[sp],16;; ldf.fill f96=[sp],16;;
+ ldf.fill f95=[sp],16;; ldf.fill f94=[sp],16;; ldf.fill f93=[sp],16;; ldf.fill f92=[sp],16;;
+ ldf.fill f91=[sp],16;; ldf.fill f90=[sp],16;; ldf.fill f89=[sp],16;; ldf.fill f88=[sp],16;;
+ ldf.fill f87=[sp],16;; ldf.fill f86=[sp],16;; ldf.fill f85=[sp],16;; ldf.fill f84=[sp],16;;
+ ldf.fill f83=[sp],16;; ldf.fill f82=[sp],16;; ldf.fill f81=[sp],16;; ldf.fill f80=[sp],16;;
+ ldf.fill f79=[sp],16;; ldf.fill f78=[sp],16;; ldf.fill f77=[sp],16;; ldf.fill f76=[sp],16;;
+ ldf.fill f75=[sp],16;; ldf.fill f74=[sp],16;; ldf.fill f73=[sp],16;; ldf.fill f72=[sp],16;;
+ ldf.fill f71=[sp],16;; ldf.fill f70=[sp],16;; ldf.fill f69=[sp],16;; ldf.fill f68=[sp],16;;
+ ldf.fill f67=[sp],16;; ldf.fill f66=[sp],16;; ldf.fill f65=[sp],16;; ldf.fill f64=[sp],16;;
+ ldf.fill f63=[sp],16;; ldf.fill f62=[sp],16;; ldf.fill f61=[sp],16;; ldf.fill f60=[sp],16;;
+ ldf.fill f59=[sp],16;; ldf.fill f58=[sp],16;; ldf.fill f57=[sp],16;; ldf.fill f56=[sp],16;;
+ ldf.fill f55=[sp],16;; ldf.fill f54=[sp],16;; ldf.fill f53=[sp],16;; ldf.fill f52=[sp],16;;
+ ldf.fill f51=[sp],16;; ldf.fill f50=[sp],16;; ldf.fill f49=[sp],16;; ldf.fill f48=[sp],16;;
+ ldf.fill f47=[sp],16;; ldf.fill f46=[sp],16;; ldf.fill f45=[sp],16;; ldf.fill f44=[sp],16;;
+ ldf.fill f43=[sp],16;; ldf.fill f42=[sp],16;; ldf.fill f41=[sp],16;; ldf.fill f40=[sp],16;;
+ ldf.fill f39=[sp],16;; ldf.fill f38=[sp],16;; ldf.fill f37=[sp],16;; ldf.fill f36=[sp],16;;
+ ldf.fill f35=[sp],16;; ldf.fill f34=[sp],16;; ldf.fill f33=[sp],16;; ldf.fill f32=[sp],16;;
+ ldf.fill f31=[sp],16;; ldf.fill f30=[sp],16;; ldf.fill f29=[sp],16;; ldf.fill f28=[sp],16;;
+ ldf.fill f27=[sp],16;; ldf.fill f26=[sp],16;; ldf.fill f25=[sp],16;; ldf.fill f24=[sp],16;;
+ ldf.fill f23=[sp],16;; ldf.fill f22=[sp],16;; ldf.fill f21=[sp],16;; ldf.fill f20=[sp],16;;
+ ldf.fill f19=[sp],16;; ldf.fill f18=[sp],16;; ldf.fill f17=[sp],16;; ldf.fill f16=[sp],16;;
+ ldf.fill f15=[sp],16;; ldf.fill f14=[sp],16;; ldf.fill f13=[sp],16;; ldf.fill f12=[sp],16;;
+ ldf.fill f11=[sp],16;; ldf.fill f10=[sp],16;; ldf.fill f9=[sp],16;; ldf.fill f8=[sp],16;;
+ ldf.fill f7=[sp],16;; ldf.fill f6=[sp],16;; ldf.fill f5=[sp],16;; ldf.fill f4=[sp],16;;
+ ldf.fill f3=[sp],16;; ldf.fill f2=[sp],16;;
+ invala;;
+ br b7;;
+
+//-----------------------------------------------------------------------------
+//++
+// EsalSetSalDataArea
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+// in0 = Reverse Thunk Address
+// in1 = IntThunk Address
+//
+// Return Value:
+// r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+
+PROCEDURE_ENTRY (EsalSetSalDataArea)
+
+ NESTED_SETUP (4,8,0,0)
+
+EsalCalcStart1_3::
+ mov r8 = ip;;
+ add r8 = (ReverseThunkAddress - EsalCalcStart1_3), r8;;
+ st8 [r8] = in0;;
+
+EsalCalcStart1_4::
+ mov r8 = ip;;
+ add r8 = (IntThunkAddress - EsalCalcStart1_4), r8;;
+ st8 [r8] = in1;;
+
+ mov r8 = r0;;
+
+ NESTED_RETURN
+
+PROCEDURE_EXIT (EsalSetSalDataArea)
+
+//-----------------------------------------------------------------------------
+//++
+// EsagGetReverseThunkAddress
+//
+// Register physical address of Esal Data Area
+//
+// On Entry :
+// out0 = CodeStart
+// out1 = CodeEnd
+// out1 = ReverseThunkCode
+//
+// Return Value:
+// r8 = SAL_SUCCESS
+//
+// As per static calling conventions.
+//
+//--
+//---------------------------------------------------------------------------
+
+PROCEDURE_ENTRY (EsalGetReverseThunkAddress)
+
+ NESTED_SETUP (4,8,0,0)
+
+EsalCalcStart1_31::
+ mov r8 = ip;;
+ add r8 = (Ia32CodeStart - EsalCalcStart1_31), r8;;
+ mov r9 = r8;;
+
+EsalCalcStart1_41::
+ mov r8 = ip;;
+ add r8 = (Ia32CodeEnd - EsalCalcStart1_41), r8;;
+ mov r10 = r8;;
+
+EsalCalcStart1_51::
+ mov r8 = ip;;
+ add r8 = (ReverseThunkAddress - EsalCalcStart1_51), r8;;
+ mov r11 = r8;;
+ mov r8 = r0;;
+
+ NESTED_RETURN
+
+PROCEDURE_EXIT (EsalGetReverseThunkAddress)
+
+
+.align 16
+PROCEDURE_ENTRY (InterruptRedirectionTemplate)
+ data8 0x90CFCD08
+ data8 0x90CFCD09
+ data8 0x90CFCD0A
+ data8 0x90CFCD0B
+ data8 0x90CFCD0C
+ data8 0x90CFCD0D
+ data8 0x90CFCD0E
+ data8 0x90CFCD0F
+PROCEDURE_EXIT (InterruptRedirectionTemplate)
+
+//------------------------------//
+// Reverse Thunk Code //
+//------------------------------//
+
+Ia32CodeStart::
+ br.sptk.few Ia32CodeStart;; // IPF CSM integration -Bug (Write This Code)
+ReverseThunkCode::
+ data8 0xb80f66fa // CLI, JMPE xxxx
+ReverseThunkAddress::
+ data8 0 // Return Address
+IntThunkAddress::
+ data8 0 // IntThunk Address
+Ia32CodeEnd::
+
+
+
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
new file mode 100644
index 0000000000..e601bbd63b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Ipf/Thunk.c
@@ -0,0 +1,550 @@
+/** @file
+ Call into 16-bit BIOS code
+
+ BugBug: Thunker does A20 gate. Can we get rid of this code or
+ put it into Legacy16 code.
+
+Copyright (c) 1999 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include "IpfThunk.h"
+
+/**
+ Gets the current flat GDT and IDT descriptors and store them in
+ Private->IntThunk. These values are used by the Thunk code.
+ This method must be called before every thunk in order to assure
+ that the correct GDT and IDT are restored after the thunk.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosGetFlatDescs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ BIOS interrupt call function.
+
+ @param BiosInt Int number of BIOS call
+ @param Segment Segment number
+ @param Offset Offset in segment
+ @param Regs IA32 Register set.
+ @param Stack Base address of stack
+ @param StackSize Size of stack
+
+ @retval EFI_SUCCESS BIOS interrupt call succeeds.
+
+**/
+EFI_STATUS
+BiosIntCall (
+ IN UINT16 BiosInt,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ IPF_DWORD_REGS DwordRegs;
+ UINT64 IntTypeVariable;
+
+ IntTypeVariable = 0x8000000000000000;
+ IntTypeVariable |= (UINT64)BiosInt;
+
+ DwordRegs.Cs = Segment;
+ DwordRegs.Eip = Offset;
+
+ DwordRegs.Ds = Regs->X.DS;
+ DwordRegs.Es = Regs->X.ES;
+ DwordRegs.Fs = Regs->X.ES;
+ DwordRegs.Gs = Regs->X.ES;
+ DwordRegs.Ss = 0xFFFF;
+
+ DwordRegs.Eax = Regs->X.AX;
+ DwordRegs.Ebx = Regs->X.BX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ DwordRegs.Ecx = Regs->E.ECX;
+ DwordRegs.Edx = Regs->X.DX;
+
+ DwordRegs.Ebp = Regs->X.BP;
+ DwordRegs.Eflag = *((UINT16 *) &Regs->X.Flags);
+
+ DwordRegs.Edi = Regs->X.DI;
+ DwordRegs.Esi = Regs->X.SI;
+ DwordRegs.Esp = 0xFFFFFFFF;
+
+ EfiIaEntryPoint (IntTypeVariable, &DwordRegs, ((UINTN) Stack + StackSize), StackSize);
+
+ Regs->X.CS = DwordRegs.Cs;
+
+ Regs->X.DS = (UINT16) DwordRegs.Ds;
+ Regs->X.SS = (UINT16) DwordRegs.Ss;
+
+ Regs->E.EAX = DwordRegs.Eax;
+ Regs->E.EBX = DwordRegs.Ebx;
+ Regs->E.ECX = DwordRegs.Ecx;
+ Regs->E.EDX = DwordRegs.Edx;
+
+ Regs->E.EBP = DwordRegs.Ebp;
+ CopyMem (&Regs->X.Flags, &DwordRegs.Eflag, sizeof (EFI_FLAGS_REG));
+
+ Regs->E.EDI = DwordRegs.Edi;
+ Regs->E.ESI = DwordRegs.Esi;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Template of real mode code.
+
+ @param CodeStart Start address of code.
+ @param CodeEnd End address of code
+ @param ReverseThunkStart Start of reverse thunk.
+ @param IntThunk Low memory thunk.
+
+**/
+VOID
+RealModeTemplate (
+ OUT UINTN *CodeStart,
+ OUT UINTN *CodeEnd,
+ OUT UINTN *ReverseThunkStart,
+ LOW_MEMORY_THUNK *IntThunk
+ )
+{
+ SAL_RETURN_REGS SalStatus;
+
+ SalStatus = EsalGetReverseThunkAddress ();
+
+ *CodeStart = SalStatus.r9;
+ *CodeEnd = SalStatus.r10;
+ *ReverseThunkStart = SalStatus.r11;
+
+}
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ GDT32 *CodeGdt;
+ GDT32 *DataGdt;
+ UINTN CodeStart;
+ UINTN CodeEnd;
+ UINTN ReverseThunkStart;
+ UINT32 Base;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINTN TempData;
+
+ ASSERT (Private);
+
+ IntThunk = Private->IntThunk;
+
+ //
+ // Clear the reserved descriptor
+ //
+ ZeroMem (&(IntThunk->RealModeGdt[0]), sizeof (GDT32));
+
+ //
+ // Setup a descriptor for real-mode code
+ //
+ CodeGdt = &(IntThunk->RealModeGdt[1]);
+
+ //
+ // Fill in the descriptor with our real-mode segment value
+ //
+ CodeGdt->Type = 0xA;
+ //
+ // code/read
+ //
+ CodeGdt->System = 1;
+ CodeGdt->Dpl = 0;
+ CodeGdt->Present = 1;
+ CodeGdt->Software = 0;
+ CodeGdt->Reserved = 0;
+ CodeGdt->DefaultSize = 0;
+ //
+ // 16 bit operands
+ //
+ CodeGdt->Granularity = 0;
+
+ CodeGdt->LimitHi = 0;
+ CodeGdt->LimitLo = 0xffff;
+
+ Base = (*((UINT32 *) &IntThunk->Code));
+ CodeGdt->BaseHi = (Base >> 24) & 0xFF;
+ CodeGdt->BaseMid = (Base >> 16) & 0xFF;
+ CodeGdt->BaseLo = Base & 0xFFFF;
+
+ //
+ // Setup a descriptor for read-mode data
+ //
+ DataGdt = &(IntThunk->RealModeGdt[2]);
+ CopyMem (DataGdt, CodeGdt, sizeof (GDT32));
+
+ DataGdt->Type = 0x2;
+ //
+ // read/write data
+ //
+ DataGdt->BaseHi = 0x0;
+ //
+ // Base = 0
+ //
+ DataGdt->BaseMid = 0x0;
+ //
+ DataGdt->BaseLo = 0x0;
+ //
+ DataGdt->LimitHi = 0x0F;
+ //
+ // Limit = 4Gb
+ //
+ DataGdt->LimitLo = 0xFFFF;
+ //
+ DataGdt->Granularity = 0x1;
+ //
+ //
+ // Compute selector value
+ //
+ IntThunk->RealModeGdtDesc.Limit = (UINT16) (sizeof (IntThunk->RealModeGdt) - 1);
+ CopyMem (&IntThunk->RealModeGdtDesc.Base, (UINT32 *) &IntThunk->RealModeGdt, sizeof (UINT32));
+ //
+ // IntThunk->RealModeGdtDesc.Base = *((UINT32*) &IntThunk->RealModeGdt);
+ //
+ IntThunk->RealModeIdtDesc.Limit = 0xFFFF;
+ IntThunk->RealModeIdtDesc.Base = 0;
+ IntThunk->LowCodeSelector = (UINT32) ((UINTN) CodeGdt - IntThunk->RealModeGdtDesc.Base);
+ IntThunk->LowDataSelector = (UINT32) ((UINTN) DataGdt - IntThunk->RealModeGdtDesc.Base);
+
+ //
+ // Initialize low real-mode code thunk
+ //
+ RealModeTemplate (&CodeStart, &CodeEnd, &ReverseThunkStart, IntThunk);
+
+ TempData = (UINTN) &(IntThunk->Code);
+ IntThunk->LowReverseThunkStart = ((UINT32) TempData + (UINT32) (ReverseThunkStart - CodeStart));
+
+ EsalSetSalDataArea (TempData, (UINTN) IntThunk);
+ CopyMem (IntThunk->Code, (VOID *) CodeStart, CodeEnd - CodeStart);
+
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallSegment = EFI_SEGMENT (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+ IntThunk->EfiToLegacy16InitTable.ReverseThunkCallOffset = EFI_OFFSET (*((UINT32 *) &IntThunk->LowReverseThunkStart));
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN *Address;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+
+ //
+ // Get the current flat GDT, IDT, and SS and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // Stack for reverse thunk flat mode.
+ // It must point to top of stack (end of stack space).
+ //
+ TempData = ((UINTN) IntThunk->RevThunkStack) + LOW_STACK_SIZE;
+ IntThunk->RevFlatStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ TempData = BiosInt * 4;
+ Address = (UINTN *) TempData;
+ IaOffset = 0xFFFF & (*Address);
+ IaSegment = 0xFFFF & ((*Address) >> 16);
+
+ Status = BiosIntCall (
+ BiosInt,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the
+ target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ LOW_MEMORY_THUNK *IntThunk;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ UINTN IaSegment;
+ UINTN IaOffset;
+ UINTN TempData;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ IntThunk = Private->IntThunk;
+ IaSegment = Segment;
+ IaOffset = Offset;
+
+ //
+ // Get the current flat GDT and IDT and store them in Private->IntThunk.
+ //
+ Status = LegacyBiosGetFlatDescs (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+ //
+ // Clear the error flag; thunk code may set it.
+ //
+ Stack16 = (UINT16 *) (IntThunk->Stack + LOW_STACK_SIZE);
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+ //
+ // Copy regs to low memory stack
+ //
+ Stack16 -= sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+ CopyMem (Stack16, Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ //
+ // Provide low stack esp
+ //
+ TempData = ((UINTN) Stack16) - ((UINTN) IntThunk);
+ IntThunk->LowStack = *((UINT32 *) &TempData);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Call the real mode thunk code
+ //
+ Status = BiosIntCall (
+ 0x100,
+ (UINT16) IaSegment,
+ (UINT16) IaOffset,
+ (EFI_IA32_REGISTER_SET *) Stack16,
+ IntThunk,
+ IntThunk->LowStack
+ );
+
+ //
+ // Check for errors with the thunk
+ //
+ switch (Status) {
+ case THUNK_OK:
+ break;
+
+ case THUNK_ERR_A20_UNSUP:
+ case THUNK_ERR_A20_FAILED:
+ default:
+ //
+ // For all errors, set EFLAGS.CF (used by legacy BIOS to indicate error).
+ //
+ Regs->X.Flags.CF = 1;
+ break;
+ }
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Return the resulting registers
+ //
+ CopyMem (Regs, Stack16, sizeof (EFI_IA32_REGISTER_SET));
+ Stack16 += sizeof (EFI_IA32_REGISTER_SET) / sizeof (UINT16);
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ Stack16 += StackSize / sizeof (UINT16);
+ }
+
+ return (BOOLEAN) (Regs->X.Flags.CF != 0);
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c
new file mode 100644
index 0000000000..6ee43ad676
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBbs.c
@@ -0,0 +1,384 @@
+/** @file
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+// Give floppy 3 states
+// FLOPPY_PRESENT_WITH_MEDIA = Floppy controller present and media is inserted
+// FLOPPY_NOT_PRESENT = No floppy controller present
+// FLOPPY_PRESENT_NO_MEDIA = Floppy controller present but no media inserted
+//
+#define FLOPPY_NOT_PRESENT 0
+#define FLOPPY_PRESENT_WITH_MEDIA 1
+#define FLOPPY_PRESENT_NO_MEDIA 2
+
+BBS_TABLE *mBbsTable;
+BOOLEAN mBbsTableDoneFlag = FALSE;
+BOOLEAN IsHaveMediaInFloppy = TRUE;
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+
+ HandleBuffer = NULL;
+ HandleCount = 0;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ //
+ // If don't find any ISA/IO protocol assume no floppy. Need for floppy
+ // free system
+ //
+ if (HandleCount == 0) {
+ return FLOPPY_NOT_PRESENT;
+ }
+
+ ASSERT (HandleBuffer != NULL);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x604)) {
+ continue;
+ }
+ //
+ // Update blockio in case the floppy is inserted in during BdsTimeout
+ //
+ Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ if (BlkIo->Media->MediaPresent) {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_WITH_MEDIA;
+ } else {
+ FreePool (HandleBuffer);
+ return FLOPPY_PRESENT_NO_MEDIA;
+ }
+ }
+
+ FreePool (HandleBuffer);
+
+ return FLOPPY_NOT_PRESENT;
+
+}
+
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINTN BbsIndex;
+ HDD_INFO *HddInfo;
+ UINTN HddIndex;
+ UINTN Index;
+
+ //
+ // First entry is floppy.
+ // Next 2*MAX_IDE_CONTROLLER entries are for onboard IDE.
+ // Next n entries are filled in after each ROM is dispatched.
+ // Entry filled in if follow BBS spec. See LegacyPci.c
+ // Next entries are for non-BBS compliant ROMS. They are filled in by
+ // 16-bit code during Legacy16UpdateBbs invocation. Final BootPriority
+ // occurs after that invocation.
+ //
+ // Floppy
+ // Set default state.
+ //
+ IsHaveMediaInFloppy = HasMediaInFloppy ();
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_WITH_MEDIA) {
+ BbsTable[0].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ } else {
+ if (IsHaveMediaInFloppy == FLOPPY_PRESENT_NO_MEDIA) {
+ BbsTable[0].BootPriority = BBS_LOWEST_PRIORITY;
+ } else {
+ BbsTable[0].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+
+ BbsTable[0].Bus = 0xff;
+ BbsTable[0].Device = 0xff;
+ BbsTable[0].Function = 0xff;
+ BbsTable[0].DeviceType = BBS_FLOPPY;
+ BbsTable[0].Class = 01;
+ BbsTable[0].SubClass = 02;
+ BbsTable[0].StatusFlags.OldPosition = 0;
+ BbsTable[0].StatusFlags.Reserved1 = 0;
+ BbsTable[0].StatusFlags.Enabled = 0;
+ BbsTable[0].StatusFlags.Failed = 0;
+ BbsTable[0].StatusFlags.MediaPresent = 0;
+ BbsTable[0].StatusFlags.Reserved2 = 0;
+
+ //
+ // Onboard HDD - Note Each HDD controller controls 2 drives
+ // Master & Slave
+ //
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+ //
+ // Get IDE Drive Info
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+
+ for (HddIndex = 0; HddIndex < MAX_IDE_CONTROLLER; HddIndex++) {
+
+ BbsIndex = HddIndex * 2 + 1;
+ for (Index = 0; Index < 2; ++Index) {
+
+ BbsTable[BbsIndex + Index].Bus = HddInfo[HddIndex].Bus;
+ BbsTable[BbsIndex + Index].Device = HddInfo[HddIndex].Device;
+ BbsTable[BbsIndex + Index].Function = HddInfo[HddIndex].Function;
+ BbsTable[BbsIndex + Index].Class = 01;
+ BbsTable[BbsIndex + Index].SubClass = 01;
+ BbsTable[BbsIndex + Index].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex + Index].StatusFlags.Reserved2 = 0;
+
+ //
+ // If no controller found or no device found set to ignore
+ // else set to unprioritized and set device type
+ //
+ if (HddInfo[HddIndex].CommandBaseAddress == 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ } else {
+ if (Index == 0) {
+ if ((HddInfo[HddIndex].Status & (HDD_MASTER_IDE | HDD_MASTER_ATAPI_CDROM | HDD_MASTER_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_MASTER_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_MASTER_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ } else {
+ if ((HddInfo[HddIndex].Status & (HDD_SLAVE_IDE | HDD_SLAVE_ATAPI_CDROM | HDD_SLAVE_ATAPI_ZIPDISK)) != 0) {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ if ((HddInfo[HddIndex].Status & HDD_SLAVE_IDE) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ } else if ((HddInfo[HddIndex].Status & HDD_SLAVE_ATAPI_CDROM) != 0) {
+ BbsTable[BbsIndex + Index].DeviceType = BBS_CDROM;
+ } else {
+ //
+ // for ZIPDISK
+ //
+ BbsTable[BbsIndex + Index].DeviceType = BBS_HARDDISK;
+ }
+ } else {
+ BbsTable[BbsIndex + Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ }
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+// HDD_INFO *LocalHddInfo;
+// IN BBS_TABLE *LocalBbsTable;
+ UINTN NumHandles;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN TempData;
+ UINT32 Granularity;
+
+ HandleBuffer = NULL;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+// LocalHddInfo = EfiToLegacy16BootTable->HddInfo;
+// LocalBbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+
+ if (!mBbsTableDoneFlag) {
+ mBbsTable = Private->BbsTablePtr;
+
+ //
+ // Always enable disk controllers so 16-bit CSM code has valid information for all
+ // drives.
+ //
+ //
+ // Get PciRootBridgeIO protocol
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &NumHandles,
+ &HandleBuffer
+ );
+
+ if (NumHandles == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ mBbsTableDoneFlag = TRUE;
+ for (Index = 0; Index < NumHandles; Index++) {
+ //
+ // Connect PciRootBridgeIO protocol handle with FALSE parameter to let
+ // PCI bus driver enumerate all subsequent handles
+ //
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+
+ }
+
+ LegacyBiosBuildBbs (Private, mBbsTable);
+
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ //
+ // Call into Legacy16 code to add to BBS table for non BBS compliant OPROMs.
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16UpdateBbs;
+
+ //
+ // Pass in handoff data
+ //
+ TempData = (UINTN) EfiToLegacy16BootTable;
+ Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINT32) TempData);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xe0000, 0x20000, &Granularity);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ *HddCount = MAX_IDE_CONTROLLER;
+ *HddInfo = EfiToLegacy16BootTable->HddInfo;
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c
new file mode 100644
index 0000000000..c45d5d4c3e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBda.c
@@ -0,0 +1,66 @@
+/** @file
+ This code fills in BDA (0x400) and EBDA (pointed to by 0x4xx)
+ information. There is support for doing initializeation before
+ Legacy16 is loaded and before a legacy boot is attempted.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT8 *Ebda;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ Ebda = (UINT8 *) ((UINTN) 0x9fc00);
+
+ ZeroMem (Bda, 0x100);
+ ZeroMem (Ebda, 0x400);
+ //
+ // 640k-1k for EBDA
+ //
+ Bda->MemSize = 0x27f;
+ Bda->KeyHead = 0x1e;
+ Bda->KeyTail = 0x1e;
+ Bda->FloppyData = 0x00;
+ Bda->FloppyTimeout = 0xff;
+
+ Bda->KeyStart = 0x001E;
+ Bda->KeyEnd = 0x003E;
+ Bda->KeyboardStatus = 0x10;
+ Bda->Ebda = 0x9fc0;
+
+ //
+ // Move LPT time out here and zero out LPT4 since some SCSI OPROMS
+ // use this as scratch pad (LPT4 is Reserved)
+ //
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1400;
+
+ *Ebda = 0x01;
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
new file mode 100644
index 0000000000..dd2e2b9167
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBios.c
@@ -0,0 +1,1154 @@
+/** @file
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
+
+//
+// define maximum number of HDD system supports
+//
+#define MAX_HDD_ENTRIES 0x30
+
+//
+// Module Global:
+// Since this driver will only ever produce one instance of the Private Data
+// protocol you are not required to dynamically allocate the PrivateData.
+//
+LEGACY_BIOS_INSTANCE mPrivateData;
+
+//
+// The SMBIOS table in EfiRuntimeServicesData memory
+//
+VOID *mRuntimeSmbiosEntryPoint = NULL;
+
+//
+// The SMBIOS table in EfiReservedMemoryType memory
+//
+EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint = 0;
+EFI_PHYSICAL_ADDRESS mStructureTableAddress = 0;
+UINTN mStructureTablePages = 0;
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemPage;
+
+ //
+ // Allocate Pages of memory less <= StartPageAddress
+ //
+ MemPage = (EFI_PHYSICAL_ADDRESS) (UINTN) StartPageAddress;
+ Status = gBS->AllocatePages (
+ AllocateType,
+ EfiBootServicesCode,
+ Pages,
+ &MemPage
+ );
+ //
+ // Do not ASSERT on Status error but let caller decide since some cases
+ // memory is already taken but that is ok.
+ //
+ if (!EFI_ERROR (Status)) {
+ *Result = (EFI_PHYSICAL_ADDRESS) (UINTN) MemPage;
+ }
+ //
+ // If reach here the status = EFI_SUCCESS
+ //
+ return Status;
+}
+
+
+/**
+ This function is called when EFI needs to reserve an area in the 0xE0000 or 0xF0000
+ 64 KB blocks.
+
+ Note: inconsistency with the Framework CSM spec. Per the spec, this function may be
+ invoked only once. This limitation is relaxed to allow multiple calls in this implemenation.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_STATUS Status;
+ UINT32 Granularity;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.BX = (UINT16) Region;
+ Regs.X.CX = (UINT16) LegacyMemorySize;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX == 0) {
+ *LegacyMemoryAddress = (VOID *) (UINTN) ((Regs.X.DS << 4) + Regs.X.BX);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_OUT_OF_RESOURCES;
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return Status;
+}
+
+
+/**
+ This function is called when copying data to the region assigned by
+ EFI_LEGACY_BIOS_PROTOCOL.GetLegacyRegion().
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS The data was copied successfully.
+ @retval EFI_ACCESS_DENIED Either the starting or ending address is out of bounds.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ )
+{
+
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT32 Granularity;
+
+ if ((LegacyMemoryAddress < (VOID *)(UINTN)0xE0000 ) ||
+ ((UINTN) LegacyMemoryAddress + LegacyMemorySize > (UINTN) 0x100000)
+ ) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // There is no protection from writes over lapping if this function is
+ // called multiple times.
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+ CopyMem (LegacyMemoryAddress, LegacyMemorySourceAddress, LegacyMemorySize);
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, 0xE0000, 0x20000, &Granularity);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+ UINT8 *PtrEnd;
+ BOOLEAN Done;
+ EFI_COMPATIBILITY16_TABLE *Table;
+ UINT8 CheckSum;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ VOID *LegacyBiosImage;
+ UINTN LegacyBiosImageSize;
+ UINTN E820Size;
+ UINT32 *ClearPtr;
+ BBS_TABLE *BbsTable;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINTN Index;
+ UINT32 TpmPointer;
+ VOID *TpmBinaryImage;
+ UINTN TpmBinaryImageSize;
+ UINTN Location;
+ UINTN Alignment;
+ UINTN TempData;
+ EFI_PHYSICAL_ADDRESS Address;
+ UINT16 OldMask;
+ UINT16 NewMask;
+ UINT32 Granularity;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+
+ Location = 0;
+ Alignment = 0;
+
+ //
+ // we allocate the C/D/E/F segment as RT code so no one will use it any more.
+ //
+ Address = 0xC0000;
+ gDS->GetMemorySpaceDescriptor (Address, &Descriptor);
+ if (Descriptor.GcdMemoryType == EfiGcdMemoryTypeSystemMemory) {
+ //
+ // If it is already reserved, we should be safe, or else we allocate it.
+ //
+ Status = gBS->AllocatePages (
+ AllocateAddress,
+ EfiRuntimeServicesCode,
+ 0x40000/EFI_PAGE_SIZE,
+ &Address
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Bugbug: need to figure out whether C/D/E/F segment should be marked as reserved memory.
+ //
+ DEBUG ((DEBUG_ERROR, "Failed to allocate the C/D/E/F segment Status = %r", Status));
+ }
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"StartLegacy",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinarySystemRom,
+ &LegacyBiosImage,
+ &LegacyBiosImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private->BiosStart = (UINT32) (0x100000 - LegacyBiosImageSize);
+ Private->OptionRom = 0xc0000;
+ Private->LegacyBiosImageSize = (UINT32) LegacyBiosImageSize;
+
+ //
+ // Can only shadow into memory allocated for legacy useage.
+ //
+ ASSERT (Private->BiosStart > Private->OptionRom);
+
+ //
+ // Shadow Legacy BIOS. Turn on memory and copy image
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+
+ ClearPtr = (VOID *) ((UINTN) 0xc0000);
+
+ //
+ // Initialize region from 0xc0000 to start of BIOS to all ffs. This allows unused
+ // regions to be used by EMM386 etc.
+ //
+ SetMem ((VOID *) ClearPtr, (UINTN) (0x40000 - LegacyBiosImageSize), 0xff);
+
+ TempData = Private->BiosStart;
+
+ CopyMem (
+ (VOID *) TempData,
+ LegacyBiosImage,
+ (UINTN) LegacyBiosImageSize
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xc0000, 0x40000, EfiCpuFlushTypeWriteBackInvalidate);
+
+ //
+ // Search for Legacy16 table in Shadowed ROM
+ //
+ Done = FALSE;
+ Table = NULL;
+ for (Ptr = (UINT8 *) TempData; Ptr < (UINT8 *) ((UINTN) 0x100000) && !Done; Ptr += 0x10) {
+ if (*(UINT32 *) Ptr == SIGNATURE_32 ('I', 'F', 'E', '$')) {
+ Table = (EFI_COMPATIBILITY16_TABLE *) Ptr;
+ PtrEnd = Ptr + Table->TableLength;
+ for (CheckSum = 0; Ptr < PtrEnd; Ptr++) {
+ CheckSum = (UINT8) (CheckSum +*Ptr);
+ }
+
+ Done = TRUE;
+ }
+ }
+
+ if (Table == NULL) {
+ DEBUG ((EFI_D_ERROR, "No Legacy16 table found\n"));
+ return EFI_NOT_FOUND;
+ }
+
+ if (!Done) {
+ //
+ // Legacy16 table header checksum error.
+ //
+ DEBUG ((EFI_D_ERROR, "Legacy16 table found with bad talbe header checksum\n"));
+ }
+
+ //
+ // Remember location of the Legacy16 table
+ //
+ Private->Legacy16Table = Table;
+ Private->Legacy16CallSegment = Table->Compatibility16CallSegment;
+ Private->Legacy16CallOffset = Table->Compatibility16CallOffset;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ Private->Legacy16InitPtr = EfiToLegacy16InitTable;
+ Private->Legacy16BootPtr = &Private->IntThunk->EfiToLegacy16BootTable;
+ Private->InternalIrqRoutingTable = NULL;
+ Private->NumberIrqRoutingEntries = 0;
+ Private->BbsTablePtr = NULL;
+ Private->LegacyEfiHddTable = NULL;
+ Private->DiskEnd = 0;
+ Private->Disk4075 = 0;
+ Private->HddTablePtr = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo;
+ Private->NumberHddControllers = MAX_IDE_CONTROLLER;
+ Private->Dump[0] = 'D';
+ Private->Dump[1] = 'U';
+ Private->Dump[2] = 'M';
+ Private->Dump[3] = 'P';
+
+ ZeroMem (
+ Private->Legacy16BootPtr,
+ sizeof (EFI_TO_COMPATIBILITY16_BOOT_TABLE)
+ );
+
+ //
+ // Store away a copy of the EFI System Table
+ //
+ Table->EfiSystemTable = (UINT32) (UINTN) gST;
+
+ //
+ // IPF CSM integration -Bug
+ //
+ // Construct the Legacy16 boot memory map. This sets up number of
+ // E820 entries.
+ //
+ LegacyBiosBuildE820 (Private, &E820Size);
+ //
+ // Initialize BDA and EBDA standard values needed to load Legacy16 code
+ //
+ LegacyBiosInitBda (Private);
+ LegacyBiosInitCmos (Private);
+
+ //
+ // All legacy interrupt should be masked when do initialization work from legacy 16 code.
+ //
+ Private->Legacy8259->GetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+ NewMask = 0xFFFF;
+ Private->Legacy8259->SetMask(Private->Legacy8259, &NewMask, NULL, NULL, NULL);
+
+ //
+ // Call into Legacy16 code to do an INIT
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16InitializeYourself;
+ Regs.X.ES = EFI_SEGMENT (*((UINT32 *) &EfiToLegacy16InitTable));
+ Regs.X.BX = EFI_OFFSET (*((UINT32 *) &EfiToLegacy16InitTable));
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ //
+ // Restore original legacy interrupt mask value
+ //
+ Private->Legacy8259->SetMask(Private->Legacy8259, &OldMask, NULL, NULL, NULL);
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"BackFromInitYourself",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ // Copy E820 table after InitializeYourself is completed
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) E820Size;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Table->E820Length = (UINT32) E820Size;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ TempData = Table->E820Pointer;
+ CopyMem ((VOID *) TempData, Private->E820Table, E820Size);
+ }
+ //
+ // Get PnPInstallationCheck Info.
+ //
+ Private->PnPInstallationCheckSegment = Table->PnPInstallationCheckSegment;
+ Private->PnPInstallationCheckOffset = Table->PnPInstallationCheckOffset;
+
+ //
+ // Check if PCI Express is supported. If yes, Save base address.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformPciExpressBase,
+ NULL,
+ NULL,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+ Private->Legacy16Table->PciExpressBase = (UINT32)Location;
+ Location = 0;
+ }
+ //
+ // Check if TPM is supported. If yes get a region in E0000,F0000 to copy it
+ // into, copy it and update pointer to binary image. This needs to be
+ // done prior to any OPROM for security purposes.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformInfo (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformBinaryTpmBinary,
+ &TpmBinaryImage,
+ &TpmBinaryImageSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ if (!EFI_ERROR (Status)) {
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TpmBinaryImageSize;
+ Regs.X.DX = 1;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Table->Compatibility16CallSegment,
+ Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ TpmPointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "TPM cannot be loaded\n"));
+ } else {
+ CopyMem ((VOID *) (UINTN)TpmPointer, TpmBinaryImage, TpmBinaryImageSize);
+ Table->TpmSegment = Regs.X.DS;
+ Table->TpmOffset = Regs.X.BX;
+
+ }
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->Cpu->FlushDataCache (Private->Cpu, Private->BiosStart, (UINT32) LegacyBiosImageSize, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (Private->LegacyRegion, Private->BiosStart, (UINT32) LegacyBiosImageSize, &Granularity);
+
+ //
+ // Get the BbsTable from LOW_MEMORY_THUNK
+ //
+ BbsTable = (BBS_TABLE *)(UINTN)Private->IntThunk->BbsTable;
+ ZeroMem ((VOID *)BbsTable, sizeof (Private->IntThunk->BbsTable));
+
+ EfiToLegacy16BootTable->BbsTable = (UINT32)(UINTN)BbsTable;
+ Private->BbsTablePtr = (VOID *) BbsTable;
+ //
+ // Skip Floppy and possible onboard IDE drives
+ //
+ EfiToLegacy16BootTable->NumberBbsEntries = 1 + 2 * MAX_IDE_CONTROLLER;
+
+ for (Index = 0; Index < (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE)); Index++) {
+ BbsTable[Index].BootPriority = BBS_IGNORE_ENTRY;
+ }
+ //
+ // Allocate space for Legacy HDD table
+ //
+ LegacyEfiHddTable = (LEGACY_EFI_HDD_TABLE *) AllocateZeroPool ((UINTN) MAX_HDD_ENTRIES * sizeof (LEGACY_EFI_HDD_TABLE));
+ ASSERT (LegacyEfiHddTable);
+
+ Private->LegacyEfiHddTable = LegacyEfiHddTable;
+ Private->LegacyEfiHddTableIndex = 0x00;
+
+ //
+ // start testtest
+ // GetTimerValue (&Ticker);
+ //
+ // gRT->SetVariable (L"EndOfLoadFv",
+ // &gEfiGlobalVariableGuid,
+ // EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ // sizeof (UINT64),
+ // (VOID *)&Ticker
+ // );
+ // end testtest
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+
+ //
+ // EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ // EFI_LEGACY16_TABLE *Legacy16Table;
+ //
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ //
+ // LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ // Legacy16Table = Private->Legacy16Table;
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ // LegacyBiosPlatform->ShadowServiceRoms (LegacyBiosPlatform,
+ // &Private->OptionRom,
+ // Legacy16Table);
+ //
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the PCI BIOS interface version.
+
+ @param Private Driver private data.
+
+ @return The PCI interface version number in Binary Coded Decimal (BCD) format.
+ E.g.: 0x0210 indicates 2.10, 0x0300 indicates 3.00
+
+**/
+UINT16
+GetPciInterfaceVersion (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_IA32_REGISTER_SET Reg;
+ BOOLEAN ThunkFailed;
+ UINT16 PciInterfaceVersion;
+
+ PciInterfaceVersion = 0;
+
+ Reg.X.AX = 0xB101;
+ Reg.E.EDI = 0;
+
+ ThunkFailed = Private->LegacyBios.Int86 (&Private->LegacyBios, 0x1A, &Reg);
+ if (!ThunkFailed) {
+ //
+ // From PCI Firmware 3.0 Specification:
+ // If the CARRY FLAG [CF] is cleared and AH is set to 00h, it is still necessary to examine the
+ // contents of [EDX] for the presence of the string "PCI" + (trailing space) to fully validate the
+ // presence of the PCI function set. [BX] will further indicate the version level, with enough
+ // granularity to allow for incremental changes in the code that don't affect the function interface.
+ // Version numbers are stored as Binary Coded Decimal (BCD) values. For example, Version 2.10
+ // would be returned as a 02h in the [BH] registers and 10h in the [BL] registers.
+ //
+ if ((Reg.X.Flags.CF == 0) && (Reg.H.AH == 0) && (Reg.E.EDX == SIGNATURE_32 ('P', 'C', 'I', ' '))) {
+ PciInterfaceVersion = Reg.X.BX;
+ }
+ }
+ return PciInterfaceVersion;
+}
+
+/**
+ Callback function to calculate SMBIOS table size, and allocate memory for SMBIOS table.
+ SMBIOS table will be copied into EfiReservedMemoryType memory in legacy boot path.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context The pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+InstallSmbiosEventCallback (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;
+
+ //
+ // Get SMBIOS table from EFI configuration table
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiSmbiosTableGuid,
+ &mRuntimeSmbiosEntryPoint
+ );
+ if ((EFI_ERROR (Status)) || (mRuntimeSmbiosEntryPoint == NULL)) {
+ return;
+ }
+
+ EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
+
+ //
+ // Allocate memory for SMBIOS Entry Point Structure.
+ // CSM framework spec requires SMBIOS table below 4GB in EFI_TO_COMPATIBILITY16_BOOT_TABLE.
+ //
+ if (mReserveSmbiosEntryPoint == 0) {
+ //
+ // Entrypoint structure with fixed size is allocated only once.
+ //
+ mReserveSmbiosEntryPoint = SIZE_4GB - 1;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength)),
+ &mReserveSmbiosEntryPoint
+ );
+ if (EFI_ERROR (Status)) {
+ mReserveSmbiosEntryPoint = 0;
+ return;
+ }
+ DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Entry Point Structure\n"));
+ }
+
+ if ((mStructureTableAddress != 0) &&
+ (mStructureTablePages < (UINTN) EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength))) {
+ //
+ // If original buffer is not enough for the new SMBIOS table, free original buffer and re-allocate
+ //
+ gBS->FreePages (mStructureTableAddress, mStructureTablePages);
+ mStructureTableAddress = 0;
+ mStructureTablePages = 0;
+ DEBUG ((EFI_D_INFO, "Original size is not enough. Re-allocate the memory.\n"));
+ }
+
+ if (mStructureTableAddress == 0) {
+ //
+ // Allocate reserved memory below 4GB.
+ // Smbios spec requires the structure table is below 4GB.
+ //
+ mStructureTableAddress = SIZE_4GB - 1;
+ mStructureTablePages = EFI_SIZE_TO_PAGES (EntryPointStructure->TableLength);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ mStructureTablePages,
+ &mStructureTableAddress
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages (
+ mReserveSmbiosEntryPoint,
+ EFI_SIZE_TO_PAGES ((UINTN) (EntryPointStructure->EntryPointLength))
+ );
+ mReserveSmbiosEntryPoint = 0;
+ mStructureTableAddress = 0;
+ mStructureTablePages = 0;
+ return;
+ }
+ DEBUG ((EFI_D_INFO, "Allocate memory for Smbios Structure Table\n"));
+ }
+}
+
+/**
+ Install Driver to produce Legacy BIOS protocol.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Legacy BIOS protocol installed
+ @retval No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstall (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_TO_COMPATIBILITY16_INIT_TABLE *EfiToLegacy16InitTable;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ EFI_PHYSICAL_ADDRESS EbdaReservedBaseAddress;
+ VOID *MemoryPtr;
+ EFI_PHYSICAL_ADDRESS MemoryAddressUnder1MB;
+ UINTN Index;
+ UINT32 *BaseVectorMaster;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ UINT32 *ClearPtr;
+ EFI_PHYSICAL_ADDRESS MemStart;
+ UINT32 IntRedirCode;
+ UINT32 Granularity;
+ BOOLEAN DecodeOn;
+ UINT32 MemorySize;
+ EFI_GCD_MEMORY_SPACE_DESCRIPTOR Descriptor;
+ UINT64 Length;
+ UINT8 *SecureBoot;
+ EFI_EVENT InstallSmbiosEvent;
+
+ //
+ // Load this driver's image to memory
+ //
+ Status = RelocateImageUnder4GIfNeeded (ImageHandle, SystemTable);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // When UEFI Secure Boot is enabled, CSM module will not start any more.
+ //
+ SecureBoot = NULL;
+ GetEfiGlobalVariable2 (EFI_SECURE_BOOT_MODE_NAME, (VOID**)&SecureBoot, NULL);
+ if ((SecureBoot != NULL) && (*SecureBoot == SECURE_BOOT_MODE_ENABLE)) {
+ FreePool (SecureBoot);
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ if (SecureBoot != NULL) {
+ FreePool (SecureBoot);
+ }
+
+ Private = &mPrivateData;
+ ZeroMem (Private, sizeof (LEGACY_BIOS_INSTANCE));
+
+ //
+ // Grab a copy of all the protocols we depend on. Any error would
+ // be a dispatcher bug!.
+ //
+ Status = gBS->LocateProtocol (&gEfiCpuArchProtocolGuid, NULL, (VOID **) &Private->Cpu);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiTimerArchProtocolGuid, NULL, (VOID **) &Private->Timer);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyRegion2ProtocolGuid, NULL, (VOID **) &Private->LegacyRegion);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosPlatformProtocolGuid, NULL, (VOID **) &Private->LegacyBiosPlatform);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacy8259ProtocolGuid, NULL, (VOID **) &Private->Legacy8259);
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->LocateProtocol (&gEfiLegacyInterruptProtocolGuid, NULL, (VOID **) &Private->LegacyInterrupt);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Locate Memory Test Protocol if exists
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &Private->GenericMemoryTest
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make sure all memory from 0-640K is tested
+ //
+ for (StartAddress = 0; StartAddress < 0xa0000; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, 0xa0000 - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+ //
+ // Make sure all memory from 1MB to 16MB is tested and added to memory map
+ //
+ for (StartAddress = BASE_1MB; StartAddress < BASE_16MB; ) {
+ gDS->GetMemorySpaceDescriptor (StartAddress, &Descriptor);
+ if (Descriptor.GcdMemoryType != EfiGcdMemoryTypeReserved) {
+ StartAddress = Descriptor.BaseAddress + Descriptor.Length;
+ continue;
+ }
+ Length = MIN (Descriptor.Length, BASE_16MB - StartAddress);
+ Private->GenericMemoryTest->CompatibleRangeTest (
+ Private->GenericMemoryTest,
+ StartAddress,
+ Length
+ );
+ StartAddress = StartAddress + Length;
+ }
+
+ Private->Signature = LEGACY_BIOS_INSTANCE_SIGNATURE;
+
+ Private->LegacyBios.Int86 = LegacyBiosInt86;
+ Private->LegacyBios.FarCall86 = LegacyBiosFarCall86;
+ Private->LegacyBios.CheckPciRom = LegacyBiosCheckPciRom;
+ Private->LegacyBios.InstallPciRom = LegacyBiosInstallPciRom;
+ Private->LegacyBios.LegacyBoot = LegacyBiosLegacyBoot;
+ Private->LegacyBios.UpdateKeyboardLedStatus = LegacyBiosUpdateKeyboardLedStatus;
+ Private->LegacyBios.GetBbsInfo = LegacyBiosGetBbsInfo;
+ Private->LegacyBios.ShadowAllLegacyOproms = LegacyBiosShadowAllLegacyOproms;
+ Private->LegacyBios.PrepareToBootEfi = LegacyBiosPrepareToBootEfi;
+ Private->LegacyBios.GetLegacyRegion = LegacyBiosGetLegacyRegion;
+ Private->LegacyBios.CopyLegacyRegion = LegacyBiosCopyLegacyRegion;
+ Private->LegacyBios.BootUnconventionalDevice = LegacyBiosBootUnconventionalDevice;
+
+ Private->ImageHandle = ImageHandle;
+
+ //
+ // Enable read attribute of legacy region.
+ //
+ DecodeOn = TRUE;
+ Private->LegacyRegion->Decode (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity,
+ &DecodeOn
+ );
+ //
+ // Set Cachebility for legacy region
+ // BUGBUG: Comments about this legacy region cacheability setting
+ // This setting will make D865GCHProduction CSM Unhappy
+ //
+ if (PcdGetBool (PcdLegacyBiosCacheLegacyRegion)) {
+ gDS->SetMemorySpaceAttributes (
+ 0x0,
+ 0xA0000,
+ EFI_MEMORY_WB
+ );
+ gDS->SetMemorySpaceAttributes (
+ 0xc0000,
+ 0x40000,
+ EFI_MEMORY_WB
+ );
+ }
+
+ gDS->SetMemorySpaceAttributes (
+ 0xA0000,
+ 0x20000,
+ EFI_MEMORY_UC
+ );
+
+ //
+ // Allocate 0 - 4K for real mode interupt vectors and BDA.
+ //
+ AllocateLegacyMemory (
+ AllocateAddress,
+ 0,
+ 1,
+ &MemoryAddress
+ );
+ ASSERT (MemoryAddress == 0x000000000);
+
+ ClearPtr = (VOID *) ((UINTN) 0x0000);
+
+ //
+ // Initialize region from 0x0000 to 4k. This initializes interrupt vector
+ // range.
+ //
+ gBS->SetMem ((VOID *) ClearPtr, 0x400, INITIAL_VALUE_BELOW_1K);
+ ZeroMem ((VOID *) ((UINTN)ClearPtr + 0x400), 0xC00);
+
+ //
+ // Allocate pages for OPROM usage
+ //
+ MemorySize = PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ CONVENTIONAL_MEMORY_TOP - MemorySize,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddress), MemorySize);
+
+ //
+ // Allocate all 32k chunks from 0x60000 ~ 0x88000 for Legacy OPROMs that
+ // don't use PMM but look for zeroed memory. Note that various non-BBS
+ // OpROMs expect different areas to be free
+ //
+ EbdaReservedBaseAddress = MemoryAddress;
+ MemoryAddress = PcdGet32 (PcdOpromReservedMemoryBase);
+ MemorySize = PcdGet32 (PcdOpromReservedMemorySize);
+ //
+ // Check if base address and size for reserved memory are 4KB aligned.
+ //
+ ASSERT ((MemoryAddress & 0xFFF) == 0);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+ //
+ // Check if the reserved memory is below EBDA reserved range.
+ //
+ ASSERT ((MemoryAddress < EbdaReservedBaseAddress) && ((MemoryAddress + MemorySize - 1) < EbdaReservedBaseAddress));
+ for (MemStart = MemoryAddress; MemStart < MemoryAddress + MemorySize; MemStart += 0x1000) {
+ Status = AllocateLegacyMemory (
+ AllocateAddress,
+ MemStart,
+ 1,
+ &StartAddress
+ );
+ if (!EFI_ERROR (Status)) {
+ MemoryPtr = (VOID *) ((UINTN) StartAddress);
+ ZeroMem (MemoryPtr, 0x1000);
+ } else {
+ DEBUG ((EFI_D_ERROR, "WARNING: Allocate legacy memory fail for SCSI card - %x\n", MemStart));
+ }
+ }
+
+ //
+ // Allocate low PMM memory and zero it out
+ //
+ MemorySize = PcdGet32 (PcdLowPmmMemorySize);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddressUnder1MB
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ ZeroMem ((VOID *) ((UINTN) MemoryAddressUnder1MB), MemorySize);
+
+ //
+ // Allocate space for thunker and Init Thunker
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ CONVENTIONAL_MEMORY_TOP,
+ (sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 2,
+ &MemoryAddress
+ );
+ ASSERT_EFI_ERROR (Status);
+ Private->IntThunk = (LOW_MEMORY_THUNK *) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable = &Private->IntThunk->EfiToLegacy16InitTable;
+ EfiToLegacy16InitTable->ThunkStart = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->ThunkSizeInBytes = (UINT32) (sizeof (LOW_MEMORY_THUNK));
+
+ Status = LegacyBiosInitializeThunk (Private);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Init the legacy memory map in memory < 1 MB.
+ //
+ EfiToLegacy16InitTable->BiosLessThan1MB = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemory = (UINT32) MemoryAddressUnder1MB;
+ EfiToLegacy16InitTable->LowPmmMemorySizeInBytes = MemorySize;
+
+ MemorySize = PcdGet32 (PcdHighPmmMemorySize);
+ ASSERT ((MemorySize & 0xFFF) == 0);
+ //
+ // Allocate high PMM Memory under 16 MB
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0x1000000,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddress
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If it fails, allocate high PMM Memory under 4GB
+ //
+ Status = AllocateLegacyMemory (
+ AllocateMaxAddress,
+ 0xFFFFFFFF,
+ EFI_SIZE_TO_PAGES (MemorySize),
+ &MemoryAddress
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ EfiToLegacy16InitTable->HiPmmMemory = (UINT32) (EFI_PHYSICAL_ADDRESS) (UINTN) MemoryAddress;
+ EfiToLegacy16InitTable->HiPmmMemorySizeInBytes = MemorySize;
+ }
+
+ //
+ // ShutdownAPs();
+ //
+ // Start the Legacy BIOS;
+ //
+ Status = ShadowAndStartLegacy16 (Private);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Initialize interrupt redirection code and entries;
+ // IDT Vectors 0x68-0x6f must be redirected to IDT Vectors 0x08-0x0f.
+ //
+ CopyMem (
+ Private->IntThunk->InterruptRedirectionCode,
+ (VOID *) (UINTN) InterruptRedirectionTemplate,
+ sizeof (Private->IntThunk->InterruptRedirectionCode)
+ );
+
+ //
+ // Save Unexpected interrupt vector so can restore it just prior to boot
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ Private->BiosUnexpectedInt = BaseVectorMaster[0];
+ IntRedirCode = (UINT32) (UINTN) Private->IntThunk->InterruptRedirectionCode;
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = (EFI_SEGMENT (IntRedirCode + Index * 4) << 16) | EFI_OFFSET (IntRedirCode + Index * 4);
+ }
+ //
+ // Save EFI value
+ //
+ Private->ThunkSeg = (UINT16) (EFI_SEGMENT (IntRedirCode));
+
+ //
+ // Allocate reserved memory for SMBIOS table used in legacy boot if SMBIOS table exists
+ //
+ InstallSmbiosEventCallback (NULL, NULL);
+
+ //
+ // Create callback function to update the size of reserved memory after LegacyBiosDxe starts
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ InstallSmbiosEventCallback,
+ NULL,
+ &gEfiSmbiosTableGuid,
+ &InstallSmbiosEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Make a new handle and install the protocol
+ //
+ Private->Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &Private->Handle,
+ &gEfiLegacyBiosProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &Private->LegacyBios
+ );
+ Private->Csm16PciInterfaceVersion = GetPciInterfaceVersion (Private);
+
+ DEBUG ((EFI_D_INFO, "CSM16 PCI BIOS Interface Version: %02x.%02x\n",
+ (UINT8) (Private->Csm16PciInterfaceVersion >> 8),
+ (UINT8) Private->Csm16PciInterfaceVersion
+ ));
+ ASSERT (Private->Csm16PciInterfaceVersion != 0);
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
new file mode 100644
index 0000000000..f8cc4f3fc4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
@@ -0,0 +1,150 @@
+## @file
+# Legacy Bios Module to support CSM.
+#
+# This driver installs Legacy Bios Protocol to support CSM module work in EFI system.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBiosDxe
+ MODULE_UNI_FILE = LegacyBiosDxe.uni
+ FILE_GUID = F122A15C-C10B-4d54-8F48-60F4F06DD1AD
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = LegacyBiosInstall
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF
+#
+
+[Sources]
+ LegacyCmos.c
+ LegacyIde.c
+ LegacyBios.c
+ LegacyBda.c
+ LegacyBiosInterface.h
+ LegacyPci.c
+
+[Sources.Ia32]
+ IA32/InterruptTable.S
+ IA32/InterruptTable.asm
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.X64]
+ X64/InterruptTable.asm
+ X64/InterruptTable.S
+ Thunk.c
+ LegacyBootSupport.c
+ LegacyBbs.c
+ LegacySio.c
+
+[Sources.IPF]
+ Ipf/IpfThunk.s
+ Ipf/Thunk.c
+ Ipf/IpfThunk.i
+ Ipf/IpfBootSupport.c
+ Ipf/IpfThunk.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ DevicePathLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ DxeServicesTableLib
+ PcdLib
+ ReportStatusCodeLib
+ PeCoffLib
+ CacheMaintenanceLib
+ DebugAgentLib
+
+[LibraryClasses.IA32]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.X64]
+ IoLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ BaseLib
+
+[LibraryClasses.IPF]
+ IoLib
+ UefiRuntimeServicesTableLib
+
+
+[Guids]
+ gEfiDiskInfoIdeInterfaceGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosBuildIdeData() to assure device is a disk
+ gEfiSmbiosTableGuid ## SOMETIMES_CONSUMES ##SystemTable
+ gEfiLegacyBiosGuid ## SOMETIMES_CONSUMES ##GUID #Used in LegacyBiosInstallVgaRom() to locate handle buffer
+
+[Guids.IA32]
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ##SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ##SystemTable
+
+[Guids.X64]
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ##SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ##SystemTable
+
+
+[Protocols]
+ gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciRootBridgeIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiTimerArchProtocolGuid ## CONSUMES
+ gEfiIsaIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiGenericMemTestProtocolGuid ## CONSUMES
+ gEfiDiskInfoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLegacy8259ProtocolGuid ## CONSUMES
+ gEfiLegacyBiosPlatformProtocolGuid ## CONSUMES
+ gEfiLegacyInterruptProtocolGuid ## CONSUMES
+ gEfiLegacyRegion2ProtocolGuid ## CONSUMES
+ gEfiLegacyBiosProtocolGuid ## PRODUCES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEndOpromShadowAddress ## SOMETIMES_CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLowPmmMemorySize ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHighPmmMemorySize ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize ## CONSUMES
+
+[Depex]
+ gEfiLegacyRegion2ProtocolGuid AND gEfiLegacyInterruptProtocolGuid AND gEfiLegacyBiosPlatformProtocolGuid AND gEfiLegacy8259ProtocolGuid AND gEfiGenericMemTestProtocolGuid AND gEfiCpuArchProtocolGuid AND gEfiTimerArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LegacyBiosDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni
new file mode 100644
index 0000000000..30e995c2dc
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni
new file mode 100644
index 0000000000..c62c69e3cd
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
new file mode 100644
index 0000000000..fcc0190d1e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosInterface.h
@@ -0,0 +1,1541 @@
+/** @file
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _LEGACY_BIOS_INTERFACE_
+#define _LEGACY_BIOS_INTERFACE_
+
+
+#include <FrameworkDxe.h>
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/SmBios.h>
+
+#include <Guid/SmBios.h>
+#include <Guid/Acpi.h>
+#include <Guid/DxeServices.h>
+#include <Guid/LegacyBios.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/ImageAuthentication.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/Timer.h>
+#include <Protocol/IsaIo.h>
+#include <Protocol/LegacyRegion2.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyInterrupt.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/DiskInfo.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/LegacyBiosPlatform.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/Legacy8259.h>
+#include <Protocol/PciRootBridgeIo.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/IoLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/PeCoffLib.h>
+#include <Library/CacheMaintenanceLib.h>
+#include <Library/DebugAgentLib.h>
+
+//
+// BUGBUG: This entry maybe changed to PCD in future and wait for
+// redesign of BDS library
+//
+#define MAX_BBS_ENTRIES 0x100
+
+//
+// Thunk Status Codes
+// (These apply only to errors with the thunk and not to the code that was
+// thunked to.)
+//
+#define THUNK_OK 0x00
+#define THUNK_ERR_A20_UNSUP 0x01
+#define THUNK_ERR_A20_FAILED 0x02
+
+//
+// Vector base definitions
+//
+//
+// 8259 Hardware definitions
+//
+#define LEGACY_MODE_BASE_VECTOR_MASTER 0x08
+#define LEGACY_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// The original PC used INT8-F for master PIC. Since these mapped over
+// processor exceptions TIANO moved the master PIC to INT68-6F.
+//
+// The vector base for slave PIC is set as 0x70 for PC-AT compatibility.
+//
+#define PROTECTED_MODE_BASE_VECTOR_MASTER 0x68
+#define PROTECTED_MODE_BASE_VECTOR_SLAVE 0x70
+
+//
+// When we call CSM16 functions, some CSM16 use es:[offset + 0xabcd] to get data passed from CSM32,
+// offset + 0xabcd could overflow which exceeds 0xFFFF which is invalid in real mode.
+// So this will keep offset as small as possible to avoid offset overflow in real mode.
+//
+#define NORMALIZE_EFI_SEGMENT(_Adr) (UINT16) (((UINTN) (_Adr)) >> 4)
+#define NORMALIZE_EFI_OFFSET(_Adr) (UINT16) (((UINT16) ((UINTN) (_Adr))) & 0xf)
+
+//
+// Trace defines
+//
+//
+#define LEGACY_BDA_TRACE 0x000
+#define LEGACY_BIOS_TRACE 0x040
+#define LEGACY_BOOT_TRACE 0x080
+#define LEGACY_CMOS_TRACE 0x0C0
+#define LEGACY_IDE_TRACE 0x100
+#define LEGACY_MP_TRACE 0x140
+#define LEGACY_PCI_TRACE 0x180
+#define LEGACY_SIO_TRACE 0x1C0
+
+#define LEGACY_PCI_TRACE_000 LEGACY_PCI_TRACE + 0x00
+#define LEGACY_PCI_TRACE_001 LEGACY_PCI_TRACE + 0x01
+#define LEGACY_PCI_TRACE_002 LEGACY_PCI_TRACE + 0x02
+#define LEGACY_PCI_TRACE_003 LEGACY_PCI_TRACE + 0x03
+#define LEGACY_PCI_TRACE_004 LEGACY_PCI_TRACE + 0x04
+#define LEGACY_PCI_TRACE_005 LEGACY_PCI_TRACE + 0x05
+#define LEGACY_PCI_TRACE_006 LEGACY_PCI_TRACE + 0x06
+#define LEGACY_PCI_TRACE_007 LEGACY_PCI_TRACE + 0x07
+#define LEGACY_PCI_TRACE_008 LEGACY_PCI_TRACE + 0x08
+#define LEGACY_PCI_TRACE_009 LEGACY_PCI_TRACE + 0x09
+#define LEGACY_PCI_TRACE_00A LEGACY_PCI_TRACE + 0x0A
+#define LEGACY_PCI_TRACE_00B LEGACY_PCI_TRACE + 0x0B
+#define LEGACY_PCI_TRACE_00C LEGACY_PCI_TRACE + 0x0C
+#define LEGACY_PCI_TRACE_00D LEGACY_PCI_TRACE + 0x0D
+#define LEGACY_PCI_TRACE_00E LEGACY_PCI_TRACE + 0x0E
+#define LEGACY_PCI_TRACE_00F LEGACY_PCI_TRACE + 0x0F
+
+#define BDA_VIDEO_MODE 0x49
+
+#define IDE_PI_REGISTER_PNE BIT0
+#define IDE_PI_REGISTER_SNE BIT2
+
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT32 ShadowAddress;
+ UINT32 ShadowedSize;
+ UINT8 DiskStart;
+ UINT8 DiskEnd;
+} ROM_INSTANCE_ENTRY;
+
+//
+// Values for RealModeGdt
+//
+#if defined (MDE_CPU_IA32)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_X64)
+
+#define NUM_REAL_GDT_ENTRIES 8
+#define CONVENTIONAL_MEMORY_TOP 0xA0000 // 640 KB
+#define INITIAL_VALUE_BELOW_1K 0x0
+
+#elif defined (MDE_CPU_IPF)
+
+#define NUM_REAL_GDT_ENTRIES 3
+#define CONVENTIONAL_MEMORY_TOP 0x80000 // 512 KB
+#define INITIAL_VALUE_BELOW_1K 0xff
+
+#endif
+
+#pragma pack(1)
+
+//
+// Define what a processor GDT looks like
+//
+typedef struct {
+ UINT32 LimitLo : 16;
+ UINT32 BaseLo : 16;
+ UINT32 BaseMid : 8;
+ UINT32 Type : 4;
+ UINT32 System : 1;
+ UINT32 Dpl : 2;
+ UINT32 Present : 1;
+ UINT32 LimitHi : 4;
+ UINT32 Software : 1;
+ UINT32 Reserved : 1;
+ UINT32 DefaultSize : 1;
+ UINT32 Granularity : 1;
+ UINT32 BaseHi : 8;
+} GDT32;
+
+typedef struct {
+ UINT16 LimitLow;
+ UINT16 BaseLow;
+ UINT8 BaseMid;
+ UINT8 Attribute;
+ UINT8 LimitHi;
+ UINT8 BaseHi;
+} GDT64;
+
+//
+// Define what a processor descriptor looks like
+// This data structure must be kept in sync with ASM STRUCT in Thunk.inc
+//
+typedef struct {
+ UINT16 Limit;
+ UINT64 Base;
+} DESCRIPTOR64;
+
+typedef struct {
+ UINT16 Limit;
+ UINT32 Base;
+} DESCRIPTOR32;
+
+//
+// Low stub lay out
+//
+#define LOW_STACK_SIZE (8 * 1024) // 8k?
+#define EFI_MAX_E820_ENTRY 100
+#define FIRST_INSTANCE 1
+#define NOT_FIRST_INSTANCE 0
+
+#if defined (MDE_CPU_IA32)
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_X64)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR64 X64GdtDesc; // Protected mode GDT
+ DESCRIPTOR64 X64IdtDesc; // Protected mode IDT
+ UINTN X64Ss;
+ UINTN X64Esp;
+
+ UINTN RealStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT64 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ UINT64 PageMapLevel4;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#elif defined (MDE_CPU_IPF)
+
+typedef struct {
+ //
+ // Space for the code
+ // The address of Code is also the beginning of the relocated Thunk code
+ //
+ CHAR8 Code[4096]; // ?
+ //
+ // The address of the Reverse Thunk code
+ // Note that this member CONTAINS the address of the relocated reverse thunk
+ // code unlike the member variable 'Code', which IS the address of the Thunk
+ // code.
+ //
+ UINT32 LowReverseThunkStart;
+
+ //
+ // Data for the code (cs releative)
+ //
+ DESCRIPTOR32 GdtDesc; // Protected mode GDT
+ DESCRIPTOR32 IdtDesc; // Protected mode IDT
+ UINT32 FlatSs;
+ UINT32 FlatEsp;
+
+ UINT32 LowCodeSelector; // Low code selector in GDT
+ UINT32 LowDataSelector; // Low data selector in GDT
+ UINT32 LowStack;
+ DESCRIPTOR32 RealModeIdtDesc;
+
+ //
+ // real-mode GDT (temporary GDT with two real mode segment descriptors)
+ //
+ GDT32 RealModeGdt[NUM_REAL_GDT_ENTRIES];
+ DESCRIPTOR32 RealModeGdtDesc;
+
+ //
+ // Members specifically for the reverse thunk
+ // The RevReal* members are used to store the current state of real mode
+ // before performing the reverse thunk. The RevFlat* members must be set
+ // before calling the reverse thunk assembly code.
+ //
+ UINT16 RevRealDs;
+ UINT16 RevRealSs;
+ UINT32 RevRealEsp;
+ DESCRIPTOR32 RevRealIdtDesc;
+ UINT16 RevFlatDataSelector; // Flat data selector in GDT
+ UINT32 RevFlatStack;
+
+ //
+ // A low memory stack
+ //
+ CHAR8 Stack[LOW_STACK_SIZE];
+
+ //
+ // Stack for flat mode after reverse thunk
+ // @bug - This may no longer be necessary if the reverse thunk interface
+ // is changed to have the flat stack in a different location.
+ //
+ CHAR8 RevThunkStack[LOW_STACK_SIZE];
+
+ //
+ // Legacy16 Init memory map info
+ //
+ EFI_TO_COMPATIBILITY16_INIT_TABLE EfiToLegacy16InitTable;
+
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE EfiToLegacy16BootTable;
+
+ CHAR8 InterruptRedirectionCode[32];
+ EFI_LEGACY_INSTALL_PCI_HANDLER PciHandler;
+ EFI_DISPATCH_OPROM_TABLE DispatchOpromTable;
+ BBS_TABLE BbsTable[MAX_BBS_ENTRIES];
+} LOW_MEMORY_THUNK;
+
+#endif
+
+//
+// PnP Expansion Header
+//
+typedef struct {
+ UINT32 PnpSignature;
+ UINT8 Revision;
+ UINT8 Length;
+ UINT16 NextHeader;
+ UINT8 Reserved1;
+ UINT8 Checksum;
+ UINT32 DeviceId;
+ UINT16 MfgPointer;
+ UINT16 ProductNamePointer;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 DeviceIndicators;
+ UINT16 Bcv;
+ UINT16 DisconnectVector;
+ UINT16 Bev;
+ UINT16 Reserved2;
+ UINT16 StaticResourceVector;
+} LEGACY_PNP_EXPANSION_HEADER;
+
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT16 Vid;
+ UINT16 Did;
+ UINT16 SysSid;
+ UINT16 SVid;
+ UINT8 Class;
+ UINT8 SubClass;
+ UINT8 Interface;
+ UINT8 Reserved;
+ UINTN RomStart;
+ UINTN ManufacturerString;
+ UINTN ProductNameString;
+} LEGACY_ROM_AND_BBS_TABLE;
+
+//
+// Structure how EFI has mapped a devices HDD drive numbers.
+// Boot to EFI aware OS or shell requires this mapping when
+// 16-bit CSM assigns drive numbers.
+// This mapping is ignored booting to a legacy OS.
+//
+typedef struct {
+ UINT8 PciSegment;
+ UINT8 PciBus;
+ UINT8 PciDevice;
+ UINT8 PciFunction;
+ UINT8 StartDriveNumber;
+ UINT8 EndDriveNumber;
+} LEGACY_EFI_HDD_TABLE;
+
+//
+// This data is passed to Leacy16Boot
+//
+typedef enum {
+ EfiAcpiAddressRangeMemory = 1,
+ EfiAcpiAddressRangeReserved = 2,
+ EfiAcpiAddressRangeACPI = 3,
+ EfiAcpiAddressRangeNVS = 4,
+ EfiAddressRangePersistentMemory = 7
+} EFI_ACPI_MEMORY_TYPE;
+
+typedef struct {
+ UINT64 BaseAddr;
+ UINT64 Length;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY64;
+
+typedef struct {
+ UINT32 BassAddrLow;
+ UINT32 BaseAddrHigh;
+ UINT32 LengthLow;
+ UINT32 LengthHigh;
+ EFI_ACPI_MEMORY_TYPE Type;
+} EFI_E820_ENTRY;
+
+#pragma pack()
+
+extern BBS_TABLE *mBbsTable;
+
+extern EFI_GENERIC_MEMORY_TEST_PROTOCOL *gGenMemoryTest;
+
+#define PORT_70 0x70
+#define PORT_71 0x71
+
+#define CMOS_0A 0x0a ///< Status register A
+#define CMOS_0D 0x0d ///< Status register D
+#define CMOS_0E 0x0e ///< Diagnostic Status
+#define CMOS_0F 0x0f ///< Shutdown status
+#define CMOS_10 0x10 ///< Floppy type
+#define CMOS_12 0x12 ///< IDE type
+#define CMOS_14 0x14 ///< Same as BDA 40:10
+#define CMOS_15 0x15 ///< Low byte of base memory in 1k increments
+#define CMOS_16 0x16 ///< High byte of base memory in 1k increments
+#define CMOS_17 0x17 ///< Low byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_18 0x18 ///< High byte of 1MB+ memory in 1k increments - max 15 MB
+#define CMOS_19 0x19 ///< C: extended drive type
+#define CMOS_1A 0x1a ///< D: extended drive type
+#define CMOS_2E 0x2e ///< Most significient byte of standard checksum
+#define CMOS_2F 0x2f ///< Least significient byte of standard checksum
+#define CMOS_30 0x30 ///< CMOS 0x17
+#define CMOS_31 0x31 ///< CMOS 0x18
+#define CMOS_32 0x32 ///< Century byte
+
+//
+// 8254 Timer registers
+//
+#define TIMER0_COUNT_PORT 0x40
+#define TIMER1_COUNT_PORT 0x41
+#define TIMER2_COUNT_PORT 0x42
+#define TIMER_CONTROL_PORT 0x43
+
+//
+// Timer 0, Read/Write LSB then MSB, Square wave output, binary count use.
+//
+#define TIMER0_CONTROL_WORD 0x36
+
+#define LEGACY_BIOS_INSTANCE_SIGNATURE SIGNATURE_32 ('L', 'B', 'I', 'T')
+typedef struct {
+ UINTN Signature;
+
+ EFI_HANDLE Handle;
+ EFI_LEGACY_BIOS_PROTOCOL LegacyBios;
+
+ EFI_HANDLE ImageHandle;
+
+ //
+ // CPU Architectural Protocol
+ //
+ EFI_CPU_ARCH_PROTOCOL *Cpu;
+
+ //
+ // Timer Architectural Protocol
+ //
+ EFI_TIMER_ARCH_PROTOCOL *Timer;
+ BOOLEAN TimerUses8254;
+
+ //
+ // Protocol to Lock and Unlock 0xc0000 - 0xfffff
+ //
+ EFI_LEGACY_REGION2_PROTOCOL *LegacyRegion;
+
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+
+ //
+ // Interrupt control for thunk and PCI IRQ
+ //
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+
+ //
+ // PCI Interrupt PIRQ control
+ //
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+
+ //
+ // Generic Memory Test
+ //
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenericMemoryTest;
+
+ //
+ // TRUE if PCI Interupt Line registers have been programmed.
+ //
+ BOOLEAN PciInterruptLine;
+
+ //
+ // Code space below 1MB needed by thunker to transition to real mode.
+ // Contains stack and real mode code fragments
+ //
+ LOW_MEMORY_THUNK *IntThunk;
+
+ //
+ // Starting shadow address of the Legacy BIOS
+ //
+ UINT32 BiosStart;
+ UINT32 LegacyBiosImageSize;
+
+ //
+ // Start of variables used by CsmItp.mac ITP macro file and/os LegacyBios
+ //
+ UINT8 Dump[4];
+
+ //
+ // $EFI Legacy16 code entry info in memory < 1 MB;
+ //
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ VOID *Legacy16InitPtr;
+ VOID *Legacy16BootPtr;
+ VOID *InternalIrqRoutingTable;
+ UINT32 NumberIrqRoutingEntries;
+ VOID *BbsTablePtr;
+ VOID *HddTablePtr;
+ UINT32 NumberHddControllers;
+
+ //
+ // Cached copy of Legacy16 entry point
+ //
+ UINT16 Legacy16CallSegment;
+ UINT16 Legacy16CallOffset;
+
+ //
+ // Returned from $EFI and passed in to OPROMS
+ //
+ UINT16 PnPInstallationCheckSegment;
+ UINT16 PnPInstallationCheckOffset;
+
+ //
+ // E820 table
+ //
+ EFI_E820_ENTRY E820Table[EFI_MAX_E820_ENTRY];
+ UINT32 NumberE820Entries;
+
+ //
+ // True if legacy VGA INT 10h handler installed
+ //
+ BOOLEAN VgaInstalled;
+
+ //
+ // Number of IDE drives
+ //
+ UINT8 IdeDriveCount;
+
+ //
+ // Current Free Option ROM space. An option ROM must NOT go past
+ // BiosStart.
+ //
+ UINT32 OptionRom;
+
+ //
+ // Save Legacy16 unexpected interrupt vector. Reprogram INT 68-6F from
+ // EFI values to legacy value just before boot.
+ //
+ UINT32 BiosUnexpectedInt;
+ UINT32 ThunkSavedInt[8];
+ UINT16 ThunkSeg;
+ LEGACY_EFI_HDD_TABLE *LegacyEfiHddTable;
+ UINT16 LegacyEfiHddTableIndex;
+ UINT8 DiskEnd;
+ UINT8 Disk4075;
+ UINT16 TraceIndex;
+ UINT16 Trace[0x200];
+
+ //
+ // Indicate that whether GenericLegacyBoot is entered or not
+ //
+ BOOLEAN LegacyBootEntered;
+
+ //
+ // CSM16 PCI Interface Version
+ //
+ UINT16 Csm16PciInterfaceVersion;
+
+} LEGACY_BIOS_INSTANCE;
+
+
+#pragma pack(1)
+
+/*
+ 40:00-01 Com1
+ 40:02-03 Com2
+ 40:04-05 Com3
+ 40:06-07 Com4
+ 40:08-09 Lpt1
+ 40:0A-0B Lpt2
+ 40:0C-0D Lpt3
+ 40:0E-0E Ebda segment
+ 40:10-11 MachineConfig
+ 40:12 Bda12 - skip
+ 40:13-14 MemSize below 1MB
+ 40:15-16 Bda15_16 - skip
+ 40:17 Keyboard Shift status
+ 40:18-19 Bda18_19 - skip
+ 40:1A-1B Key buffer head
+ 40:1C-1D Key buffer tail
+ 40:1E-3D Bda1E_3D- key buffer -skip
+ 40:3E-3F FloppyData 3E = Calibration status 3F = Motor status
+ 40:40 FloppyTimeout
+ 40:41-74 Bda41_74 - skip
+ 40:75 Number of HDD drives
+ 40:76-77 Bda76_77 - skip
+ 40:78-79 78 = Lpt1 timeout, 79 = Lpt2 timeout
+ 40:7A-7B 7A = Lpt3 timeout, 7B = Lpt4 timeout
+ 40:7C-7D 7C = Com1 timeout, 7D = Com2 timeout
+ 40:7E-7F 7E = Com3 timeout, 7F = Com4 timeout
+ 40:80-81 Pointer to start of key buffer
+ 40:82-83 Pointer to end of key buffer
+ 40:84-87 Bda84_87 - skip
+ 40:88 HDD Data Xmit rate
+ 40:89-8f skip
+ 40:90 Floppy data rate
+ 40:91-95 skip
+ 40:96 Keyboard Status
+ 40:97 LED Status
+ 40:98-101 skip
+*/
+typedef struct {
+ UINT16 Com1;
+ UINT16 Com2;
+ UINT16 Com3;
+ UINT16 Com4;
+ UINT16 Lpt1;
+ UINT16 Lpt2;
+ UINT16 Lpt3;
+ UINT16 Ebda;
+ UINT16 MachineConfig;
+ UINT8 Bda12;
+ UINT16 MemSize;
+ UINT8 Bda15_16[0x02];
+ UINT8 ShiftStatus;
+ UINT8 Bda18_19[0x02];
+ UINT16 KeyHead;
+ UINT16 KeyTail;
+ UINT16 Bda1E_3D[0x10];
+ UINT16 FloppyData;
+ UINT8 FloppyTimeout;
+ UINT8 Bda41_74[0x34];
+ UINT8 NumberOfDrives;
+ UINT8 Bda76_77[0x02];
+ UINT16 Lpt1_2Timeout;
+ UINT16 Lpt3_4Timeout;
+ UINT16 Com1_2Timeout;
+ UINT16 Com3_4Timeout;
+ UINT16 KeyStart;
+ UINT16 KeyEnd;
+ UINT8 Bda84_87[0x4];
+ UINT8 DataXmit;
+ UINT8 Bda89_8F[0x07];
+ UINT8 FloppyXRate;
+ UINT8 Bda91_95[0x05];
+ UINT8 KeyboardStatus;
+ UINT8 LedStatus;
+} BDA_STRUC;
+#pragma pack()
+
+#define LEGACY_BIOS_INSTANCE_FROM_THIS(this) CR (this, LEGACY_BIOS_INSTANCE, LegacyBios, LEGACY_BIOS_INSTANCE_SIGNATURE)
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ );
+
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ );
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ To boot from an unconventional device like parties and/or execute
+ HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data.
+ The caller must provide a pointer to the specific
+ Service Area and not the start all Service Areas.
+ EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ );
+
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ );
+
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ );
+
+
+/**
+ Get all BBS info
+
+ @param This Protocol instance pointer.
+ @param HddCount Number of HDD_INFO structures
+ @param HddInfo Onboard IDE controller information
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Tables returned
+ @retval EFI_NOT_FOUND resource not found
+ @retval EFI_DEVICE_ERROR can not get BBS table
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetBbsInfo (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *HddCount,
+ OUT HDD_INFO **HddInfo,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ );
+
+
+/**
+ Shadow all legacy16 OPROMs that haven't been shadowed.
+ Warning: Use this with caution. This routine disconnects all EFI
+ drivers. If used externally then caller must re-connect EFI
+ drivers.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS OPROMs shadowed
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosShadowAllLegacyOproms (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ );
+
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ );
+
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitBda (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ );
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ );
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+
+/**
+ Contains the code that is copied into low memory (below 640K).
+ This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+ This template must be copied into low memory, and the IDT entries
+ 0x68-0x6F must be point to the low memory copy of this code. Each
+ entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+ computed.
+
+**/
+VOID
+InterruptRedirectionTemplate (
+ VOID
+ );
+
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ );
+
+/**
+ This function is to put all AP in halt state.
+
+ @param Private Legacy BIOS Instance data
+
+**/
+VOID
+ShutdownAPs (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Worker function for LegacyBiosGetFlatDescs, retrieving content of
+ specific registers.
+
+ @param IntThunk Pointer to IntThunk of Legacy BIOS context.
+
+**/
+VOID
+GetRegisters (
+ LOW_MEMORY_THUNK *IntThunk
+ );
+
+/**
+ Routine for calling real thunk code.
+
+ @param RealCode The address of thunk code.
+ @param BiosInt The Bios interrupt vector number.
+ @param CallAddress The address of 16-bit mode call.
+
+ @return Status returned by real thunk code
+
+**/
+UINTN
+CallRealThunkCode (
+ UINT8 *RealCode,
+ UINT8 BiosInt,
+ UINT32 CallAddress
+ );
+
+/**
+ Routine for generating soft interrupt.
+
+ @param Vector The interrupt vector number.
+
+**/
+VOID
+GenerateSoftInit (
+ UINT8 Vector
+ );
+
+/**
+ Do an AllocatePages () of type AllocateMaxAddress for EfiBootServicesCode
+ memory.
+
+ @param AllocateType Allocated Legacy Memory Type
+ @param StartPageAddress Start address of range
+ @param Pages Number of pages to allocate
+ @param Result Result of allocation
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+AllocateLegacyMemory (
+ IN EFI_ALLOCATE_TYPE AllocateType,
+ IN EFI_PHYSICAL_ADDRESS StartPageAddress,
+ IN UINTN Pages,
+ OUT EFI_PHYSICAL_ADDRESS *Result
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of required region
+ @param Region Region to use. 00 = Either 0xE0000 or 0xF0000
+ block Bit0 = 1 0xF0000 block Bit1 = 1 0xE0000
+ block
+ @param Alignment Address alignment. Bit mapped. First non-zero
+ bit from right is alignment.
+ @param LegacyMemoryAddress Region Assigned
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Procedure previously invoked
+ @retval Other Region not assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosGetLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN UINTN Region,
+ IN UINTN Alignment,
+ OUT VOID **LegacyMemoryAddress
+ );
+
+/**
+ Get a region from the LegacyBios for Tiano usage. Can only be invoked once.
+
+ @param This Protocol instance pointer.
+ @param LegacyMemorySize Size of data to copy
+ @param LegacyMemoryAddress Legacy Region destination address Note: must
+ be in region assigned by
+ LegacyBiosGetLegacyRegion
+ @param LegacyMemorySourceAddress Source of data
+
+ @retval EFI_SUCCESS Region assigned
+ @retval EFI_ACCESS_DENIED Destination outside assigned region
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCopyLegacyRegion (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINTN LegacyMemorySize,
+ IN VOID *LegacyMemoryAddress,
+ IN VOID *LegacyMemorySourceAddress
+ );
+
+/**
+ Find Legacy16 BIOS image in the FLASH device and shadow it into memory. Find
+ the $EFI table in the shadow area. Thunk into the Legacy16 code after it had
+ been shadowed.
+
+ @param Private Legacy BIOS context data
+
+ @retval EFI_SUCCESS Legacy16 code loaded
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+ShadowAndStartLegacy16 (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+/**
+ Checks the state of the floppy and if media is inserted.
+
+ This routine checks the state of the floppy and if media is inserted.
+ There are 3 cases:
+ No floppy present - Set BBS entry to ignore
+ Floppy present & no media - Set BBS entry to lowest priority. We cannot
+ set it to ignore since 16-bit CSM will
+ indicate no floppy and thus drive A: is
+ unusable. CSM-16 will not try floppy since
+ lowest priority and thus not incur boot
+ time penality.
+ Floppy present & media - Set BBS entry to some priority.
+
+ @return State of floppy media
+
+**/
+UINT8
+HasMediaInFloppy (
+ VOID
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ );
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Complete build of BBS TABLE.
+
+ @param Private Legacy BIOS Instance data
+ @param BbsTable BBS Table passed to 16-bit code
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+LegacyBiosBuildBbs (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BBS_TABLE *BbsTable
+ );
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ );
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ );
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ );
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ );
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ );
+
+/**
+ Load a legacy PC-AT OpROM for VGA controller.
+
+ @param Private Driver private data.
+
+ @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
+ @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
+ driver cannot be successfully disconnected, or VGA
+ thunk driver cannot be successfully connected.
+
+**/
+EFI_STATUS
+LegacyBiosInstallVgaRom (
+ IN LEGACY_BIOS_INSTANCE *Private
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
new file mode 100644
index 0000000000..52bcae2d13
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBootSupport.c
@@ -0,0 +1,2165 @@
+/** @file
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci.h>
+
+#define BOOT_LEGACY_OS 0
+#define BOOT_EFI_OS 1
+#define BOOT_UNCONVENTIONAL_DEVICE 2
+
+UINT32 mLoadOptionsSize = 0;
+UINTN mBootMode = BOOT_LEGACY_OS;
+VOID *mLoadOptions = NULL;
+BBS_BBS_DEVICE_PATH *mBbsDevicePathPtr = NULL;
+BBS_BBS_DEVICE_PATH mBbsDevicePathNode;
+UDC_ATTRIBUTES mAttributes = { 0, 0, 0, 0 };
+UINTN mBbsEntry = 0;
+VOID *mBeerData = NULL;
+VOID *mServiceAreaData = NULL;
+UINT64 mLowWater = 0xffffffffffffffffULL;
+
+extern BBS_TABLE *mBbsTable;
+
+extern VOID *mRuntimeSmbiosEntryPoint;
+extern EFI_PHYSICAL_ADDRESS mReserveSmbiosEntryPoint;
+extern EFI_PHYSICAL_ADDRESS mStructureTableAddress;
+
+/**
+ Print the BBS Table.
+
+ @param BbsTable The BBS table.
+
+
+**/
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *BbsTable
+ )
+{
+ UINT16 Index;
+ UINT16 SubIndex;
+ CHAR8 *String;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs mfgs:mfgo dess:deso\n"));
+ DEBUG ((EFI_D_INFO, "=================================================================\n"));
+ for (Index = 0; Index < MAX_BBS_ENTRIES; Index++) {
+ //
+ // Filter
+ //
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ DEBUG ((
+ EFI_D_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x",
+ (UINTN) Index,
+ (UINTN) BbsTable[Index].BootPriority,
+ (UINTN) BbsTable[Index].Bus,
+ (UINTN) BbsTable[Index].Device,
+ (UINTN) BbsTable[Index].Function,
+ (UINTN) BbsTable[Index].Class,
+ (UINTN) BbsTable[Index].SubClass,
+ (UINTN) BbsTable[Index].DeviceType,
+ (UINTN) * (UINT16 *) &BbsTable[Index].StatusFlags
+ ));
+ DEBUG ((
+ EFI_D_INFO,
+ " %04x:%04x %04x:%04x %04x:%04x",
+ (UINTN) BbsTable[Index].BootHandlerSegment,
+ (UINTN) BbsTable[Index].BootHandlerOffset,
+ (UINTN) BbsTable[Index].MfgStringSegment,
+ (UINTN) BbsTable[Index].MfgStringOffset,
+ (UINTN) BbsTable[Index].DescStringSegment,
+ (UINTN) BbsTable[Index].DescStringOffset
+ ));
+
+ //
+ // Print DescString
+ //
+ String = (CHAR8 *)(UINTN)((BbsTable[Index].DescStringSegment << 4) + BbsTable[Index].DescStringOffset);
+ if (String != NULL) {
+ DEBUG ((EFI_D_INFO," ("));
+ for (SubIndex = 0; String[SubIndex] != 0; SubIndex++) {
+ DEBUG ((EFI_D_INFO, "%c", String[SubIndex]));
+ }
+ DEBUG ((EFI_D_INFO,")"));
+ }
+ DEBUG ((EFI_D_INFO,"\n"));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Print the BBS Table.
+
+ @param HddInfo The HddInfo table.
+
+
+**/
+VOID
+PrintHddInfo (
+ IN HDD_INFO *HddInfo
+ )
+{
+ UINTN Index;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ DEBUG ((EFI_D_INFO, "Index - %04x\n", Index));
+ DEBUG ((EFI_D_INFO, " Status - %04x\n", (UINTN)HddInfo[Index].Status));
+ DEBUG ((EFI_D_INFO, " B/D/F - %02x/%02x/%02x\n", (UINTN)HddInfo[Index].Bus, (UINTN)HddInfo[Index].Device, (UINTN)HddInfo[Index].Function));
+ DEBUG ((EFI_D_INFO, " Command - %04x\n", HddInfo[Index].CommandBaseAddress));
+ DEBUG ((EFI_D_INFO, " Control - %04x\n", HddInfo[Index].ControlBaseAddress));
+ DEBUG ((EFI_D_INFO, " BusMaster - %04x\n", HddInfo[Index].BusMasterAddress));
+ DEBUG ((EFI_D_INFO, " HddIrq - %02x\n", HddInfo[Index].HddIrq));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[0].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ DEBUG ((EFI_D_INFO, " IdentifyDrive[1].Raw[0] - %x\n", HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ return ;
+}
+
+/**
+ Print the PCI Interrupt Line and Interrupt Pin registers.
+**/
+VOID
+PrintPciInterruptRegister (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_HANDLE *Handles;
+ UINTN HandleNum;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Interrupt[2];
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleNum,
+ &Handles
+ );
+
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+
+ DEBUG ((EFI_D_INFO, "\n"));
+ DEBUG ((EFI_D_INFO, " bb/dd/ff interrupt line interrupt pin\n"));
+ DEBUG ((EFI_D_INFO, "======================================\n"));
+ for (Index = 0; Index < HandleNum; Index++) {
+ Status = gBS->HandleProtocol (Handles[Index], &gEfiPciIoProtocolGuid, (VOID **) &PciIo);
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ PCI_INT_LINE_OFFSET,
+ 2,
+ Interrupt
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ Status = PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_INFO, " %02x/%02x/%02x 0x%02x 0x%02x\n",
+ Bus, Device, Function, Interrupt[0], Interrupt[1]));
+ }
+ }
+ DEBUG ((EFI_D_INFO, "\n"));
+
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ );
+
+/**
+ Update SIO data.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+UpdateSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index1;
+ UINT8 LegacyInterrupts[16];
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ EFI_LEGACY_IRQ_PRIORITY_TABLE_ENTRY *IrqPriorityTable;
+ UINTN NumberPriorityEntries;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ UINT8 HddIrq;
+ UINT16 LegacyInt;
+ UINT16 LegMask;
+ UINT32 Register;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+
+ LegacyInt = 0;
+ HandleBuffer = NULL;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ LegacyBiosBuildSioData (Private);
+ SetMem (LegacyInterrupts, sizeof (LegacyInterrupts), 0);
+
+ //
+ // Create list of legacy interrupts.
+ //
+ for (Index = 0; Index < 4; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Serial[Index].Irq;
+ }
+
+ for (Index = 4; Index < 7; Index++) {
+ LegacyInterrupts[Index] = EfiToLegacy16BootTable->SioData.Parallel[Index - 4].Irq;
+ }
+
+ LegacyInterrupts[7] = EfiToLegacy16BootTable->SioData.Floppy.Irq;
+
+ //
+ // Get Legacy Hdd IRQs. If native mode treat as PCI
+ //
+ for (Index = 0; Index < 2; Index++) {
+ HddIrq = EfiToLegacy16BootTable->HddInfo[Index].HddIrq;
+ if ((HddIrq != 0) && ((HddIrq == 15) || (HddIrq == 14))) {
+ LegacyInterrupts[Index + 8] = HddIrq;
+ }
+ }
+
+ Private->LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ NULL,
+ NULL,
+ (VOID **) &IrqPriorityTable,
+ &NumberPriorityEntries
+ );
+ //
+ // Remove legacy interrupts from the list of PCI interrupts available.
+ //
+ for (Index = 0; Index <= 0x0b; Index++) {
+ for (Index1 = 0; Index1 <= NumberPriorityEntries; Index1++) {
+ if (LegacyInterrupts[Index] != 0) {
+ LegacyInt = (UINT16) (LegacyInt | (1 << LegacyInterrupts[Index]));
+ if (LegacyInterrupts[Index] == IrqPriorityTable[Index1].Irq) {
+ IrqPriorityTable[Index1].Used = LEGACY_USED;
+ }
+ }
+ }
+ }
+
+ Private->Legacy8259->GetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Set SIO interrupts and disable mouse. Let mouse driver
+ // re-enable it.
+ //
+ LegMask = (UINT16) ((LegMask &~LegacyInt) | 0x1000);
+ Private->Legacy8259->SetMask (
+ Private->Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ //
+ // Disable mouse in keyboard controller
+ //
+ Register = 0xA7;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ IsaIo->Io.Write (IsaIo, EfiIsaIoWidthUint8, 0x64, 1, &Register);
+
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ This requires updating the checksum, if it exists.
+
+ @param IdentifyDriveData ATA Identify Data
+ @param Checksum checksum of the ATA Identify Data
+
+ @retval EFI_SUCCESS checksum calculated
+ @retval EFI_SECURITY_VIOLATION IdentifyData invalid
+
+**/
+EFI_STATUS
+CalculateIdentifyDriveChecksum (
+ IN UINT8 *IdentifyDriveData,
+ OUT UINT8 *Checksum
+ )
+{
+ UINTN Index;
+ UINT8 LocalChecksum;
+ LocalChecksum = 0;
+ *Checksum = 0;
+ if (IdentifyDriveData[510] != 0xA5) {
+ return EFI_SECURITY_VIOLATION;
+ }
+
+ for (Index = 0; Index < 512; Index++) {
+ LocalChecksum = (UINT8) (LocalChecksum + IdentifyDriveData[Index]);
+ }
+
+ *Checksum = LocalChecksum;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+
+ @param IdentifyDriveData ATA Identify Data
+
+
+**/
+VOID
+UpdateIdentifyDriveData (
+ IN UINT8 *IdentifyDriveData
+ )
+{
+ UINT16 NumberCylinders;
+ UINT16 NumberHeads;
+ UINT16 NumberSectorsTrack;
+ UINT32 CapacityInSectors;
+ UINT8 OriginalChecksum;
+ UINT8 FinalChecksum;
+ EFI_STATUS Status;
+ ATAPI_IDENTIFY *ReadInfo;
+
+ //
+ // Status indicates if Integrity byte is correct. Checksum should be
+ // 0 if valid.
+ //
+ ReadInfo = (ATAPI_IDENTIFY *) IdentifyDriveData;
+ Status = CalculateIdentifyDriveChecksum (IdentifyDriveData, &OriginalChecksum);
+ if (OriginalChecksum != 0) {
+ Status = EFI_SECURITY_VIOLATION;
+ }
+ //
+ // If NumberCylinders = 0 then do data(Controller present but don drive attached).
+ //
+ NumberCylinders = ReadInfo->Raw[1];
+ if (NumberCylinders != 0) {
+ ReadInfo->Raw[54] = NumberCylinders;
+
+ NumberHeads = ReadInfo->Raw[3];
+ ReadInfo->Raw[55] = NumberHeads;
+
+ NumberSectorsTrack = ReadInfo->Raw[6];
+ ReadInfo->Raw[56] = NumberSectorsTrack;
+
+ //
+ // Copy Multisector info and set valid bit.
+ //
+ ReadInfo->Raw[59] = (UINT16) (ReadInfo->Raw[47] + 0x100);
+ CapacityInSectors = (UINT32) ((UINT32) (NumberCylinders) * (UINT32) (NumberHeads) * (UINT32) (NumberSectorsTrack));
+ ReadInfo->Raw[57] = (UINT16) (CapacityInSectors >> 16);
+ ReadInfo->Raw[58] = (UINT16) (CapacityInSectors & 0xffff);
+ if (Status == EFI_SUCCESS) {
+ //
+ // Forece checksum byte to 0 and get new checksum.
+ //
+ ReadInfo->Raw[255] &= 0xff;
+ CalculateIdentifyDriveChecksum (IdentifyDriveData, &FinalChecksum);
+
+ //
+ // Force new checksum such that sum is 0.
+ //
+ FinalChecksum = (UINT8) ((UINT8)0 - FinalChecksum);
+ ReadInfo->Raw[255] = (UINT16) (ReadInfo->Raw[255] | (FinalChecksum << 8));
+ }
+ }
+}
+
+/**
+ Identify drive data must be updated to actual parameters before boot.
+ Do for all drives.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+UpdateAllIdentifyDriveData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN Index;
+ HDD_INFO *HddInfo;
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ //
+ // Each controller can have 2 devices. Update for each device
+ //
+ if ((HddInfo[Index].Status & HDD_MASTER_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[0].Raw[0]));
+ }
+
+ if ((HddInfo[Index].Status & HDD_SLAVE_IDE) != 0) {
+ UpdateIdentifyDriveData ((UINT8 *) (&HddInfo[Index].IdentifyDrive[1].Raw[0]));
+ }
+ }
+}
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableIdeController (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINT8 ByteBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ByteBuffer = 0x1f;
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint8, 0x04, 1, &ByteBuffer);
+ }
+ }
+}
+
+
+/**
+ Enable ide controller. This gets disabled when LegacyBoot.c is about
+ to run the Option ROMs.
+
+ @param Private Legacy BIOS Instance data
+
+
+**/
+VOID
+EnableAllControllers (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ EFI_STATUS Status;
+
+ //
+ //
+ //
+ EnableIdeController (Private);
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // We do not enable PPB here. This is for HotPlug Consideration.
+ // The Platform HotPlug Driver is responsible for Padding enough hot plug
+ // resources. It is also responsible for enable this bridge. If it
+ // does not pad it. It will cause some early Windows fail to installation.
+ // If the platform driver does not pad resource for PPB, PPB should be in
+ // un-enabled state to let Windows know that this PPB is not configured by
+ // BIOS. So Windows will allocate default resource for PPB.
+ //
+ // The reason for why we enable the command register is:
+ // The CSM will use the IO bar to detect some IRQ status, if the command
+ // is disabled, the IO resource will be out of scope.
+ // For example:
+ // We installed a legacy IRQ handle for a PCI IDE controller. When IRQ
+ // comes up, the handle will check the IO space to identify is the
+ // controller generated the IRQ source.
+ // If the IO command is not enabled, the IRQ handler will has wrong
+ // information. It will cause IRQ storm when the correctly IRQ handler fails
+ // to run.
+ //
+ if (!(IS_PCI_VGA (&PciConfigHeader) ||
+ IS_PCI_OLD_VGA (&PciConfigHeader) ||
+ IS_PCI_IDE (&PciConfigHeader) ||
+ IS_PCI_P2P (&PciConfigHeader) ||
+ IS_PCI_P2P_SUB (&PciConfigHeader) ||
+ IS_PCI_LPC (&PciConfigHeader) )) {
+
+ PciConfigHeader.Hdr.Command |= 0x1f;
+
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 4, 1, &PciConfigHeader.Hdr.Command);
+ }
+ }
+}
+
+/**
+ The following routines are identical in operation, so combine
+ for code compaction:
+ EfiGetPlatformBinaryGetMpTable
+ EfiGetPlatformBinaryGetOemIntData
+ EfiGetPlatformBinaryGetOem32Data
+ EfiGetPlatformBinaryGetOem16Data
+
+ @param This Protocol instance pointer.
+ @param Id Table/Data identifier
+
+ @retval EFI_SUCCESS Success
+ @retval EFI_INVALID_PARAMETER Invalid ID
+ @retval EFI_OUT_OF_RESOURCES no resource to get data or table
+
+**/
+EFI_STATUS
+LegacyGetDataOrTable (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_GET_PLATFORM_INFO_MODE Id
+ )
+{
+ VOID *Table;
+ UINT32 TablePtr;
+ UINTN TableSize;
+ UINTN Alignment;
+ UINTN Location;
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ EFI_IA32_REGISTER_SET Regs;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+ Legacy16Table = Private->Legacy16Table;
+
+ //
+ // Phase 1 - get an address allocated in 16-bit code
+ //
+ while (TRUE) {
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ case EfiGetPlatformBinaryOemIntData:
+ case EfiGetPlatformBinaryOem32Data:
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ 0,
+ 0
+ );
+ DEBUG ((EFI_D_INFO, "LegacyGetDataOrTable - ID: %x, %r\n", (UINTN)Id, Status));
+ DEBUG ((EFI_D_INFO, " Table - %x, Size - %x, Location - %x, Alignment - %x\n", (UINTN)Table, (UINTN)TableSize, (UINTN)Location, (UINTN)Alignment));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) TableSize;
+ Regs.X.BX = (UINT16) Location;
+ Regs.X.DX = (UINT16) Alignment;
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Table ID %x length insufficient\n", Id));
+ return EFI_OUT_OF_RESOURCES;
+ } else {
+ break;
+ }
+ }
+ //
+ // Phase 2 Call routine second time with address to allow address adjustment
+ //
+ Status = LegacyBiosPlatform->GetPlatformInfo (
+ LegacyBiosPlatform,
+ Id,
+ (VOID *) &Table,
+ &TableSize,
+ &Location,
+ &Alignment,
+ Regs.X.DS,
+ Regs.X.BX
+ );
+ switch (Id) {
+ case EfiGetPlatformBinaryMpTable:
+ {
+ Legacy16Table->MpTablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Legacy16Table->MpTableLength = (UINT32)TableSize;
+ DEBUG ((EFI_D_INFO, "MP table in legacy region - %x\n", (UINTN)Legacy16Table->MpTablePtr));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOemIntData:
+ {
+
+ Legacy16Table->OemIntSegment = Regs.X.DS;
+ Legacy16Table->OemIntOffset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "OemInt table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->OemIntSegment, (UINTN)Legacy16Table->OemIntOffset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem32Data:
+ {
+ Legacy16Table->Oem32Segment = Regs.X.DS;
+ Legacy16Table->Oem32Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem32 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem32Segment, (UINTN)Legacy16Table->Oem32Offset));
+ break;
+ }
+
+ case EfiGetPlatformBinaryOem16Data:
+ {
+ //
+ // Legacy16Table->Oem16Segment = Regs.X.DS;
+ // Legacy16Table->Oem16Offset = Regs.X.BX;
+ DEBUG ((EFI_D_INFO, "Oem16 table in legacy region - %04x:%04x\n", (UINTN)Legacy16Table->Oem16Segment, (UINTN)Legacy16Table->Oem16Offset));
+ break;
+ }
+
+ default:
+ {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Phase 3 Copy table to final location
+ //
+ TablePtr = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+
+ CopyMem (
+ (VOID *) (UINTN)TablePtr,
+ Table,
+ TableSize
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Copy SMBIOS table to EfiReservedMemoryType of memory for legacy boot.
+
+**/
+VOID
+CreateSmbiosTableInReservedMemory (
+ VOID
+ )
+{
+ SMBIOS_TABLE_ENTRY_POINT *EntryPointStructure;
+
+ if ((mRuntimeSmbiosEntryPoint == NULL) ||
+ (mReserveSmbiosEntryPoint == 0) ||
+ (mStructureTableAddress == 0)) {
+ return;
+ }
+
+ EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *) mRuntimeSmbiosEntryPoint;
+
+ //
+ // Copy SMBIOS Entry Point Structure
+ //
+ CopyMem (
+ (VOID *)(UINTN) mReserveSmbiosEntryPoint,
+ EntryPointStructure,
+ EntryPointStructure->EntryPointLength
+ );
+
+ //
+ // Copy SMBIOS Structure Table into EfiReservedMemoryType memory
+ //
+ CopyMem (
+ (VOID *)(UINTN) mStructureTableAddress,
+ (VOID *)(UINTN) EntryPointStructure->TableAddress,
+ EntryPointStructure->TableLength
+ );
+
+ //
+ // Update TableAddress in Entry Point Structure
+ //
+ EntryPointStructure = (SMBIOS_TABLE_ENTRY_POINT *)(UINTN) mReserveSmbiosEntryPoint;
+ EntryPointStructure->TableAddress = (UINT32)(UINTN) mStructureTableAddress;
+
+ //
+ // Fixup checksums in the Entry Point Structure
+ //
+ EntryPointStructure->IntermediateChecksum = 0;
+ EntryPointStructure->EntryPointStructureChecksum = 0;
+
+ EntryPointStructure->IntermediateChecksum =
+ CalculateCheckSum8 (
+ (UINT8 *) EntryPointStructure + OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString),
+ EntryPointStructure->EntryPointLength - OFFSET_OF (SMBIOS_TABLE_ENTRY_POINT, IntermediateAnchorString)
+ );
+ EntryPointStructure->EntryPointStructureChecksum =
+ CalculateCheckSum8 ((UINT8 *) EntryPointStructure, EntryPointStructure->EntryPointLength);
+}
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+GenericLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_IA32_REGISTER_SET Regs;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINTN CopySize;
+ VOID *AcpiPtr;
+ HDD_INFO *HddInfo;
+ HDD_INFO *LocalHddInfo;
+ UINTN Index;
+ EFI_COMPATIBILITY16_TABLE *Legacy16Table;
+ UINT32 *BdaPtr;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ BBS_TABLE *LocalBbsTable;
+ UINT32 *BaseVectorMaster;
+ EFI_TIME BootTime;
+ UINT32 LocalTime;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ VOID *AcpiTable;
+ UINTN ShadowAddress;
+ UINT32 Granularity;
+
+ LocalHddInfo = NULL;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalBbsTable = NULL;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ DEBUG_CODE (
+ DEBUG ((EFI_D_ERROR, "Start of legacy boot\n"));
+ );
+
+ Legacy16Table = Private->Legacy16Table;
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ HddInfo = &EfiToLegacy16BootTable->HddInfo[0];
+
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ EfiToLegacy16BootTable->MajorVersion = EFI_TO_LEGACY_MAJOR_VERSION;
+ EfiToLegacy16BootTable->MinorVersion = EFI_TO_LEGACY_MINOR_VERSION;
+
+ //
+ // If booting to a legacy OS then force HDD drives to the appropriate
+ // boot mode by calling GetIdeHandle.
+ // A reconnect -r can force all HDDs back to native mode.
+ //
+ IdeController = NULL;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ Status = LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ }
+ }
+ //
+ // Unlock the Legacy BIOS region
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ //
+ // Reconstruct the Legacy16 boot memory map
+ //
+ LegacyBiosBuildE820 (Private, &CopySize);
+ if (CopySize > Private->Legacy16Table->E820Length) {
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) CopySize;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->E820Pointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "Legacy16 E820 length insufficient\n"));
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ }
+ } else {
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->E820Pointer,
+ Private->E820Table,
+ CopySize
+ );
+ Private->Legacy16Table->E820Length = (UINT32) CopySize;
+ }
+
+ //
+ // We do not ASSERT if SmbiosTable not found. It is possbile that a platform does not produce SmbiosTable.
+ //
+ if (mReserveSmbiosEntryPoint == 0) {
+ DEBUG ((EFI_D_INFO, "Smbios table is not found!\n"));
+ }
+ CreateSmbiosTableInReservedMemory ();
+ EfiToLegacy16BootTable->SmbiosTable = (UINT32)(UINTN)mReserveSmbiosEntryPoint;
+
+ AcpiTable = NULL;
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi20TableGuid,
+ &AcpiTable
+ );
+ if (EFI_ERROR (Status)) {
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiAcpi10TableGuid,
+ &AcpiTable
+ );
+ }
+ //
+ // We do not ASSERT if AcpiTable not found. It is possbile that a platform does not produce AcpiTable.
+ //
+ if (AcpiTable == NULL) {
+ DEBUG ((EFI_D_INFO, "ACPI table is not found!\n"));
+ }
+ EfiToLegacy16BootTable->AcpiTable = (UINT32)(UINTN)AcpiTable;
+
+ //
+ // Get RSD Ptr table rev at offset 15 decimal
+ // Rev = 0 Length is 20 decimal
+ // Rev != 0 Length is UINT32 at offset 20 decimal
+ //
+ if (AcpiTable != NULL) {
+
+ AcpiPtr = AcpiTable;
+ if (*((UINT8 *) AcpiPtr + 15) == 0) {
+ CopySize = 20;
+ } else {
+ AcpiPtr = ((UINT8 *) AcpiPtr + 20);
+ CopySize = (*(UINT32 *) AcpiPtr);
+ }
+
+ CopyMem (
+ (VOID *)(UINTN) Private->Legacy16Table->AcpiRsdPtrPointer,
+ AcpiTable,
+ CopySize
+ );
+ }
+ //
+ // Make sure all PCI Interrupt Line register are programmed to match 8259
+ //
+ PciProgramAllInterruptLineRegisters (Private);
+
+ //
+ // Unlock the Legacy BIOS region as PciProgramAllInterruptLineRegisters
+ // can lock it.
+ //
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ Private->BiosStart,
+ Private->LegacyBiosImageSize,
+ &Granularity
+ );
+
+ //
+ // Configure Legacy Device Magic
+ //
+ // Only do this code if booting legacy OS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ UpdateSioData (Private);
+ }
+ //
+ // Setup BDA and EBDA standard areas before Legacy Boot
+ //
+ LegacyBiosCompleteBdaBeforeBoot (Private);
+ LegacyBiosCompleteStandardCmosBeforeBoot (Private);
+
+ //
+ // We must build IDE data, if it hasn't been done, before PciShadowRoms
+ // to insure EFI drivers are connected.
+ //
+ LegacyBiosBuildIdeData (Private, &HddInfo, 1);
+ UpdateAllIdentifyDriveData (Private);
+
+ //
+ // Clear IO BAR, if IDE controller in legacy mode.
+ //
+ InitLegacyIdeController (IdeController);
+
+ //
+ // Generate number of ticks since midnight for BDA. DOS requires this
+ // for its time. We have to make assumptions as to how long following
+ // code takes since after PciShadowRoms PciIo is gone. Place result in
+ // 40:6C-6F
+ //
+ // Adjust value by 1 second.
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+ LocalTime += 1;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) (UINTN)0x46C;
+ *BdaPtr = LocalTime;
+
+ //
+ // Shadow PCI ROMs. We must do this near the end since this will kick
+ // of Native EFI drivers that may be needed to collect info for Legacy16
+ //
+ // WARNING: PciIo is gone after this call.
+ //
+ PciShadowRoms (Private);
+
+ //
+ // Shadow PXE base code, BIS etc.
+ //
+ Private->LegacyRegion->UnLock (Private->LegacyRegion, 0xc0000, 0x40000, &Granularity);
+ ShadowAddress = Private->OptionRom;
+ Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookShadowServiceRoms,
+ 0,
+ 0,
+ &ShadowAddress,
+ Legacy16Table,
+ NULL
+ );
+ Private->OptionRom = (UINT32)ShadowAddress;
+ //
+ // Register Legacy SMI Handler
+ //
+ LegacyBiosPlatform->SmmInit (
+ LegacyBiosPlatform,
+ EfiToLegacy16BootTable
+ );
+
+ //
+ // Let platform code know the boot options
+ //
+ LegacyBiosGetBbsInfo (
+ This,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ DEBUG_CODE (
+ PrintPciInterruptRegister ();
+ PrintBbsTable (LocalBbsTable);
+ PrintHddInfo (LocalHddInfo);
+ );
+ //
+ // If drive wasn't spun up then BuildIdeData may have found new drives.
+ // Need to update BBS boot priority.
+ //
+ for (Index = 0; Index < MAX_IDE_CONTROLLER; Index++) {
+ if ((LocalHddInfo[Index].IdentifyDrive[0].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 1].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 1].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+
+ if ((LocalHddInfo[Index].IdentifyDrive[1].Raw[0] != 0) &&
+ (LocalBbsTable[2 * Index + 2].BootPriority == BBS_IGNORE_ENTRY)
+ ) {
+ LocalBbsTable[2 * Index + 2].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ LegacyBiosPlatform->PrepareToBoot (
+ LegacyBiosPlatform,
+ mBbsDevicePathPtr,
+ mBbsTable,
+ mLoadOptionsSize,
+ mLoadOptions,
+ (VOID *) &Private->IntThunk->EfiToLegacy16BootTable
+ );
+
+ //
+ // If no boot device return to BDS
+ //
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ for (Index = 0; Index < BbsCount; Index++){
+ if ((LocalBbsTable[Index].BootPriority != BBS_DO_NOT_BOOT_FROM) &&
+ (LocalBbsTable[Index].BootPriority != BBS_UNPRIORITIZED_ENTRY) &&
+ (LocalBbsTable[Index].BootPriority != BBS_IGNORE_ENTRY)) {
+ break;
+ }
+ }
+ if (Index == BbsCount) {
+ return EFI_DEVICE_ERROR;
+ }
+ }
+ //
+ // Let the Legacy16 code know the device path type for legacy boot
+ //
+ EfiToLegacy16BootTable->DevicePathType = mBbsDevicePathPtr->DeviceType;
+
+ //
+ // Copy MP table, if it exists.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryMpTable);
+
+ if (!Private->LegacyBootEntered) {
+ //
+ // Copy OEM INT Data, if it exists. Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOemIntData);
+
+ //
+ // Copy OEM16 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem16Data);
+
+ //
+ // Copy OEM32 Data, if it exists.Note: This code treats any data
+ // as a bag of bits and knows nothing of the contents nor cares.
+ // Contents are IBV specific.
+ //
+ LegacyGetDataOrTable (This, EfiGetPlatformBinaryOem32Data);
+ }
+
+ //
+ // Call into Legacy16 code to prepare for INT 19h
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16PrepareToBoot;
+
+ //
+ // Pass in handoff data
+ //
+ Regs.X.ES = NORMALIZE_EFI_SEGMENT ((UINTN)EfiToLegacy16BootTable);
+ Regs.X.BX = NORMALIZE_EFI_OFFSET ((UINTN)EfiToLegacy16BootTable);
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ if (Regs.X.AX != 0) {
+ return EFI_DEVICE_ERROR;
+ }
+ //
+ // Lock the Legacy BIOS region
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ if ((Private->Legacy16Table->TableLength >= OFFSET_OF (EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
+ ((Private->Legacy16Table->UmaAddress != 0) && (Private->Legacy16Table->UmaSize != 0))) {
+ //
+ // Here we could reduce UmaAddress down as far as Private->OptionRom, taking into
+ // account the granularity of the access control.
+ //
+ DEBUG((EFI_D_INFO, "Unlocking UMB RAM region 0x%x-0x%x\n", Private->Legacy16Table->UmaAddress,
+ Private->Legacy16Table->UmaAddress + Private->Legacy16Table->UmaSize));
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ Private->Legacy16Table->UmaAddress,
+ Private->Legacy16Table->UmaSize,
+ &Granularity
+ );
+ }
+
+ //
+ // Lock attributes of the Legacy Region if chipset supports
+ //
+ Private->LegacyRegion->BootLock (
+ Private->LegacyRegion,
+ 0xc0000,
+ 0x40000,
+ &Granularity
+ );
+
+ //
+ // Call into Legacy16 code to do the INT 19h
+ //
+ EnableAllControllers (Private);
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+
+ //
+ // Signal all the events that are waiting on EVT_SIGNAL_LEGACY_BOOT
+ //
+ EfiSignalEventLegacyBoot ();
+
+ //
+ // Report Status Code to indicate legacy boot event was signalled
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_LEGACY_BOOT_EVENT)
+ );
+
+ DEBUG ((EFI_D_INFO, "Legacy INT19 Boot...\n"));
+
+ //
+ // Disable DXE Timer while executing in real mode
+ //
+ Private->Timer->SetTimerPeriod (Private->Timer, 0);
+
+ //
+ // Save and disable interrupt of debug timer
+ //
+ SaveAndSetDebugTimerInterrupt (FALSE);
+
+
+ //
+ // Put the 8259 into its legacy mode by reprogramming the vector bases
+ //
+ Private->Legacy8259->SetVectorBase (Private->Legacy8259, LEGACY_MODE_BASE_VECTOR_MASTER, LEGACY_MODE_BASE_VECTOR_SLAVE);
+ //
+ // PC History
+ // The original PC used INT8-F for master PIC. Since these mapped over
+ // processor exceptions TIANO moved the master PIC to INT68-6F.
+ // We need to set these back to the Legacy16 unexpected interrupt(saved
+ // in LegacyBios.c) since some OS see that these have values different from
+ // what is expected and invoke them. Since the legacy OS corrupts EFI
+ // memory, there is no handler for these interrupts and OS blows up.
+ //
+ // We need to save the TIANO values for the rare case that the Legacy16
+ // code cannot boot but knows memory hasn't been destroyed.
+ //
+ // To compound the problem, video takes over one of these INTS and must be
+ // be left.
+ // @bug - determine if video hooks INT(in which case we must find new
+ // set of TIANO vectors) or takes it over.
+ //
+ //
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ Private->ThunkSavedInt[Index] = BaseVectorMaster[Index];
+ if (Private->ThunkSeg == (UINT16) (BaseVectorMaster[Index] >> 16)) {
+ BaseVectorMaster[Index] = (UINT32) (Private->BiosUnexpectedInt);
+ }
+ }
+
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16Boot;
+
+ Private->LegacyBios.FarCall86 (
+ This,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ BaseVectorMaster = (UINT32 *) (sizeof (UINT32) * PROTECTED_MODE_BASE_VECTOR_MASTER);
+ for (Index = 0; Index < 8; Index++) {
+ BaseVectorMaster[Index] = Private->ThunkSavedInt[Index];
+ }
+ }
+ Private->LegacyBootEntered = TRUE;
+ if ((mBootMode == BOOT_LEGACY_OS) || (mBootMode == BOOT_UNCONVENTIONAL_DEVICE)) {
+ //
+ // Should never return unless never passed control to 0:7c00(first stage
+ // OS loader) and only then if no bootable device found.
+ //
+ return EFI_DEVICE_ERROR;
+ } else {
+ //
+ // If boot to EFI then expect to return to caller
+ //
+ return EFI_SUCCESS;
+ }
+}
+
+
+/**
+ Assign drive number to legacy HDD drives prior to booting an EFI
+ aware OS so the OS can access drives without an EFI driver.
+ Note: BBS compliant drives ARE NOT available until this call by
+ either shell or EFI.
+
+ @param This Protocol instance pointer.
+ @param BbsCount Number of BBS_TABLE structures
+ @param BbsTable List BBS entries
+
+ @retval EFI_SUCCESS Drive numbers assigned
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosPrepareToBootEfi (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ OUT UINT16 *BbsCount,
+ OUT BBS_TABLE **BbsTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+ mBootMode = BOOT_EFI_OS;
+ mBbsDevicePathPtr = NULL;
+ Status = GenericLegacyBoot (This);
+ *BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ *BbsCount = (UINT16) (sizeof (Private->IntThunk->BbsTable) / sizeof (BBS_TABLE));
+ return Status;
+}
+
+/**
+ To boot from an unconventional device like parties and/or execute HDD diagnostics.
+
+ @param This Protocol instance pointer.
+ @param Attributes How to interpret the other input parameters
+ @param BbsEntry The 0-based index into the BbsTable for the parent
+ device.
+ @param BeerData Pointer to the 128 bytes of ram BEER data.
+ @param ServiceAreaData Pointer to the 64 bytes of raw Service Area data. The
+ caller must provide a pointer to the specific Service
+ Area and not the start all Service Areas.
+
+ @retval EFI_INVALID_PARAMETER if error. Does NOT return if no error.
+
+***/
+EFI_STATUS
+EFIAPI
+LegacyBiosBootUnconventionalDevice (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UDC_ATTRIBUTES Attributes,
+ IN UINTN BbsEntry,
+ IN VOID *BeerData,
+ IN VOID *ServiceAreaData
+ )
+{
+ EFI_STATUS Status;
+ EFI_TO_COMPATIBILITY16_BOOT_TABLE *EfiToLegacy16BootTable;
+ LEGACY_BIOS_INSTANCE *Private;
+ UD_TABLE *UcdTable;
+ UINTN Index;
+ UINT16 BootPriority;
+ BBS_TABLE *BbsTable;
+
+ BootPriority = 0;
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ mBootMode = BOOT_UNCONVENTIONAL_DEVICE;
+ mBbsDevicePathPtr = &mBbsDevicePathNode;
+ mAttributes = Attributes;
+ mBbsEntry = BbsEntry;
+ mBeerData = BeerData, mServiceAreaData = ServiceAreaData;
+
+ EfiToLegacy16BootTable = &Private->IntThunk->EfiToLegacy16BootTable;
+
+ //
+ // Do input parameter checking
+ //
+ if ((Attributes.DirectoryServiceValidity == 0) &&
+ (Attributes.RabcaUsedFlag == 0) &&
+ (Attributes.ExecuteHddDiagnosticsFlag == 0)
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (((Attributes.DirectoryServiceValidity != 0) && (ServiceAreaData == NULL)) ||
+ (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag) != 0) && (BeerData == NULL))
+ ) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UcdTable = (UD_TABLE *) AllocatePool (
+ sizeof (UD_TABLE)
+ );
+ if (NULL == UcdTable) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ EfiToLegacy16BootTable->UnconventionalDeviceTable = (UINT32)(UINTN)UcdTable;
+ UcdTable->Attributes = Attributes;
+ UcdTable->BbsTableEntryNumberForParentDevice = (UINT8) BbsEntry;
+ //
+ // Force all existing BBS entries to DoNotBoot. This allows 16-bit CSM
+ // to assign drive numbers but bot boot from. Only newly created entries
+ // will be valid.
+ //
+ BbsTable = (BBS_TABLE*)(UINTN)EfiToLegacy16BootTable->BbsTable;
+ for (Index = 0; Index < EfiToLegacy16BootTable->NumberBbsEntries; Index++) {
+ BbsTable[Index].BootPriority = BBS_DO_NOT_BOOT_FROM;
+ }
+ //
+ // If parent is onboard IDE then assign controller & device number
+ // else they are 0.
+ //
+ if (BbsEntry < MAX_IDE_CONTROLLER * 2) {
+ UcdTable->DeviceNumber = (UINT8) ((BbsEntry - 1) % 2);
+ }
+
+ if (BeerData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->BeerData,
+ BeerData,
+ (UINTN) 128
+ );
+ }
+
+ if (ServiceAreaData != NULL) {
+ CopyMem (
+ (VOID *) UcdTable->ServiceAreaData,
+ ServiceAreaData,
+ (UINTN) 64
+ );
+ }
+ //
+ // For each new entry do the following:
+ // 1. Increment current number of BBS entries
+ // 2. Copy parent entry to new entry.
+ // 3. Zero out BootHandler Offset & segment
+ // 4. Set appropriate device type. BEV(0x80) for HDD diagnostics
+ // and Floppy(0x01) for PARTIES boot.
+ // 5. Assign new priority.
+ //
+ if ((Attributes.ExecuteHddDiagnosticsFlag) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x80;
+
+ UcdTable->BbsTableEntryNumberForHddDiag = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+ BootPriority += 1;
+
+ //
+ // Set device type as BBS_TYPE_DEV for PARTIES diagnostic
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_BEV;
+ }
+
+ if (((Attributes.DirectoryServiceValidity | Attributes.RabcaUsedFlag)) != 0) {
+ EfiToLegacy16BootTable->NumberBbsEntries += 1;
+ CopyMem (
+ (VOID *) &BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority,
+ (VOID *) &BbsTable[BbsEntry].BootPriority,
+ sizeof (BBS_TABLE)
+ );
+
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerOffset = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootHandlerSegment = 0;
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].DeviceType = 0x01;
+ UcdTable->BbsTableEntryNumberForBoot = (UINT8) (EfiToLegacy16BootTable->NumberBbsEntries - 1);
+ BbsTable[EfiToLegacy16BootTable->NumberBbsEntries].BootPriority = BootPriority;
+
+ //
+ // Set device type as BBS_TYPE_FLOPPY for PARTIES boot as floppy
+ //
+ mBbsDevicePathNode.DeviceType = BBS_TYPE_FLOPPY;
+ }
+ //
+ // Build the BBS Device Path for this boot selection
+ //
+ mBbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
+ mBbsDevicePathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (&mBbsDevicePathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+ mBbsDevicePathNode.StatusFlag = 0;
+ mBbsDevicePathNode.String[0] = 0;
+
+ Status = GenericLegacyBoot (This);
+ return Status;
+}
+
+/**
+ Attempt to legacy boot the BootOption. If the EFI contexted has been
+ compromised this function will not return.
+
+ @param This Protocol instance pointer.
+ @param BbsDevicePath EFI Device Path from BootXXXX variable.
+ @param LoadOptionsSize Size of LoadOption in size.
+ @param LoadOptions LoadOption from BootXXXX variable
+
+ @retval EFI_SUCCESS Removable media not present
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosLegacyBoot (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN BBS_BBS_DEVICE_PATH *BbsDevicePath,
+ IN UINT32 LoadOptionsSize,
+ IN VOID *LoadOptions
+ )
+{
+ EFI_STATUS Status;
+
+ mBbsDevicePathPtr = BbsDevicePath;
+ mLoadOptionsSize = LoadOptionsSize;
+ mLoadOptions = LoadOptions;
+ mBootMode = BOOT_LEGACY_OS;
+ Status = GenericLegacyBoot (This);
+
+ return Status;
+}
+
+/**
+ Convert EFI Memory Type to E820 Memory Type.
+
+ @param Type EFI Memory Type
+
+ @return ACPI Memory Type for EFI Memory Type
+
+**/
+EFI_ACPI_MEMORY_TYPE
+EfiMemoryTypeToE820Type (
+ IN UINT32 Type
+ )
+{
+ switch (Type) {
+ case EfiLoaderCode:
+ case EfiLoaderData:
+ case EfiBootServicesCode:
+ case EfiBootServicesData:
+ case EfiConventionalMemory:
+ //
+ // The memory of EfiRuntimeServicesCode and EfiRuntimeServicesData are
+ // usable memory for legacy OS, because legacy OS is not aware of EFI runtime concept.
+ // In ACPI specification, EfiRuntimeServiceCode and EfiRuntimeServiceData
+ // should be mapped to AddressRangeReserved. This statement is for UEFI OS, not for legacy OS.
+ //
+ case EfiRuntimeServicesCode:
+ case EfiRuntimeServicesData:
+ return EfiAcpiAddressRangeMemory;
+
+ case EfiPersistentMemory:
+ return EfiAddressRangePersistentMemory;
+
+ case EfiACPIReclaimMemory:
+ return EfiAcpiAddressRangeACPI;
+
+ case EfiACPIMemoryNVS:
+ return EfiAcpiAddressRangeNVS;
+
+ //
+ // All other types map to reserved.
+ // Adding the code just waists FLASH space.
+ //
+ // case EfiReservedMemoryType:
+ // case EfiUnusableMemory:
+ // case EfiMemoryMappedIO:
+ // case EfiMemoryMappedIOPortSpace:
+ // case EfiPalCode:
+ //
+ default:
+ return EfiAcpiAddressRangeReserved;
+ }
+}
+
+/**
+ Build the E820 table.
+
+ @param Private Legacy BIOS Instance data
+ @param Size Size of E820 Table
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildE820 (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ EFI_E820_ENTRY64 *E820Table;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMap;
+ EFI_MEMORY_DESCRIPTOR *EfiMemoryMapEnd;
+ EFI_MEMORY_DESCRIPTOR *EfiEntry;
+ EFI_MEMORY_DESCRIPTOR *NextEfiEntry;
+ EFI_MEMORY_DESCRIPTOR TempEfiEntry;
+ UINTN EfiMemoryMapSize;
+ UINTN EfiMapKey;
+ UINTN EfiDescriptorSize;
+ UINT32 EfiDescriptorVersion;
+ UINTN Index;
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_HOB_RESOURCE_DESCRIPTOR *ResourceHob;
+ UINTN TempIndex;
+ UINTN IndexSort;
+ UINTN TempNextIndex;
+ EFI_E820_ENTRY64 TempE820;
+ EFI_ACPI_MEMORY_TYPE TempType;
+ BOOLEAN ChangedFlag;
+ UINTN Above1MIndex;
+ UINT64 MemoryBlockLength;
+
+ E820Table = (EFI_E820_ENTRY64 *) Private->E820Table;
+
+ //
+ // Get the EFI memory map.
+ //
+ EfiMemoryMapSize = 0;
+ EfiMemoryMap = NULL;
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ do {
+ //
+ // Use size returned back plus 1 descriptor for the AllocatePool.
+ // We don't just multiply by 2 since the "for" loop below terminates on
+ // EfiMemoryMapEnd which is dependent upon EfiMemoryMapSize. Otherwize
+ // we process bogus entries and create bogus E820 entries.
+ //
+ EfiMemoryMap = (EFI_MEMORY_DESCRIPTOR *) AllocatePool (EfiMemoryMapSize);
+ ASSERT (EfiMemoryMap != NULL);
+ Status = gBS->GetMemoryMap (
+ &EfiMemoryMapSize,
+ EfiMemoryMap,
+ &EfiMapKey,
+ &EfiDescriptorSize,
+ &EfiDescriptorVersion
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (EfiMemoryMap);
+ }
+ } while (Status == EFI_BUFFER_TOO_SMALL);
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Punch in the E820 table for memory less than 1 MB.
+ // Assume ZeroMem () has been done on data structure.
+ //
+ //
+ // First entry is 0 to (640k - EBDA)
+ //
+ E820Table[0].BaseAddr = 0;
+ E820Table[0].Length = (UINT64) ((*(UINT16 *) (UINTN)0x40E) << 4);
+ E820Table[0].Type = EfiAcpiAddressRangeMemory;
+
+ //
+ // Second entry is (640k - EBDA) to 640k
+ //
+ E820Table[1].BaseAddr = E820Table[0].Length;
+ E820Table[1].Length = (UINT64) ((640 * 1024) - E820Table[0].Length);
+ E820Table[1].Type = EfiAcpiAddressRangeReserved;
+
+ //
+ // Third Entry is legacy BIOS
+ // DO NOT CLAIM region from 0xA0000-0xDFFFF. OS can use free areas
+ // to page in memory under 1MB.
+ // Omit region from 0xE0000 to start of BIOS, if any. This can be
+ // used for a multiple reasons including OPROMS.
+ //
+
+ //
+ // The CSM binary image size is not the actually size that CSM binary used,
+ // to avoid memory corrupt, we declare the 0E0000 - 0FFFFF is used by CSM binary.
+ //
+ E820Table[2].BaseAddr = 0xE0000;
+ E820Table[2].Length = 0x20000;
+ E820Table[2].Type = EfiAcpiAddressRangeReserved;
+
+ Above1MIndex = 2;
+
+ //
+ // Process the EFI map to produce E820 map;
+ //
+
+ //
+ // Sort memory map from low to high
+ //
+ EfiEntry = EfiMemoryMap;
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ while (EfiEntry < EfiMemoryMapEnd) {
+ while (NextEfiEntry < EfiMemoryMapEnd) {
+ if (EfiEntry->PhysicalStart > NextEfiEntry->PhysicalStart) {
+ CopyMem (&TempEfiEntry, EfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (EfiEntry, NextEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ CopyMem (NextEfiEntry, &TempEfiEntry, sizeof (EFI_MEMORY_DESCRIPTOR));
+ }
+
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (NextEfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ NextEfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ EfiEntry = EfiMemoryMap;
+ EfiMemoryMapEnd = (EFI_MEMORY_DESCRIPTOR *) ((UINT8 *) EfiMemoryMap + EfiMemoryMapSize);
+ for (Index = Above1MIndex; (EfiEntry < EfiMemoryMapEnd) && (Index < EFI_MAX_E820_ENTRY - 1); ) {
+ MemoryBlockLength = (UINT64) (LShiftU64 (EfiEntry->NumberOfPages, 12));
+ if ((EfiEntry->PhysicalStart + MemoryBlockLength) < 0x100000) {
+ //
+ // Skip the memory block is under 1MB
+ //
+ } else {
+ if (EfiEntry->PhysicalStart < 0x100000) {
+ //
+ // When the memory block spans below 1MB, ensure the memory block start address is at least 1MB
+ //
+ MemoryBlockLength -= 0x100000 - EfiEntry->PhysicalStart;
+ EfiEntry->PhysicalStart = 0x100000;
+ }
+
+ //
+ // Convert memory type to E820 type
+ //
+ TempType = EfiMemoryTypeToE820Type (EfiEntry->Type);
+
+ if ((E820Table[Index].Type == TempType) && (EfiEntry->PhysicalStart == (E820Table[Index].BaseAddr + E820Table[Index].Length))) {
+ //
+ // Grow an existing entry
+ //
+ E820Table[Index].Length += MemoryBlockLength;
+ } else {
+ //
+ // Make a new entry
+ //
+ ++Index;
+ E820Table[Index].BaseAddr = EfiEntry->PhysicalStart;
+ E820Table[Index].Length = MemoryBlockLength;
+ E820Table[Index].Type = TempType;
+ }
+ }
+ EfiEntry = NEXT_MEMORY_DESCRIPTOR (EfiEntry, EfiDescriptorSize);
+ }
+
+ FreePool (EfiMemoryMap);
+
+ //
+ // Process the reserved memory map to produce E820 map ;
+ //
+ for (Hob.Raw = GetHobList (); !END_OF_HOB_LIST (Hob); Hob.Raw = GET_NEXT_HOB (Hob)) {
+ if (Hob.Raw != NULL && GET_HOB_TYPE (Hob) == EFI_HOB_TYPE_RESOURCE_DESCRIPTOR) {
+ ResourceHob = Hob.ResourceDescriptor;
+ if (((ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_MAPPED_IO) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_FIRMWARE_DEVICE) ||
+ (ResourceHob->ResourceType == EFI_RESOURCE_MEMORY_RESERVED) ) &&
+ (ResourceHob->PhysicalStart > 0x100000) &&
+ (Index < EFI_MAX_E820_ENTRY - 1)) {
+ ++Index;
+ E820Table[Index].BaseAddr = ResourceHob->PhysicalStart;
+ E820Table[Index].Length = ResourceHob->ResourceLength;
+ E820Table[Index].Type = EfiAcpiAddressRangeReserved;
+ }
+ }
+ }
+
+ Index ++;
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Sort E820Table from low to high
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ ChangedFlag = FALSE;
+ for (TempNextIndex = 1; TempNextIndex < Index - TempIndex; TempNextIndex++) {
+ if (E820Table[TempNextIndex - 1].BaseAddr > E820Table[TempNextIndex].BaseAddr) {
+ ChangedFlag = TRUE;
+ TempE820.BaseAddr = E820Table[TempNextIndex - 1].BaseAddr;
+ TempE820.Length = E820Table[TempNextIndex - 1].Length;
+ TempE820.Type = E820Table[TempNextIndex - 1].Type;
+
+ E820Table[TempNextIndex - 1].BaseAddr = E820Table[TempNextIndex].BaseAddr;
+ E820Table[TempNextIndex - 1].Length = E820Table[TempNextIndex].Length;
+ E820Table[TempNextIndex - 1].Type = E820Table[TempNextIndex].Type;
+
+ E820Table[TempNextIndex].BaseAddr = TempE820.BaseAddr;
+ E820Table[TempNextIndex].Length = TempE820.Length;
+ E820Table[TempNextIndex].Type = TempE820.Type;
+ }
+ }
+
+ if (!ChangedFlag) {
+ break;
+ }
+ }
+
+ //
+ // Remove the overlap range
+ //
+ for (TempIndex = 1; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex - 1].BaseAddr <= E820Table[TempIndex].BaseAddr &&
+ ((E820Table[TempIndex - 1].BaseAddr + E820Table[TempIndex - 1].Length) >=
+ (E820Table[TempIndex].BaseAddr +E820Table[TempIndex].Length))) {
+ //
+ //Overlap range is found
+ //
+ ASSERT (E820Table[TempIndex - 1].Type == E820Table[TempIndex].Type);
+
+ if (TempIndex == Index - 1) {
+ E820Table[TempIndex].BaseAddr = 0;
+ E820Table[TempIndex].Length = 0;
+ E820Table[TempIndex].Type = (EFI_ACPI_MEMORY_TYPE) 0;
+ Index--;
+ break;
+ } else {
+ for (IndexSort = TempIndex; IndexSort < Index - 1; IndexSort ++) {
+ E820Table[IndexSort].BaseAddr = E820Table[IndexSort + 1].BaseAddr;
+ E820Table[IndexSort].Length = E820Table[IndexSort + 1].Length;
+ E820Table[IndexSort].Type = E820Table[IndexSort + 1].Type;
+ }
+ Index--;
+ }
+ }
+ }
+
+
+
+ Private->IntThunk->EfiToLegacy16InitTable.NumberE820Entries = (UINT32)Index;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberE820Entries = (UINT32)Index;
+ Private->NumberE820Entries = (UINT32)Index;
+ *Size = (UINTN) (Index * sizeof (EFI_E820_ENTRY64));
+
+ //
+ // Determine OS usable memory above 1Mb
+ //
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb = 0x0000;
+ for (TempIndex = Above1MIndex; TempIndex < Index; TempIndex++) {
+ if (E820Table[TempIndex].BaseAddr >= 0x100000 && E820Table[TempIndex].BaseAddr < 0x100000000ULL) { // not include above 4G memory
+ //
+ // ACPIReclaimMemory is also usable memory for ACPI OS, after OS dumps all ACPI tables.
+ //
+ if ((E820Table[TempIndex].Type == EfiAcpiAddressRangeMemory) || (E820Table[TempIndex].Type == EfiAcpiAddressRangeACPI)) {
+ Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb += (UINT32) (E820Table[TempIndex].Length);
+ } else {
+ break; // break at first not normal memory, because SMM may use reserved memory.
+ }
+ }
+ }
+
+ Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb = Private->IntThunk->EfiToLegacy16BootTable.OsMemoryAbove1Mb;
+
+ //
+ // Print DEBUG information
+ //
+ for (TempIndex = 0; TempIndex < Index; TempIndex++) {
+ DEBUG((EFI_D_INFO, "E820[%2d]: 0x%16lx ---- 0x%16lx, Type = 0x%x \n",
+ TempIndex,
+ E820Table[TempIndex].BaseAddr,
+ (E820Table[TempIndex].BaseAddr + E820Table[TempIndex].Length),
+ E820Table[TempIndex].Type
+ ));
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard BDA and EBDA stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteBdaBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ BDA_STRUC *Bda;
+ UINT16 MachineConfig;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+ MachineConfig = 0;
+
+ SioPtr = &(Private->IntThunk->EfiToLegacy16BootTable.SioData);
+ Bda->Com1 = SioPtr->Serial[0].Address;
+ Bda->Com2 = SioPtr->Serial[1].Address;
+ Bda->Com3 = SioPtr->Serial[2].Address;
+ Bda->Com4 = SioPtr->Serial[3].Address;
+
+ if (SioPtr->Serial[0].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[1].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[2].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ if (SioPtr->Serial[3].Address != 0x00) {
+ MachineConfig += 0x200;
+ }
+
+ Bda->Lpt1 = SioPtr->Parallel[0].Address;
+ Bda->Lpt2 = SioPtr->Parallel[1].Address;
+ Bda->Lpt3 = SioPtr->Parallel[2].Address;
+
+ if (SioPtr->Parallel[0].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[1].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ if (SioPtr->Parallel[2].Address != 0x00) {
+ MachineConfig += 0x4000;
+ }
+
+ Bda->NumberOfDrives = (UINT8) (Bda->NumberOfDrives + Private->IdeDriveCount);
+ if (SioPtr->Floppy.NumberOfFloppy != 0x00) {
+ MachineConfig = (UINT16) (MachineConfig + 0x01 + (SioPtr->Floppy.NumberOfFloppy - 1) * 0x40);
+ Bda->FloppyXRate = 0x07;
+ }
+
+ Bda->Lpt1_2Timeout = 0x1414;
+ Bda->Lpt3_4Timeout = 0x1414;
+ Bda->Com1_2Timeout = 0x0101;
+ Bda->Com3_4Timeout = 0x0101;
+
+ //
+ // Force VGA and Coprocessor, indicate 101/102 keyboard
+ //
+ MachineConfig = (UINT16) (MachineConfig + 0x00 + 0x02 + (SioPtr->MousePresent * 0x04));
+ Bda->MachineConfig = MachineConfig;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill in the standard BDA for Keyboard LEDs
+
+ @param This Protocol instance pointer.
+ @param Leds Current LED status
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosUpdateKeyboardLedStatus (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 Leds
+ )
+{
+ LEGACY_BIOS_INSTANCE *Private;
+ BDA_STRUC *Bda;
+ UINT8 LocalLeds;
+ EFI_IA32_REGISTER_SET Regs;
+
+ Bda = (BDA_STRUC *) ((UINTN) 0x400);
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ LocalLeds = Leds;
+ Bda->LedStatus = (UINT8) ((Bda->LedStatus &~0x07) | LocalLeds);
+ LocalLeds = (UINT8) (LocalLeds << 4);
+ Bda->ShiftStatus = (UINT8) ((Bda->ShiftStatus &~0x70) | LocalLeds);
+ LocalLeds = (UINT8) (Leds & 0x20);
+ Bda->KeyboardStatus = (UINT8) ((Bda->KeyboardStatus &~0x20) | LocalLeds);
+ //
+ // Call into Legacy16 code to allow it to do any processing
+ //
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+ Regs.X.AX = Legacy16SetKeyboardLeds;
+ Regs.H.CL = Leds;
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16Table->Compatibility16CallSegment,
+ Private->Legacy16Table->Compatibility16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff prior to legacy Boot
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosCompleteStandardCmosBeforeBoot (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT8 Bda;
+ UINT8 Floppy;
+ UINT32 Size;
+
+ //
+ // Update CMOS locations
+ // 10 floppy
+ // 12,19,1A - ignore as OS don't use them and there is no standard due
+ // to large capacity drives
+ // CMOS 14 = BDA 40:10 plus bit 3(display enabled)
+ //
+ Bda = (UINT8)(*((UINT8 *)((UINTN)0x410)) | BIT3);
+
+ //
+ // Force display enabled
+ //
+ Floppy = 0x00;
+ if ((Bda & BIT0) != 0) {
+ Floppy = BIT6;
+ }
+
+ //
+ // Check if 2.88MB floppy set
+ //
+ if ((Bda & (BIT7 | BIT6)) != 0) {
+ Floppy = (UINT8)(Floppy | BIT1);
+ }
+
+ LegacyWriteStandardCmos (CMOS_10, Floppy);
+ LegacyWriteStandardCmos (CMOS_14, Bda);
+
+ //
+ // Force Status Register A to set rate selection bits and divider
+ //
+ LegacyWriteStandardCmos (CMOS_0A, 0x26);
+
+ //
+ // redo memory size since it can change
+ //
+ Size = (15 * SIZE_1MB) >> 10;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Relocate this image under 4G memory for IPF.
+
+ @param ImageHandle Handle of driver image.
+ @param SystemTable Pointer to system table.
+
+ @retval EFI_SUCCESS Image successfully relocated.
+ @retval EFI_ABORTED Failed to relocate image.
+
+**/
+EFI_STATUS
+RelocateImageUnder4GIfNeeded (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c
new file mode 100644
index 0000000000..0fbf902813
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyCmos.c
@@ -0,0 +1,124 @@
+/** @file
+ This code fills in standard CMOS values and updates the standard CMOS
+ checksum. The Legacy16 code or LegacyBiosPlatform.c is responsible for
+ non-standard CMOS locations and non-standard checksums.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+/**
+ Read CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to read.
+
+ @return The data value from the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyReadStandardCmos (
+ IN UINT8 Index
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoRead8 (PORT_71);
+}
+
+/**
+ Write CMOS register through index/data port.
+
+ @param[in] Index The index of the CMOS register to write.
+ @param[in] Value The value of CMOS register to write.
+
+ @return The value written to the CMOS register specified by Index.
+
+**/
+UINT8
+LegacyWriteStandardCmos (
+ IN UINT8 Index,
+ IN UINT8 Value
+ )
+{
+ IoWrite8 (PORT_70, Index);
+ return IoWrite8 (PORT_71, Value);
+}
+
+/**
+ Calculate the new standard CMOS checksum and write it.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Calculate 16-bit checksum successfully
+
+**/
+EFI_STATUS
+LegacyCalculateWriteStandardCmosChecksum (
+ VOID
+ )
+{
+ UINT8 Register;
+ UINT16 Checksum;
+
+ for (Checksum = 0, Register = 0x10; Register < 0x2e; Register++) {
+ Checksum = (UINT16)(Checksum + LegacyReadStandardCmos (Register));
+ }
+ LegacyWriteStandardCmos (CMOS_2E, (UINT8)(Checksum >> 8));
+ LegacyWriteStandardCmos (CMOS_2F, (UINT8)(Checksum & 0xff));
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Fill in the standard CMOS stuff before Legacy16 load
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosInitCmos (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ UINT32 Size;
+
+ //
+ // Clear all errors except RTC lost power
+ //
+ LegacyWriteStandardCmos (CMOS_0E, (UINT8)(LegacyReadStandardCmos (CMOS_0E) & BIT7));
+
+ //
+ // Update CMOS locations 15,16,17,18,30,31 and 32
+ // CMOS 16,15 = 640Kb = 0x280
+ // CMOS 18,17 = 31,30 = 15Mb max in 1Kb increments =0x3C00 max
+ // CMOS 32 = 0x20
+ //
+ LegacyWriteStandardCmos (CMOS_15, 0x80);
+ LegacyWriteStandardCmos (CMOS_16, 0x02);
+
+ Size = 15 * SIZE_1MB;
+ if (Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb < (15 * SIZE_1MB)) {
+ Size = Private->IntThunk->EfiToLegacy16InitTable.OsMemoryAbove1Mb >> 10;
+ }
+
+ LegacyWriteStandardCmos (CMOS_17, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_30, (UINT8)(Size & 0xFF));
+ LegacyWriteStandardCmos (CMOS_18, (UINT8)(Size >> 8));
+ LegacyWriteStandardCmos (CMOS_31, (UINT8)(Size >> 8));
+
+ LegacyCalculateWriteStandardCmosChecksum ();
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c
new file mode 100644
index 0000000000..4d520f8a32
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyIde.c
@@ -0,0 +1,317 @@
+/** @file
+ Collect IDE information from Native EFI Driver
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+BOOLEAN mIdeDataBuiltFlag = FALSE;
+
+/**
+ Collect IDE Inquiry data from the IDE disks
+
+ @param Private Legacy BIOS Instance data
+ @param HddInfo Hdd Information
+ @param Flag Reconnect IdeController or not
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildIdeData (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN HDD_INFO **HddInfo,
+ IN UINT16 Flag
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE IdeController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ EFI_DISK_INFO_PROTOCOL *DiskInfo;
+ UINT32 IdeChannel;
+ UINT32 IdeDevice;
+ UINT32 Size;
+ UINT8 *InquiryData;
+ UINT32 InquiryDataSize;
+ HDD_INFO *LocalHddInfo;
+ UINT32 PciIndex;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePathNode;
+ PCI_DEVICE_PATH *PciDevicePath;
+
+ //
+ // Only build data once
+ // We have a problem with GetBbsInfo in that it can be invoked two
+ // places. Once in BDS, when all EFI drivers are connected and once in
+ // LegacyBoot after all EFI drivers are disconnected causing this routine
+ // to hang. In LegacyBoot this function is also called before EFI drivers
+ // are disconnected.
+ // Cases covered
+ // GetBbsInfo invoked in BDS. Both invocations in LegacyBoot ignored.
+ // GetBbsInfo not invoked in BDS. First invocation of this function
+ // proceeds normally and second via GetBbsInfo ignored.
+ //
+ PciDevicePath = NULL;
+ LocalHddInfo = *HddInfo;
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ if (!EFI_ERROR (Status)) {
+ IdeController = HandleBuffer[0];
+ //
+ // Force IDE drive spin up!
+ //
+ if (Flag != 0) {
+ gBS->DisconnectController (
+ IdeController,
+ NULL,
+ NULL
+ );
+ }
+
+ gBS->ConnectController (IdeController, NULL, NULL, FALSE);
+
+ //
+ // Do GetIdeHandle twice since disconnect/reconnect will switch to native mode
+ // And GetIdeHandle will switch to Legacy mode, if required.
+ //
+ Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ (VOID *) &LocalHddInfo
+ );
+ }
+
+ mIdeDataBuiltFlag = TRUE;
+
+ //
+ // Get Identity command from all drives
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDiskInfoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ Private->IdeDriveCount = (UINT8) HandleCount;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDiskInfoProtocolGuid,
+ (VOID **) &DiskInfo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (CompareGuid (&DiskInfo->Interface, &gEfiDiskInfoIdeInterfaceGuid)) {
+ //
+ // Locate which PCI device
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID *) &DevicePath
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ DevicePathNode = DevicePath;
+ while (!IsDevicePathEnd (DevicePathNode)) {
+ TempDevicePathNode = NextDevicePathNode (DevicePathNode);
+ if ((DevicePathType (DevicePathNode) == HARDWARE_DEVICE_PATH) &&
+ ( DevicePathSubType (DevicePathNode) == HW_PCI_DP) &&
+ ( DevicePathType(TempDevicePathNode) == MESSAGING_DEVICE_PATH) &&
+ ( DevicePathSubType(TempDevicePathNode) == MSG_ATAPI_DP) ) {
+ PciDevicePath = (PCI_DEVICE_PATH *) DevicePathNode;
+ break;
+ }
+ DevicePathNode = NextDevicePathNode (DevicePathNode);
+ }
+
+ if (PciDevicePath == NULL) {
+ continue;
+ }
+
+ //
+ // Find start of PCI device in HddInfo. The assumption of the data
+ // structure is 2 controllers(channels) per PCI device and each
+ // controller can have 2 drives(devices).
+ // HddInfo[PciIndex+0].[0] = Channel[0].Device[0] Primary Master
+ // HddInfo[PciIndex+0].[1] = Channel[0].Device[1] Primary Slave
+ // HddInfo[PciIndex+1].[0] = Channel[1].Device[0] Secondary Master
+ // HddInfo[PciIndex+1].[1] = Channel[1].Device[1] Secondary Slave
+ // @bug eventually need to pass in max number of entries
+ // for end of for loop
+ //
+ for (PciIndex = 0; PciIndex < 8; PciIndex++) {
+ if ((PciDevicePath->Device == LocalHddInfo[PciIndex].Device) &&
+ (PciDevicePath->Function == LocalHddInfo[PciIndex].Function)
+ ) {
+ break;
+ }
+ }
+
+ if (PciIndex == 8) {
+ continue;
+ }
+
+ Status = DiskInfo->WhichIde (DiskInfo, &IdeChannel, &IdeDevice);
+ if (!EFI_ERROR (Status)) {
+ Size = sizeof (ATAPI_IDENTIFY);
+ DiskInfo->Identify (
+ DiskInfo,
+ &LocalHddInfo[PciIndex + IdeChannel].IdentifyDrive[IdeDevice],
+ &Size
+ );
+ if (IdeChannel == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_PRIMARY;
+ } else if (IdeChannel == 1) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SECONDARY;
+ }
+
+ InquiryData = NULL;
+ InquiryDataSize = 0;
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ NULL,
+ &InquiryDataSize
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ InquiryData = (UINT8 *) AllocatePool (
+ InquiryDataSize
+ );
+ if (InquiryData != NULL) {
+ Status = DiskInfo->Inquiry (
+ DiskInfo,
+ InquiryData,
+ &InquiryDataSize
+ );
+ }
+ } else {
+ Status = EFI_DEVICE_ERROR;
+ }
+
+ //
+ // If ATAPI device then Inquiry will pass and ATA fail.
+ //
+ if (!EFI_ERROR (Status)) {
+ ASSERT (InquiryData != NULL);
+ //
+ // If IdeDevice = 0 then set master bit, else slave bit
+ //
+ if (IdeDevice == 0) {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_ATAPI_ZIPDISK;
+ }
+ } else {
+ if ((InquiryData[0] & 0x1f) == 0x05) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_CDROM;
+ } else if ((InquiryData[0] & 0x1f) == 0x00) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_ATAPI_ZIPDISK;
+ }
+ }
+ FreePool (InquiryData);
+ } else {
+ if (IdeDevice == 0) {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_MASTER_IDE;
+ } else {
+ LocalHddInfo[PciIndex + IdeChannel].Status |= HDD_SLAVE_IDE;
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ If the IDE channel is in compatibility (legacy) mode, remove all
+ PCI I/O BAR addresses from the controller.
+
+ @param IdeController The handle of target IDE controller
+
+
+**/
+VOID
+InitLegacyIdeController (
+ IN EFI_HANDLE IdeController
+ )
+{
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT32 IOBarClear;
+ EFI_STATUS Status;
+ PCI_TYPE00 PciData;
+
+ //
+ // If the IDE channel is in compatibility (legacy) mode, remove all
+ // PCI I/O BAR addresses from the controller. Some software gets
+ // confused if an IDE controller is in compatibility (legacy) mode
+ // and has PCI I/O resources allocated
+ //
+ Status = gBS->HandleProtocol (
+ IdeController,
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0, sizeof (PciData), &PciData);
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ //
+ // Check whether this is IDE
+ //
+ if ((PciData.Hdr.ClassCode[2] != PCI_CLASS_MASS_STORAGE) ||
+ (PciData.Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ return ;
+ }
+
+ //
+ // Clear bar for legacy IDE
+ //
+ IOBarClear = 0x00;
+ if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_PNE) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x10, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x14, 1, &IOBarClear);
+ }
+ if ((PciData.Hdr.ClassCode[0] & IDE_PI_REGISTER_SNE) == 0) {
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x18, 1, &IOBarClear);
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint32, 0x1C, 1, &IOBarClear);
+ }
+
+ return ;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
new file mode 100644
index 0000000000..9d84ab0000
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyPci.c
@@ -0,0 +1,3007 @@
+/** @file
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+#include <IndustryStandard/Pci30.h>
+
+#define PCI_START_ADDRESS(x) (((x) + 0x7ff) & ~0x7ff)
+
+#define MAX_BRIDGE_INDEX 0x20
+typedef struct {
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINT8 PrimaryBus;
+ UINT8 SecondaryBus;
+ UINT8 SubordinateBus;
+} BRIDGE_TABLE;
+
+#define ROM_MAX_ENTRIES 24
+BRIDGE_TABLE Bridges[MAX_BRIDGE_INDEX];
+UINTN SortedBridgeIndex[MAX_BRIDGE_INDEX];
+UINTN NumberOfBridges;
+LEGACY_PNP_EXPANSION_HEADER *mBasePnpPtr;
+UINT16 mBbsRomSegment;
+UINTN mHandleCount;
+EFI_HANDLE mVgaHandle;
+BOOLEAN mIgnoreBbsUpdateFlag;
+BOOLEAN mVgaInstallationInProgress = FALSE;
+UINT32 mRomCount = 0x00;
+ROM_INSTANCE_ENTRY mRomEntry[ROM_MAX_ENTRIES];
+
+
+/**
+ Query shadowed legacy ROM parameters registered by RomShadow() previously.
+
+ @param PciHandle PCI device whos ROM has been shadowed
+ @param DiskStart DiskStart value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param RomShadowAddress Address where ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+
+ @retval EFI_SUCCESS Query Logging successful.
+ @retval EFI_NOT_FOUND No logged data found about PciHandle.
+
+**/
+EFI_STATUS
+GetShadowedRomParameters (
+ IN EFI_HANDLE PciHandle,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINTN *ShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+
+ for(Index = 0; Index < mRomCount; Index++) {
+ if ((mRomEntry[Index].PciSegment == PciSegment) &&
+ (mRomEntry[Index].PciBus == PciBus) &&
+ (mRomEntry[Index].PciDevice == PciDevice) &&
+ (mRomEntry[Index].PciFunction == PciFunction)) {
+ break;
+ }
+ }
+
+ if (Index == mRomCount) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = mRomEntry[Index].DiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = mRomEntry[Index].DiskEnd;
+ }
+
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *)(UINTN)mRomEntry[Index].ShadowAddress;
+ }
+
+ if (ShadowedSize != NULL) {
+ *ShadowedSize = mRomEntry[Index].ShadowedSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Every legacy ROM that is shadowed by the Legacy BIOS driver will be
+ registered into this API so that the policy code can know what has
+ happend
+
+ @param PciHandle PCI device whos ROM is being shadowed
+ @param ShadowAddress Address that ROM was shadowed
+ @param ShadowedSize Runtime size of ROM
+ @param DiskStart DiskStart value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+ @param DiskEnd DiskEnd value from
+ EFI_LEGACY_BIOS_PROTOCOL.InstallPciRom
+
+ @retval EFI_SUCCESS Logging successful.
+ @retval EFI_OUT_OF_RESOURCES No remaining room for registering another option
+ ROM.
+
+**/
+EFI_STATUS
+RomShadow (
+ IN EFI_HANDLE PciHandle,
+ IN UINT32 ShadowAddress,
+ IN UINT32 ShadowedSize,
+ IN UINT8 DiskStart,
+ IN UINT8 DiskEnd
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+
+ //
+ // See if there is room to register another option ROM
+ //
+ if (mRomCount >= ROM_MAX_ENTRIES) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &mRomEntry[mRomCount].PciSegment,
+ &mRomEntry[mRomCount].PciBus,
+ &mRomEntry[mRomCount].PciDevice,
+ &mRomEntry[mRomCount].PciFunction
+ );
+ mRomEntry[mRomCount].ShadowAddress = ShadowAddress;
+ mRomEntry[mRomCount].ShadowedSize = ShadowedSize;
+ mRomEntry[mRomCount].DiskStart = DiskStart;
+ mRomEntry[mRomCount].DiskEnd = DiskEnd;
+
+ mRomCount++;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Return EFI_SUCCESS if PciHandle has had a legacy BIOS ROM shadowed. This
+ information represents every call to RomShadow ()
+
+ @param PciHandle PCI device to get status for
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No Legacy ROM loaded for this device
+
+**/
+EFI_STATUS
+IsLegacyRom (
+ IN EFI_HANDLE PciHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN Index;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+
+ //
+ // Get the PCI I/O Protocol on PciHandle
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the location of the PCI device
+ //
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+
+ //
+ // See if the option ROM from PciHandle has been previously posted
+ //
+ for (Index = 0; Index < mRomCount; Index++) {
+ if (mRomEntry[Index].PciSegment == Segment &&
+ mRomEntry[Index].PciBus == Bus &&
+ mRomEntry[Index].PciDevice == Device &&
+ mRomEntry[Index].PciFunction == Function
+ ) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Find the PC-AT ROM Image in the raw PCI Option ROM. Also return the
+ related information from the header.
+
+ @param Csm16Revision The PCI interface version of underlying CSM16
+ @param VendorId Vendor ID of the PCI device
+ @param DeviceId Device ID of the PCI device
+ @param Rom On input pointing to beginning of the raw PCI OpROM
+ On output pointing to the first legacy PCI OpROM
+ @param ImageSize On input is the size of Raw PCI Rom
+ On output is the size of the first legacy PCI ROM
+ @param MaxRuntimeImageLength The max runtime image length only valid if OpRomRevision >= 3
+ @param OpRomRevision Revision of the PCI Rom
+ @param ConfigUtilityCodeHeader Pointer to Configuration Utility Code Header
+
+ @retval EFI_SUCCESS Successfully find the legacy PCI ROM
+ @retval EFI_NOT_FOUND Failed to find the legacy PCI ROM
+
+**/
+EFI_STATUS
+GetPciLegacyRom (
+ IN UINT16 Csm16Revision,
+ IN UINT16 VendorId,
+ IN UINT16 DeviceId,
+ IN OUT VOID **Rom,
+ IN OUT UINTN *ImageSize,
+ OUT UINTN *MaxRuntimeImageLength, OPTIONAL
+ OUT UINT8 *OpRomRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ BOOLEAN Match;
+ UINT16 *DeviceIdList;
+ EFI_PCI_ROM_HEADER RomHeader;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+ VOID *BackupImage;
+ VOID *BestImage;
+
+
+ if (*ImageSize < sizeof (EFI_PCI_ROM_HEADER)) {
+ return EFI_NOT_FOUND;
+ }
+
+ BestImage = NULL;
+ BackupImage = NULL;
+ RomHeader.Raw = *Rom;
+ while (RomHeader.Generic->Signature == PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ if (RomHeader.Generic->PcirOffset == 0 ||
+ (RomHeader.Generic->PcirOffset & 3) !=0 ||
+ *ImageSize < RomHeader.Raw - (UINT8 *) *Rom + RomHeader.Generic->PcirOffset + sizeof (PCI_DATA_STRUCTURE)) {
+ break;
+ }
+
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+ //
+ // Check signature in the PCI Data Structure.
+ //
+ if (Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) {
+ break;
+ }
+
+ if ((UINTN)(RomHeader.Raw - (UINT8 *) *Rom) + Pcir->ImageLength * 512 > *ImageSize) {
+ break;
+ }
+
+ if (Pcir->CodeType == PCI_CODE_TYPE_PCAT_IMAGE) {
+ Match = FALSE;
+ if (Pcir->VendorId == VendorId) {
+ if (Pcir->DeviceId == DeviceId) {
+ Match = TRUE;
+ } else if ((Pcir->Revision >= 3) && (Pcir->DeviceListOffset != 0)) {
+ DeviceIdList = (UINT16 *)(((UINT8 *) Pcir) + Pcir->DeviceListOffset);
+ //
+ // Checking the device list
+ //
+ while (*DeviceIdList != 0) {
+ if (*DeviceIdList == DeviceId) {
+ Match = TRUE;
+ break;
+ }
+ DeviceIdList ++;
+ }
+ }
+ }
+
+ if (Match) {
+ if (Csm16Revision >= 0x0300) {
+ //
+ // Case 1: CSM16 3.0
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 1.1: meets OpRom 3.0
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ } else {
+ //
+ // case 1.2: meets OpRom 2.x
+ // Store it and try to find the OpRom 3.0
+ //
+ BackupImage = RomHeader.Raw;
+ }
+ } else {
+ //
+ // Case 2: CSM16 2.x
+ //
+ if (Pcir->Revision >= 3) {
+ //
+ // case 2.1: meets OpRom 3.0
+ // Store it and try to find the OpRom 2.x
+ //
+ BackupImage = RomHeader.Raw;
+ } else {
+ //
+ // case 2.2: meets OpRom 2.x
+ // Perfect!!!
+ //
+ BestImage = RomHeader.Raw;
+ break;
+ }
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "GetPciLegacyRom - OpRom not match (%04x-%04x)\n", (UINTN)VendorId, (UINTN)DeviceId));
+ }
+ }
+
+ if ((Pcir->Indicator & 0x80) == 0x80) {
+ break;
+ } else {
+ RomHeader.Raw += 512 * Pcir->ImageLength;
+ }
+ }
+
+ if (BestImage == NULL) {
+ if (BackupImage == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // The versions of CSM16 and OpRom don't match exactly
+ //
+ BestImage = BackupImage;
+ }
+ RomHeader.Raw = BestImage;
+ Pcir = (PCI_3_0_DATA_STRUCTURE *) (RomHeader.Raw + RomHeader.Generic->PcirOffset);
+ *Rom = BestImage;
+ *ImageSize = Pcir->ImageLength * 512;
+
+ if (MaxRuntimeImageLength != NULL) {
+ if (Pcir->Revision < 3) {
+ *MaxRuntimeImageLength = 0;
+ } else {
+ *MaxRuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+
+ if (OpRomRevision != NULL) {
+ //
+ // Optional return PCI Data Structure revision
+ //
+ if (Pcir->Length >= 0x1C) {
+ *OpRomRevision = Pcir->Revision;
+ } else {
+ *OpRomRevision = 0;
+ }
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ //
+ // Optional return ConfigUtilityCodeHeaderOffset supported by the PC-AT ROM
+ //
+ if ((Pcir->Revision < 3) || (Pcir->ConfigUtilityCodeHeaderOffset == 0)) {
+ *ConfigUtilityCodeHeader = NULL;
+ } else {
+ *ConfigUtilityCodeHeader = RomHeader.Raw + Pcir->ConfigUtilityCodeHeaderOffset;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build a table of bridge info for PIRQ translation.
+
+ @param RoutingTable RoutingTable obtained from Platform.
+ @param RoutingTableEntries Number of RoutingTable entries.
+
+ @retval EFI_SUCCESS New Subordinate bus.
+ @retval EFI_NOT_FOUND No more Subordinate busses.
+
+**/
+EFI_STATUS
+CreateBridgeTable (
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN BridgeIndex;
+ UINTN Index;
+ UINTN Index1;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ BRIDGE_TABLE SlotBridges[MAX_BRIDGE_INDEX];
+ UINTN SlotBridgeIndex;
+
+ BridgeIndex = 0x00;
+ SlotBridgeIndex = 0x00;
+
+ //
+ // Assumption is table is built from low bus to high bus numbers.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ if (IS_PCI_P2P (&PciConfigHeader) && (BridgeIndex < MAX_BRIDGE_INDEX)) {
+ PciIo->GetLocation (
+ PciIo,
+ &Bridges[BridgeIndex].PciSegment,
+ &Bridges[BridgeIndex].PciBus,
+ &Bridges[BridgeIndex].PciDevice,
+ &Bridges[BridgeIndex].PciFunction
+ );
+
+ Bridges[BridgeIndex].PrimaryBus = PciConfigHeader.Bridge.PrimaryBus;
+
+ Bridges[BridgeIndex].SecondaryBus = PciConfigHeader.Bridge.SecondaryBus;
+
+ Bridges[BridgeIndex].SubordinateBus = PciConfigHeader.Bridge.SubordinateBus;
+
+ for (Index1 = 0; Index1 < RoutingTableEntries; Index1++){
+ //
+ // Test whether we have found the Bridge in the slot, must be the one that directly interfaced to the board
+ // Once we find one, store it in the SlotBridges[]
+ //
+ if ((RoutingTable[Index1].Slot != 0) && (Bridges[BridgeIndex].PrimaryBus == RoutingTable[Index1].Bus)
+ && ((Bridges[BridgeIndex].PciDevice << 3) == RoutingTable[Index1].Device)) {
+ CopyMem (&SlotBridges[SlotBridgeIndex], &Bridges[BridgeIndex], sizeof (BRIDGE_TABLE));
+ SlotBridgeIndex++;
+
+ break;
+ }
+ }
+
+ ++BridgeIndex;
+ }
+ }
+
+ //
+ // Pack up Bridges by removing those useless ones
+ //
+ for (Index = 0; Index < BridgeIndex;){
+ for (Index1 = 0; Index1 < SlotBridgeIndex; Index1++) {
+ if (((Bridges[Index].PciBus == SlotBridges[Index1].PrimaryBus) && (Bridges[Index].PciDevice == SlotBridges[Index1].PciDevice)) ||
+ ((Bridges[Index].PciBus >= SlotBridges[Index1].SecondaryBus) && (Bridges[Index].PciBus <= SlotBridges[Index1].SubordinateBus))) {
+ //
+ // We have found one that meets our criteria
+ //
+ Index++;
+ break;
+ }
+ }
+
+ //
+ // This one doesn't meet criteria, pack it
+ //
+ if (Index1 >= SlotBridgeIndex) {
+ for (Index1 = Index; BridgeIndex > 1 && Index1 < BridgeIndex - 1 ; Index1++) {
+ CopyMem (&Bridges[Index1], &Bridges[Index1 + 1], sizeof (BRIDGE_TABLE));
+ }
+
+ BridgeIndex--;
+ }
+ }
+
+ NumberOfBridges = BridgeIndex;
+
+ //
+ // Sort bridges low to high by Secondary bus followed by subordinate bus
+ //
+ if (NumberOfBridges > 1) {
+ Index = 0;
+ do {
+ SortedBridgeIndex[Index] = Index;
+ ++Index;
+ } while (Index < NumberOfBridges);
+
+ for (Index = 0; Index < NumberOfBridges - 1; Index++) {
+ for (Index1 = Index + 1; Index1 < NumberOfBridges; Index1++) {
+ if (Bridges[Index].SecondaryBus > Bridges[Index1].SecondaryBus) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+
+ if ((Bridges[Index].SecondaryBus == Bridges[Index1].SecondaryBus) &&
+ (Bridges[Index].SubordinateBus > Bridges[Index1].SubordinateBus)
+ ) {
+ SortedBridgeIndex[Index] = Index1;
+ SortedBridgeIndex[Index1] = Index;
+ }
+ }
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find base Bridge for device.
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device.
+ @param PciDevice Input = Device.
+ @param RoutingTable The platform specific routing table
+ @param RoutingTableEntries Number of entries in table
+
+ @retval EFI_SUCCESS At base bus.
+ @retval EFI_NOT_FOUND Behind a bridge.
+
+**/
+EFI_STATUS
+GetBaseBus (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN UINTN PciBus,
+ IN UINTN PciDevice,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < RoutingTableEntries; Index++) {
+ if ((RoutingTable[Index].Bus == PciBus) && (RoutingTable[Index].Device == (PciDevice << 3))) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Translate PIRQ through busses
+
+ @param Private Legacy BIOS Instance data
+ @param PciBus Input = Bus of device. Output = Translated Bus
+ @param PciDevice Input = Device. Output = Translated Device
+ @param PciFunction Input = Function. Output = Translated Function
+ @param PirqIndex Input = Original PIRQ index. If single function
+ device then 0, otherwise 0-3.
+ Output = Translated Index
+
+ @retval EFI_SUCCESS Pirq successfully translated.
+ @retval EFI_NOT_FOUND The device is not behind any known bridge.
+
+**/
+EFI_STATUS
+TranslateBusPirq (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN OUT UINTN *PciBus,
+ IN OUT UINTN *PciDevice,
+ IN OUT UINTN *PciFunction,
+ IN OUT UINT8 *PirqIndex
+ )
+{
+ /*
+ This routine traverses the PCI busses from base slot
+ and translates the PIRQ register to the appropriate one.
+
+ Example:
+
+ Bus 0, Device 1 is PCI-PCI bridge that all PCI slots reside on.
+ Primary bus# = 0
+ Secondary bus # = 1
+ Subordinate bus # is highest bus # behind this bus
+ Bus 1, Device 0 is Slot 0 and is not a bridge.
+ Bus 1, Device 1 is Slot 1 and is a bridge.
+ Slot PIRQ routing is A,B,C,D.
+ Primary bus # = 1
+ Secondary bus # = 2
+ Subordinate bus # = 5
+ Bus 2, Device 6 is a bridge. It has no bridges behind it.
+ Primary bus # = 2
+ Secondary bus # = 3
+ Subordinate bus # = 3
+ Bridge PIRQ routing is C,D,A,B
+ Bus 2, Device 7 is a bridge. It has 1 bridge behind it.
+ Primary bus # = 2
+ Secondary bus = 4 Device 6 takes bus 2.
+ Subordinate bus = 5.
+ Bridge PIRQ routing is D,A,B,C
+ Bus 4, Device 2 is a bridge. It has no bridges behind it.
+ Primary bus # = 4
+ Secondary bus # = 5
+ Subordinate bus = 5
+ Bridge PIRQ routing is B,C,D,A
+ Bus 5, Device 1 is to be programmed.
+ Device PIRQ routing is C,D,A,B
+
+
+Search busses starting from slot bus for final bus >= Secondary bus and
+final bus <= Suborninate bus. Assumption is bus entries increase in bus
+number.
+Starting PIRQ is A,B,C,D.
+Bus 2, Device 7 satisfies search criteria. Rotate (A,B,C,D) left by device
+ 7 modulo 4 giving (D,A,B,C).
+Bus 4, Device 2 satisfies search criteria. Rotate (D,A,B,C) left by 2 giving
+ (B,C,D,A).
+No other busses match criteria. Device to be programmed is Bus 5, Device 1.
+Rotate (B,C,D,A) by 1 giving C,D,A,B. Translated PIRQ is C.
+
+*/
+ UINTN LocalBus;
+ UINTN LocalDevice;
+ UINTN BaseBus;
+ UINTN BaseDevice;
+ UINTN BaseFunction;
+ UINT8 LocalPirqIndex;
+ BOOLEAN BaseIndexFlag;
+ UINTN BridgeIndex;
+ UINTN SBridgeIndex;
+ BaseIndexFlag = FALSE;
+ BridgeIndex = 0x00;
+
+ LocalPirqIndex = *PirqIndex;
+ LocalBus = *PciBus;
+ LocalDevice = *PciDevice;
+ BaseBus = *PciBus;
+ BaseDevice = *PciDevice;
+ BaseFunction = *PciFunction;
+
+ //
+ // LocalPirqIndex list PIRQs in rotated fashion
+ // = 0 A,B,C,D
+ // = 1 B,C,D,A
+ // = 2 C,D,A,B
+ // = 3 D,A,B,C
+ //
+
+ for (BridgeIndex = 0; BridgeIndex < NumberOfBridges; BridgeIndex++) {
+ SBridgeIndex = SortedBridgeIndex[BridgeIndex];
+ //
+ // Check if device behind this bridge
+ //
+ if ((LocalBus >= Bridges[SBridgeIndex].SecondaryBus) && (LocalBus <= Bridges[SBridgeIndex].SubordinateBus)) {
+ //
+ // If BaseIndexFlag = FALSE then have found base bridge, i.e
+ // bridge in slot. Save info for use by IRQ routing table.
+ //
+ if (!BaseIndexFlag) {
+ BaseBus = Bridges[SBridgeIndex].PciBus;
+ BaseDevice = Bridges[SBridgeIndex].PciDevice;
+ BaseFunction = Bridges[SBridgeIndex].PciFunction;
+ BaseIndexFlag = TRUE;
+ } else {
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8)Bridges[SBridgeIndex].PciDevice)%4);
+ }
+
+ //
+ // Check if at device. If not get new PCI location & PIRQ
+ //
+ if (Bridges[SBridgeIndex].SecondaryBus == (UINT8) LocalBus) {
+ //
+ // Translate PIRQ
+ //
+ LocalPirqIndex = (UINT8) ((LocalPirqIndex + (UINT8) (LocalDevice)) % 4);
+ break;
+ }
+ }
+ }
+
+ //
+ // In case we fail to find the Bridge just above us, this is some potential error and we want to warn the user
+ //
+ if(BridgeIndex >= NumberOfBridges){
+ DEBUG ((EFI_D_ERROR, "Cannot Find IRQ Routing for Bus %d, Device %d, Function %d\n", *PciBus, *PciDevice, *PciFunction));
+ }
+
+ *PirqIndex = LocalPirqIndex;
+ *PciBus = BaseBus;
+ *PciDevice = BaseDevice;
+ *PciFunction = BaseFunction;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param RoutingTable Pointer to IRQ routing table
+ @param RoutingTableEntries IRQ routing table entries
+ @param PirqTable Pointer to $PIR table
+ @param PirqTableSize Length of table
+
+**/
+VOID
+CopyPirqTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable,
+ IN UINTN RoutingTableEntries,
+ IN EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable,
+ IN UINTN PirqTableSize
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT32 Granularity;
+
+ //
+ // Copy $PIR table, if it exists.
+ //
+ if (PirqTable != NULL) {
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->InternalIrqRoutingTable = RoutingTable;
+ Private->NumberIrqRoutingEntries = (UINT16) (RoutingTableEntries);
+ ZeroMem (&Regs, sizeof (EFI_IA32_REGISTER_SET));
+
+ Regs.X.AX = Legacy16GetTableAddress;
+ Regs.X.CX = (UINT16) PirqTableSize;
+ //
+ // Allocate at F segment according to PCI IRQ Routing Table Specification
+ //
+ Regs.X.BX = (UINT16) 0x1;
+ //
+ // 16-byte boundary alignment requirement according to
+ // PCI IRQ Routing Table Specification
+ //
+ Regs.X.DX = 0x10;
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Legacy16Table->IrqRoutingTablePointer = (UINT32) (Regs.X.DS * 16 + Regs.X.BX);
+ if (Regs.X.AX != 0) {
+ DEBUG ((EFI_D_ERROR, "PIRQ table length insufficient - %x\n", PirqTableSize));
+ } else {
+ DEBUG ((EFI_D_INFO, "PIRQ table in legacy region - %x\n", Private->Legacy16Table->IrqRoutingTablePointer));
+ Private->Legacy16Table->IrqRoutingTableLength = (UINT32)PirqTableSize;
+ CopyMem (
+ (VOID *) (UINTN)Private->Legacy16Table->IrqRoutingTablePointer,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ Private->PciInterruptLine = TRUE;
+ mHandleCount = 0;
+}
+
+/**
+ Dump EFI_LEGACY_INSTALL_PCI_HANDLER structure information.
+
+ @param PciHandle The pointer to EFI_LEGACY_INSTALL_PCI_HANDLER structure
+
+**/
+VOID
+DumpPciHandle (
+ IN EFI_LEGACY_INSTALL_PCI_HANDLER *PciHandle
+ )
+{
+ DEBUG ((EFI_D_INFO, "PciBus - %02x\n", (UINTN)PciHandle->PciBus));
+ DEBUG ((EFI_D_INFO, "PciDeviceFun - %02x\n", (UINTN)PciHandle->PciDeviceFun));
+ DEBUG ((EFI_D_INFO, "PciSegment - %02x\n", (UINTN)PciHandle->PciSegment));
+ DEBUG ((EFI_D_INFO, "PciClass - %02x\n", (UINTN)PciHandle->PciClass));
+ DEBUG ((EFI_D_INFO, "PciSubclass - %02x\n", (UINTN)PciHandle->PciSubclass));
+ DEBUG ((EFI_D_INFO, "PciInterface - %02x\n", (UINTN)PciHandle->PciInterface));
+
+ DEBUG ((EFI_D_INFO, "PrimaryIrq - %02x\n", (UINTN)PciHandle->PrimaryIrq));
+ DEBUG ((EFI_D_INFO, "PrimaryReserved - %02x\n", (UINTN)PciHandle->PrimaryReserved));
+ DEBUG ((EFI_D_INFO, "PrimaryControl - %04x\n", (UINTN)PciHandle->PrimaryControl));
+ DEBUG ((EFI_D_INFO, "PrimaryBase - %04x\n", (UINTN)PciHandle->PrimaryBase));
+ DEBUG ((EFI_D_INFO, "PrimaryBusMaster - %04x\n", (UINTN)PciHandle->PrimaryBusMaster));
+
+ DEBUG ((EFI_D_INFO, "SecondaryIrq - %02x\n", (UINTN)PciHandle->SecondaryIrq));
+ DEBUG ((EFI_D_INFO, "SecondaryReserved - %02x\n", (UINTN)PciHandle->SecondaryReserved));
+ DEBUG ((EFI_D_INFO, "SecondaryControl - %04x\n", (UINTN)PciHandle->SecondaryControl));
+ DEBUG ((EFI_D_INFO, "SecondaryBase - %04x\n", (UINTN)PciHandle->SecondaryBase));
+ DEBUG ((EFI_D_INFO, "SecondaryBusMaster - %04x\n", (UINTN)PciHandle->SecondaryBusMaster));
+ return;
+}
+
+/**
+ Copy the $PIR table as required.
+
+ @param Private Legacy BIOS Instance data
+ @param PciIo Pointer to PCI_IO protocol
+ @param PciIrq Pci IRQ number
+ @param PciConfigHeader Type00 Pci configuration header
+
+**/
+VOID
+InstallLegacyIrqHandler (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_PCI_IO_PROTOCOL *PciIo,
+ IN UINT8 PciIrq,
+ IN PCI_TYPE00 *PciConfigHeader
+ )
+{
+ EFI_IA32_REGISTER_SET Regs;
+ UINT16 LegMask;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ UINT16 PrimaryMaster;
+ UINT16 SecondaryMaster;
+ UINTN TempData;
+ UINTN RegisterAddress;
+ UINT32 Granularity;
+
+ PrimaryMaster = 0;
+ SecondaryMaster = 0;
+ Legacy8259 = Private->Legacy8259;
+ //
+ // Disable interrupt in PIC, in case shared, to prevent an
+ // interrupt from occuring.
+ //
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ NULL,
+ NULL,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ Private->IntThunk->PciHandler.PciBus = (UINT8) PciBus;
+ Private->IntThunk->PciHandler.PciDeviceFun = (UINT8) ((PciDevice << 3) + PciFunction);
+ Private->IntThunk->PciHandler.PciSegment = (UINT8) PciSegment;
+ Private->IntThunk->PciHandler.PciClass = PciConfigHeader->Hdr.ClassCode[2];
+ Private->IntThunk->PciHandler.PciSubclass = PciConfigHeader->Hdr.ClassCode[1];
+ Private->IntThunk->PciHandler.PciInterface = PciConfigHeader->Hdr.ClassCode[0];
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Primary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ Private->IntThunk->PciHandler.PrimaryBusMaster = (UINT16)(PciConfigHeader->Device.Bar[4] & 0xfffc);
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x01) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.PrimaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.PrimaryBase = (UINT16) (PciConfigHeader->Device.Bar[0] & 0xfffc);
+ Private->IntThunk->PciHandler.PrimaryControl = (UINT16) ((PciConfigHeader->Device.Bar[1] & 0xfffc) + 2);
+ } else {
+ Private->IntThunk->PciHandler.PrimaryIrq = 14;
+ Private->IntThunk->PciHandler.PrimaryBase = 0x1f0;
+ Private->IntThunk->PciHandler.PrimaryControl = 0x3f6;
+ }
+ //
+ // Secondary controller data
+ //
+ if (Private->IntThunk->PciHandler.PrimaryBusMaster != 0) {
+ Private->IntThunk->PciHandler.SecondaryBusMaster = (UINT16) ((PciConfigHeader->Device.Bar[4] & 0xfffc) + 8);
+ PrimaryMaster = (UINT16) (Private->IntThunk->PciHandler.PrimaryBusMaster + 2);
+ SecondaryMaster = (UINT16) (Private->IntThunk->PciHandler.SecondaryBusMaster + 2);
+
+ //
+ // Clear pending interrupts in Bus Master registers
+ //
+ IoWrite16 (PrimaryMaster, 0x04);
+ IoWrite16 (SecondaryMaster, 0x04);
+
+ }
+
+ //
+ // Use native mode base address registers in two cases:
+ // 1. Programming Interface (PI) register indicates Secondary Controller is
+ // in native mode OR
+ // 2. PCI device Sub Class Code is not IDE
+ //
+ if (((PciConfigHeader->Hdr.ClassCode[0] & 0x04) != 0) || (PciConfigHeader->Hdr.ClassCode[1] != PCI_CLASS_MASS_STORAGE_IDE)) {
+ Private->IntThunk->PciHandler.SecondaryIrq = PciIrq;
+ Private->IntThunk->PciHandler.SecondaryBase = (UINT16) (PciConfigHeader->Device.Bar[2] & 0xfffc);
+ Private->IntThunk->PciHandler.SecondaryControl = (UINT16) ((PciConfigHeader->Device.Bar[3] & 0xfffc) + 2);
+ } else {
+
+ Private->IntThunk->PciHandler.SecondaryIrq = 15;
+ Private->IntThunk->PciHandler.SecondaryBase = 0x170;
+ Private->IntThunk->PciHandler.SecondaryControl = 0x376;
+ }
+
+ //
+ // Clear pending interrupts in IDE Command Block Status reg before we
+ // Thunk to CSM16 below. Don't want a pending Interrupt before we
+ // install the handlers as wierd corruption would occur and hang system.
+ //
+ //
+ // Read IDE CMD blk status reg to clear out any pending interrupts.
+ // Do here for Primary and Secondary IDE channels
+ //
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.PrimaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+ RegisterAddress = (UINT16)Private->IntThunk->PciHandler.SecondaryBase + 0x07;
+ IoRead8 (RegisterAddress);
+
+ Private->IntThunk->PciHandler.PrimaryReserved = 0;
+ Private->IntThunk->PciHandler.SecondaryReserved = 0;
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Regs.X.AX = Legacy16InstallPciHandler;
+ TempData = (UINTN) &Private->IntThunk->PciHandler;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+
+ DumpPciHandle (&Private->IntThunk->PciHandler);
+
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+
+ Private->Cpu->FlushDataCache (Private->Cpu, 0xE0000, 0x20000, EfiCpuFlushTypeWriteBackInvalidate);
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+}
+
+
+/**
+ Program the interrupt routing register in all the PCI devices. On a PC AT system
+ this register contains the 8259 IRQ vector that matches it's PCI interrupt.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_ALREADY_STARTED All PCI devices have been processed.
+
+**/
+EFI_STATUS
+PciProgramAllInterruptLineRegisters (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_LEGACY_8259_PROTOCOL *Legacy8259;
+ EFI_LEGACY_INTERRUPT_PROTOCOL *LegacyInterrupt;
+ EFI_LEGACY_BIOS_PLATFORM_PROTOCOL *LegacyBiosPlatform;
+ UINT8 InterruptPin;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN MassStorageHandleCount;
+ EFI_HANDLE *MassStorageHandleBuffer;
+ UINTN MassStorageHandleIndex;
+ UINT8 PciIrq;
+ UINT16 Command;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ EFI_LEGACY_IRQ_ROUTING_ENTRY *RoutingTable;
+ UINTN RoutingTableEntries;
+ UINT16 LegMask;
+ UINT16 LegEdgeLevel;
+ PCI_TYPE00 PciConfigHeader;
+ EFI_LEGACY_PIRQ_TABLE_HEADER *PirqTable;
+ UINTN PirqTableSize;
+ UINTN Flags;
+ HDD_INFO *HddInfo;
+ UINT64 Supports;
+
+ //
+ // Note - This routine use to return immediately if Private->PciInterruptLine
+ // was true. Routine changed since resets etc can cause not all
+ // PciIo protocols to be registered the first time through.
+ // New algorithm is to do the copy $PIR table on first pass and save
+ // HandleCount on first pass. If subsequent passes LocateHandleBuffer gives
+ // a larger handle count then proceed with body of function else return
+ // EFI_ALREADY_STARTED. In addition check if PCI device InterruptLine != 0.
+ // If zero then function unprogrammed else skip function.
+ //
+ Legacy8259 = Private->Legacy8259;
+ LegacyInterrupt = Private->LegacyInterrupt;
+ LegacyBiosPlatform = Private->LegacyBiosPlatform;
+
+ LegacyBiosPlatform->GetRoutingTable (
+ Private->LegacyBiosPlatform,
+ (VOID *) &RoutingTable,
+ &RoutingTableEntries,
+ (VOID *) &PirqTable,
+ &PirqTableSize,
+ NULL,
+ NULL
+ );
+ CreateBridgeTable (RoutingTable, RoutingTableEntries);
+
+ if (!Private->PciInterruptLine) {
+ CopyPirqTable (
+ Private,
+ RoutingTable,
+ RoutingTableEntries,
+ PirqTable,
+ PirqTableSize
+ );
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ if (HandleCount == mHandleCount) {
+ FreePool (HandleBuffer);
+ return EFI_ALREADY_STARTED;
+ }
+
+ if (mHandleCount == 0x00) {
+ mHandleCount = HandleCount;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // If VGA then only do VGA to allow drives fore time to spin up
+ // otherwise assign PCI IRQs to all potential devices.
+ //
+ if ((mVgaInstallationInProgress) && (HandleBuffer[Index] != mVgaHandle)) {
+ continue;
+ } else {
+ //
+ // Force code to go through all handles next time called if video.
+ // This will catch case where HandleCount doesn't change but want
+ // to get drive info etc.
+ //
+ mHandleCount = 0x00;
+ }
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Test whether the device can be enabled or not.
+ // If it can't be enabled, then just skip it to avoid further operation.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command = PciConfigHeader.Hdr.Command;
+
+ //
+ // Note PciIo->Attributes does not program the PCI command register
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ PciIo->Pci.Write (PciIo, EfiPciIoWidthUint16, 0x04, 1, &Command);
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ InterruptPin = PciConfigHeader.Device.InterruptPin;
+
+ if ((InterruptPin != 0) && (PciConfigHeader.Device.InterruptLine == PCI_INT_LINE_UNKNOWN)) {
+ PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ //
+ // Translate PIRQ index back thru busses to slot bus with InterruptPin
+ // zero based
+ //
+ InterruptPin -= 1;
+
+ Status = GetBaseBus (
+ Private,
+ PciBus,
+ PciDevice,
+ RoutingTable,
+ RoutingTableEntries
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ TranslateBusPirq (
+ Private,
+ &PciBus,
+ &PciDevice,
+ &PciFunction,
+ &InterruptPin
+ );
+ }
+ //
+ // Translate InterruptPin(0-3) into PIRQ
+ //
+ Status = LegacyBiosPlatform->TranslatePirq (
+ LegacyBiosPlatform,
+ PciBus,
+ (PciDevice << 3),
+ PciFunction,
+ &InterruptPin,
+ &PciIrq
+ );
+ //
+ // TranslatePirq() should never fail or we are in trouble
+ // If it does return failure status, check your PIRQ routing table to see if some item is missing or incorrect
+ //
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Translate Pirq Failed - Status = %r\n ", Status));
+ continue;
+ }
+
+ LegacyInterrupt->WritePirq (
+ LegacyInterrupt,
+ InterruptPin,
+ PciIrq
+ );
+
+ //
+ // Check if device has an OPROM associated with it.
+ // If not invoke special 16-bit function, to allow 16-bit
+ // code to install an interrupt handler.
+ //
+ Status = LegacyBiosCheckPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ NULL,
+ &Flags
+ );
+ if ((EFI_ERROR (Status)) && (PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_MASS_STORAGE)) {
+ //
+ // Device has no OPROM associated with it and is a mass storage
+ // device. It needs to have an PCI IRQ handler installed. To
+ // correctly install the handler we need to insure device is
+ // connected. The device may just have register itself but not
+ // been connected. Re-read PCI config space after as it can
+ // change
+ //
+ //
+ // Get IDE Handle. If matches handle then skip ConnectController
+ // since ConnectController may force native mode and we don't
+ // want that for primary IDE controller
+ //
+ MassStorageHandleCount = 0;
+ MassStorageHandleBuffer = NULL;
+ LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIdeHandle,
+ 0,
+ &MassStorageHandleBuffer,
+ &MassStorageHandleCount,
+ NULL
+ );
+
+ HddInfo = &Private->IntThunk->EfiToLegacy16BootTable.HddInfo[0];
+
+ LegacyBiosBuildIdeData (Private, &HddInfo, 0);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ for (MassStorageHandleIndex = 0; MassStorageHandleIndex < MassStorageHandleCount; MassStorageHandleIndex++) {
+ if (MassStorageHandleBuffer[MassStorageHandleIndex] == HandleBuffer[Index]) {
+ //
+ // InstallLegacyIrqHandler according to Platform requirement
+ //
+ InstallLegacyIrqHandler (
+ Private,
+ PciIo,
+ PciIrq,
+ &PciConfigHeader
+ );
+ break;
+ }
+ }
+ }
+ //
+ // Write InterruptPin and enable 8259.
+ //
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x3c,
+ 1,
+ &PciIrq
+ );
+ Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask = (UINT16) (Private->IntThunk->EfiToLegacy16BootTable.PciIrqMask | (UINT16) (1 << PciIrq));
+
+ Legacy8259->GetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+
+ LegMask = (UINT16) (LegMask & (UINT16)~(1 << PciIrq));
+ LegEdgeLevel = (UINT16) (LegEdgeLevel | (UINT16) (1 << PciIrq));
+ Legacy8259->SetMask (
+ Legacy8259,
+ &LegMask,
+ &LegEdgeLevel,
+ NULL,
+ NULL
+ );
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Find & verify PnP Expansion header in ROM image
+
+ @param Private Protocol instance pointer.
+ @param FirstHeader 1 = Find first header, 0 = Find successive headers
+ @param PnpPtr Input Rom start if FirstHeader =1, Current Header
+ otherwise Output Next header, if it exists
+
+ @retval EFI_SUCCESS Next Header found at BasePnpPtr
+ @retval EFI_NOT_FOUND No more headers
+
+**/
+EFI_STATUS
+FindNextPnpExpansionHeader (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN BOOLEAN FirstHeader,
+ IN OUT LEGACY_PNP_EXPANSION_HEADER **PnpPtr
+
+ )
+{
+ UINTN TempData;
+ LEGACY_PNP_EXPANSION_HEADER *LocalPnpPtr;
+ LocalPnpPtr = *PnpPtr;
+ if (FirstHeader == FIRST_INSTANCE) {
+ mBasePnpPtr = LocalPnpPtr;
+ mBbsRomSegment = (UINT16) ((UINTN) mBasePnpPtr >> 4);
+ //
+ // Offset 0x1a gives offset to PnP expansion header for the first
+ // instance, there after the structure gives the offset to the next
+ // structure
+ //
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) ((UINT8 *) LocalPnpPtr + 0x1a);
+ TempData = (*((UINT16 *) LocalPnpPtr));
+ } else {
+ TempData = (UINT16) LocalPnpPtr->NextHeader;
+ }
+
+ LocalPnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) (((UINT8 *) mBasePnpPtr + TempData));
+
+ //
+ // Search for PnP table in Shadowed ROM
+ //
+ *PnpPtr = LocalPnpPtr;
+ if (*(UINT32 *) LocalPnpPtr == SIGNATURE_32 ('$', 'P', 'n', 'P')) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_NOT_FOUND;
+ }
+}
+
+
+/**
+ Update list of Bev or BCV table entries.
+
+ @param Private Protocol instance pointer.
+ @param RomStart Table of ROM start address in RAM/ROM. PciIo _
+ Handle to PCI IO for this device
+ @param PciIo Instance of PCI I/O Protocol
+
+ @retval EFI_SUCCESS Always should succeed.
+
+**/
+EFI_STATUS
+UpdateBevBcvTable (
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_LEGACY_EXPANSION_ROM_HEADER *RomStart,
+ IN EFI_PCI_IO_PROTOCOL *PciIo
+ )
+{
+ VOID *RomEnd;
+ BBS_TABLE *BbsTable;
+ UINTN BbsIndex;
+ EFI_LEGACY_EXPANSION_ROM_HEADER *PciPtr;
+ LEGACY_PNP_EXPANSION_HEADER *PnpPtr;
+ BOOLEAN Instance;
+ EFI_STATUS Status;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ UINT8 Class;
+ UINT16 DeviceType;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ Class = 0;
+ DeviceType = BBS_UNKNOWN;
+
+ //
+ // Skip floppy and 2*onboard IDE controller entries(Master/Slave per
+ // controller).
+ //
+ BbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+
+ BbsTable = (BBS_TABLE*)(UINTN) Private->IntThunk->EfiToLegacy16BootTable.BbsTable;
+ PnpPtr = (LEGACY_PNP_EXPANSION_HEADER *) RomStart;
+ PciPtr = (EFI_LEGACY_EXPANSION_ROM_HEADER *) RomStart;
+
+ RomEnd = (VOID *) (PciPtr->Size512 * 512 + (UINTN) PciPtr);
+ Instance = FIRST_INSTANCE;
+ //
+ // OPROMs like PXE may not be tied to a piece of hardware and thus
+ // don't have a PciIo associated with them
+ //
+ if (PciIo != NULL) {
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint8,
+ 0x0b,
+ 1,
+ &Class
+ );
+
+ if (Class == PCI_CLASS_MASS_STORAGE) {
+ DeviceType = BBS_HARDDISK;
+ } else {
+ if (Class == PCI_CLASS_NETWORK) {
+ DeviceType = BBS_EMBED_NETWORK;
+ }
+ }
+ }
+
+ while (TRUE) {
+ Status = FindNextPnpExpansionHeader (Private, Instance, &PnpPtr);
+ Instance = NOT_FIRST_INSTANCE;
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // There can be additional $PnP headers within the OPROM.
+ // Example: SCSI can have one per drive.
+ //
+ BbsTable[BbsIndex].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ BbsTable[BbsIndex].DeviceType = DeviceType;
+ BbsTable[BbsIndex].Bus = (UINT32) Bus;
+ BbsTable[BbsIndex].Device = (UINT32) Device;
+ BbsTable[BbsIndex].Function = (UINT32) Function;
+ BbsTable[BbsIndex].StatusFlags.OldPosition = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved1 = 0;
+ BbsTable[BbsIndex].StatusFlags.Enabled = 0;
+ BbsTable[BbsIndex].StatusFlags.Failed = 0;
+ BbsTable[BbsIndex].StatusFlags.MediaPresent = 0;
+ BbsTable[BbsIndex].StatusFlags.Reserved2 = 0;
+ BbsTable[BbsIndex].Class = PnpPtr->Class;
+ BbsTable[BbsIndex].SubClass = PnpPtr->SubClass;
+ BbsTable[BbsIndex].DescStringOffset = PnpPtr->ProductNamePointer;
+ BbsTable[BbsIndex].DescStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].MfgStringOffset = PnpPtr->MfgPointer;
+ BbsTable[BbsIndex].MfgStringSegment = mBbsRomSegment;
+ BbsTable[BbsIndex].BootHandlerSegment = mBbsRomSegment;
+
+ //
+ // Have seen case where PXE base code have PnP expansion ROM
+ // header but no Bcv or Bev vectors.
+ //
+ if (PnpPtr->Bcv != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bcv;
+ ++BbsIndex;
+ }
+
+ if (PnpPtr->Bev != 0) {
+ BbsTable[BbsIndex].BootHandlerOffset = PnpPtr->Bev;
+ BbsTable[BbsIndex].DeviceType = BBS_BEV_DEVICE;
+ ++BbsIndex;
+ }
+
+ if ((PnpPtr == (LEGACY_PNP_EXPANSION_HEADER *) PciPtr) || (PnpPtr > (LEGACY_PNP_EXPANSION_HEADER *) RomEnd)) {
+ break;
+ }
+ }
+
+ BbsTable[BbsIndex].BootPriority = BBS_IGNORE_ENTRY;
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT32) BbsIndex;
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Shadow all the PCI legacy ROMs. Use data from the Legacy BIOS Protocol
+ to chose the order. Skip any devices that have already have legacy
+ BIOS run.
+
+ @param Private Protocol instance pointer.
+
+ @retval EFI_SUCCESS Succeed.
+ @retval EFI_UNSUPPORTED Cannot get VGA device handle.
+
+**/
+EFI_STATUS
+PciShadowRoms (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 Pci;
+ UINTN Index;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE VgaHandle;
+ EFI_HANDLE FirstHandle;
+ VOID **RomStart;
+ UINTN Flags;
+ PCI_TYPE00 PciConfigHeader;
+ UINT16 *Command;
+ UINT64 Supports;
+
+ //
+ // Make the VGA device first
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Place the VGA handle as first.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+ if (HandleBuffer[Index] == VgaHandle) {
+ FirstHandle = HandleBuffer[0];
+ HandleBuffer[0] = HandleBuffer[Index];
+ HandleBuffer[Index] = FirstHandle;
+ break;
+ }
+ }
+ //
+ // Allocate memory to save Command WORD from each device. We do this
+ // to restore devices to same state as EFI after switching to legacy.
+ //
+ Command = (UINT16 *) AllocatePool (
+ sizeof (UINT16) * (HandleCount + 1)
+ );
+ if (NULL == Command) {
+ FreePool (HandleBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Disconnect all EFI devices first. This covers cases where alegacy BIOS
+ // may control multiple PCI devices.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Save command register for "connect" loop
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+ Command[Index] = PciConfigHeader.Hdr.Command;
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // Stop EFI Drivers with oprom.
+ //
+ gBS->DisconnectController (
+ HandleBuffer[Index],
+ NULL,
+ NULL
+ );
+ }
+ //
+ // For every device that has not had a legacy ROM started. Start a legacy ROM.
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Here make sure if one VGA have been shadowed,
+ // then wil not shadowed another one.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (Pci) / sizeof (UINT32),
+ &Pci
+ );
+
+ //
+ // Only one Video OPROM can be given control in BIOS phase. If there are multiple Video devices,
+ // one will work in legacy mode (OPROM will be given control) and
+ // other Video devices will work in native mode (OS driver will handle these devices).
+ //
+ if (IS_PCI_DISPLAY (&Pci) && Index != 0) {
+ continue;
+ }
+ //
+ // Skip any device that already has a legacy ROM run
+ //
+ Status = IsLegacyRom (HandleBuffer[Index]);
+ if (!EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // If legacy VBIOS Oprom has not been dispatched before, install legacy VBIOS here.
+ //
+ if (IS_PCI_DISPLAY (&Pci) && Index == 0) {
+ Status = LegacyBiosInstallVgaRom (Private);
+ //
+ // A return status of EFI_NOT_FOUND is considered valid (No EFI
+ // driver is controlling video).
+ //
+ ASSERT ((Status == EFI_SUCCESS) || (Status == EFI_NOT_FOUND));
+ continue;
+ }
+
+ //
+ // Install legacy ROM
+ //
+ Status = LegacyBiosInstallPciRom (
+ &Private->LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ &Flags,
+ NULL,
+ NULL,
+ (VOID **) &RomStart,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (!((Status == EFI_UNSUPPORTED) && (Flags == NO_ROM))) {
+ continue;
+ }
+ }
+ //
+ // Restore Command register so legacy has same devices enabled or disabled
+ // as EFI.
+ // If Flags = NO_ROM use command register as is. This covers the
+ // following cases:
+ // Device has no ROMs associated with it.
+ // Device has ROM associated with it but was already
+ // installed.
+ // = ROM_FOUND but not VALID_LEGACY_ROM, disable it.
+ // = ROM_FOUND and VALID_LEGACY_ROM, enable it.
+ //
+ if ((Flags & ROM_FOUND) == ROM_FOUND) {
+ if ((Flags & VALID_LEGACY_ROM) == 0) {
+ Command[Index] = 0;
+ } else {
+ //
+ // For several VGAs, only one of them can be enabled.
+ //
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)EFI_PCI_DEVICE_ENABLE;
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+ if (!EFI_ERROR (Status)) {
+ Command[Index] = 0x1f;
+ }
+ }
+ }
+
+ PciIo->Pci.Write (
+ PciIo,
+ EfiPciIoWidthUint16,
+ 0x04,
+ 1,
+ &Command[Index]
+ );
+ }
+
+ FreePool (Command);
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded
+ @param RomImage Return the legacy PCI ROM for this device
+ @param RomSize Size of ROM Image
+ @param Flags Indicates if ROM found and if PC-AT.
+
+ @retval EFI_SUCCESS Legacy Option ROM availible for this device
+ @retval EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosCheckPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *Flags
+ )
+{
+ return LegacyBiosCheckPciRomEx (
+ This,
+ PciHandle,
+ RomImage,
+ RomSize,
+ NULL,
+ Flags,
+ NULL,
+ NULL
+ );
+
+}
+
+/**
+
+ Routine Description:
+ Test to see if a legacy PCI ROM exists for this device. Optionally return
+ the Legacy ROM instance for this PCI device.
+
+ @param[in] This Protocol instance pointer.
+ @param[in] PciHandle The PCI PC-AT OPROM from this devices ROM BAR will be loaded
+ @param[out] RomImage Return the legacy PCI ROM for this device
+ @param[out] RomSize Size of ROM Image
+ @param[out] RuntimeImageLength Runtime size of ROM Image
+ @param[out] Flags Indicates if ROM found and if PC-AT.
+ @param[out] OpromRevision Revision of the PCI Rom
+ @param[out] ConfigUtilityCodeHeaderPointer of Configuration Utility Code Header
+
+ @return EFI_SUCCESS Legacy Option ROM availible for this device
+ @return EFI_ALREADY_STARTED This device is already managed by its Oprom
+ @return EFI_UNSUPPORTED Legacy Option ROM not supported.
+
+**/
+EFI_STATUS
+LegacyBiosCheckPciRomEx (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN EFI_HANDLE PciHandle,
+ OUT VOID **RomImage, OPTIONAL
+ OUT UINTN *RomSize, OPTIONAL
+ OUT UINTN *RuntimeImageLength, OPTIONAL
+ OUT UINTN *Flags, OPTIONAL
+ OUT UINT8 *OpromRevision, OPTIONAL
+ OUT VOID **ConfigUtilityCodeHeader OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINTN LocalRomSize;
+ VOID *LocalRomImage;
+ PCI_TYPE00 PciConfigHeader;
+ VOID *LocalConfigUtilityCodeHeader;
+
+ LocalConfigUtilityCodeHeader = NULL;
+ *Flags = NO_ROM;
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+ if (!EFI_ERROR (Status)) {
+ *Flags |= (UINTN)(ROM_FOUND | VALID_LEGACY_ROM);
+ return EFI_SUCCESS;
+ }
+ //
+ // Check for PCI ROM Bar
+ //
+ LocalRomSize = (UINTN) PciIo->RomSize;
+ LocalRomImage = PciIo->RomImage;
+ if (LocalRomSize != 0) {
+ *Flags |= ROM_FOUND;
+ }
+
+ //
+ // PCI specification states you should check VendorId and Device Id.
+ //
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ Status = GetPciLegacyRom (
+ Private->Csm16PciInterfaceVersion,
+ PciConfigHeader.Hdr.VendorId,
+ PciConfigHeader.Hdr.DeviceId,
+ &LocalRomImage,
+ &LocalRomSize,
+ RuntimeImageLength,
+ OpromRevision,
+ &LocalConfigUtilityCodeHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ *Flags |= VALID_LEGACY_ROM;
+
+ //
+ // See if Configuration Utility Code Header valid
+ //
+ if (LocalConfigUtilityCodeHeader != NULL) {
+ *Flags |= ROM_WITH_CONFIG;
+ }
+
+ if (ConfigUtilityCodeHeader != NULL) {
+ *ConfigUtilityCodeHeader = LocalConfigUtilityCodeHeader;
+ }
+
+ if (RomImage != NULL) {
+ *RomImage = LocalRomImage;
+ }
+
+ if (RomSize != NULL) {
+ *RomSize = LocalRomSize;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_NOT_FOUND No PS2 Keyboard found
+
+**/
+EFI_STATUS
+EnablePs2Keyboard (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ UINTN Index;
+
+ //
+ // Get SimpleTextIn and find PS2 controller
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ (VOID **) &IsaIo,
+ NULL,
+ HandleBuffer[Index],
+ EFI_OPEN_PROTOCOL_BY_HANDLE_PROTOCOL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Use the ISA I/O Protocol to see if Controller is the Keyboard
+ // controller
+ //
+ if (IsaIo->ResourceList->Device.HID != EISA_PNP_ID (0x303) || IsaIo->ResourceList->Device.UID != 0) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ gBS->CloseProtocol (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ HandleBuffer[Index]
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+ }
+ }
+ FreePool (HandleBuffer);
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM for VGA controller.
+
+ @param Private Driver private data.
+
+ @retval EFI_SUCCESS Legacy ROM successfully installed for this device.
+ @retval EFI_DEVICE_ERROR No VGA device handle found, or native EFI video
+ driver cannot be successfully disconnected, or VGA
+ thunk driver cannot be successfully connected.
+
+**/
+EFI_STATUS
+LegacyBiosInstallVgaRom (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE VgaHandle;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_HANDLE *ConnectHandleBuffer;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE00 PciConfigHeader;
+ UINT64 Supports;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ UINTN EntryCount;
+ UINTN Index;
+ VOID *Interface;
+
+ //
+ // EfiLegacyBiosGuild attached to a device implies that there is a legacy
+ // BIOS associated with that device.
+ //
+ // There are 3 cases to consider.
+ // Case 1: No EFI driver is controlling the video.
+ // Action: Return EFI_SUCCESS from DisconnectController, search
+ // video thunk driver, and connect it.
+ // Case 2: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // not on the image handle.
+ // Action: Disconnect EFI driver.
+ // ConnectController for video thunk
+ // Case 3: EFI driver is controlling the video and EfiLegacyBiosGuid is
+ // on the image handle.
+ // Action: Do nothing and set Private->VgaInstalled = TRUE.
+ // Then this routine is not called any more.
+ //
+ //
+ // Get the VGA device.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ VgaHandle = HandleBuffer[0];
+
+ //
+ // Check whether video thunk driver already starts.
+ //
+ Status = gBS->OpenProtocolInformation (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < EntryCount; Index++) {
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_DRIVER) != 0) {
+ Status = gBS->HandleProtocol (
+ OpenInfoBuffer[Index].AgentHandle,
+ &gEfiLegacyBiosGuid,
+ (VOID **) &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // This should be video thunk driver which is managing video device
+ // So it need not start again
+ //
+ DEBUG ((EFI_D_INFO, "Video thunk driver already start! Return!\n"));
+ Private->VgaInstalled = TRUE;
+ return EFI_SUCCESS;
+ }
+ }
+ }
+
+ //
+ // Kick off the native EFI driver
+ //
+ Status = gBS->DisconnectController (
+ VgaHandle,
+ NULL,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ return EFI_DEVICE_ERROR;
+ } else {
+ return Status;
+ }
+ }
+ //
+ // Find all the Thunk Driver
+ //
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLegacyBiosGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ ASSERT_EFI_ERROR (Status);
+ ConnectHandleBuffer = (EFI_HANDLE *) AllocatePool (sizeof (EFI_HANDLE) * (HandleCount + 1));
+ ASSERT (ConnectHandleBuffer != NULL);
+
+ CopyMem (
+ ConnectHandleBuffer,
+ HandleBuffer,
+ sizeof (EFI_HANDLE) * HandleCount
+ );
+ ConnectHandleBuffer[HandleCount] = NULL;
+
+ FreePool (HandleBuffer);
+
+ //
+ // Enable the device and make sure VGA cycles are being forwarded to this VGA device
+ //
+ Status = gBS->HandleProtocol (
+ VgaHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationSupported,
+ 0,
+ &Supports
+ );
+ if (!EFI_ERROR (Status)) {
+ Supports &= (UINT64)(EFI_PCI_DEVICE_ENABLE | EFI_PCI_IO_ATTRIBUTE_VGA_MEMORY | \
+ EFI_PCI_IO_ATTRIBUTE_VGA_IO | EFI_PCI_IO_ATTRIBUTE_VGA_IO_16);
+ Status = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ Supports,
+ NULL
+ );
+ }
+
+ if (Status == EFI_SUCCESS) {
+ Private->VgaInstalled = TRUE;
+
+ //
+ // Attach the VGA thunk driver.
+ // Assume the video is installed. This prevents potential of infinite recursion.
+ //
+ Status = gBS->ConnectController (
+ VgaHandle,
+ ConnectHandleBuffer,
+ NULL,
+ TRUE
+ );
+ }
+
+ FreePool (ConnectHandleBuffer);
+
+ if (EFI_ERROR (Status)) {
+
+ Private->VgaInstalled = FALSE;
+
+ //
+ // Reconnect the EFI VGA driver.
+ //
+ gBS->ConnectController (VgaHandle, NULL, NULL, TRUE);
+ return EFI_DEVICE_ERROR;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Load a legacy PC-AT OpROM.
+
+ @param This Protocol instance pointer.
+ @param Private Driver's private data.
+ @param PciHandle The EFI handle for the PCI device. It could be
+ NULL if the OpROM image is not associated with
+ any device.
+ @param OpromRevision The revision of PCI PC-AT ROM image.
+ @param RomImage Pointer to PCI PC-AT ROM image header. It must not
+ be NULL.
+ @param ImageSize Size of the PCI PC-AT ROM image.
+ @param RuntimeImageLength On input is the max runtime image length indicated by the PCIR structure
+ On output is the actual runtime image length
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_OUT_OF_RESOURCES No more space for this ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN LEGACY_BIOS_INSTANCE *Private,
+ IN EFI_HANDLE PciHandle,
+ IN UINT8 OpromRevision,
+ IN VOID *RomImage,
+ IN UINTN ImageSize,
+ IN OUT UINTN *RuntimeImageLength,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS PciEnableStatus;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 LocalDiskStart;
+ UINT8 LocalDiskEnd;
+ UINTN Segment;
+ UINTN Bus;
+ UINTN Device;
+ UINTN Function;
+ EFI_IA32_REGISTER_SET Regs;
+ UINT8 VideoMode;
+ EFI_TIME BootTime;
+ UINT32 *BdaPtr;
+ UINT32 LocalTime;
+ UINT32 StartBbsIndex;
+ UINT32 EndBbsIndex;
+ UINT32 MaxRomAddr;
+ UINTN TempData;
+ UINTN InitAddress;
+ UINTN RuntimeAddress;
+ EFI_PHYSICAL_ADDRESS PhysicalAddress;
+ UINT32 Granularity;
+
+ PciIo = NULL;
+ LocalDiskStart = 0;
+ LocalDiskEnd = 0;
+ Segment = 0;
+ Bus = 0;
+ Device = 0;
+ Function = 0;
+ VideoMode = 0;
+ PhysicalAddress = 0;
+ MaxRomAddr = PcdGet32 (PcdEndOpromShadowAddress);
+
+ if ((Private->Legacy16Table->TableLength >= OFFSET_OF(EFI_COMPATIBILITY16_TABLE, HiPermanentMemoryAddress)) &&
+ (Private->Legacy16Table->UmaAddress != 0) &&
+ (Private->Legacy16Table->UmaSize != 0) &&
+ (MaxRomAddr > (Private->Legacy16Table->UmaAddress))) {
+ MaxRomAddr = Private->Legacy16Table->UmaAddress;
+ }
+
+
+ PciProgramAllInterruptLineRegisters (Private);
+
+ if ((OpromRevision >= 3) && (Private->Csm16PciInterfaceVersion >= 0x0300)) {
+ //
+ // CSM16 3.0 meets PCI 3.0 OpROM
+ // first test if there is enough space for its INIT code
+ //
+ PhysicalAddress = CONVENTIONAL_MEMORY_TOP;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiBootServicesCode,
+ EFI_SIZE_TO_PAGES (ImageSize),
+ &PhysicalAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ //
+ // Report Status Code to indicate that there is no enough space for OpROM
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+ InitAddress = (UINTN) PhysicalAddress;
+ //
+ // then test if there is enough space for its RT code
+ //
+ RuntimeAddress = Private->OptionRom;
+ if (RuntimeAddress + *RuntimeImageLength > MaxRomAddr) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ //
+ // Report Status Code to indicate that there is no enough space for OpROM
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ // CSM16 3.0 meets PCI 2.x OpROM
+ // CSM16 2.x meets PCI 2.x/3.0 OpROM
+ // test if there is enough space for its INIT code
+ //
+ InitAddress = PCI_START_ADDRESS (Private->OptionRom);
+ if (InitAddress + ImageSize > MaxRomAddr) {
+ DEBUG ((EFI_D_ERROR, "return LegacyBiosInstallRom(%d): EFI_OUT_OF_RESOURCES (no more space for OpROM)\n", __LINE__));
+ //
+ // Report Status Code to indicate that there is no enough space for OpROM
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_LEGACY_OPROM_NO_SPACE)
+ );
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ RuntimeAddress = InitAddress;
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ (UINT32) RuntimeAddress,
+ (UINT32) ImageSize,
+ &Granularity
+ );
+
+ DEBUG ((EFI_D_INFO, " Shadowing OpROM init/runtime/isize = %x/%x/%x\n", InitAddress, RuntimeAddress, ImageSize));
+
+ CopyMem ((VOID *) InitAddress, RomImage, ImageSize);
+
+ //
+ // Read the highest disk number "installed: and assume a new disk will
+ // show up on the first drive past the current value.
+ // There are several considerations here:
+ // 1. Non-BBS compliant drives will change 40:75 but 16-bit CSM will undo
+ // the change until boot selection time frame.
+ // 2. BBS compliants drives will not change 40:75 until boot time.
+ // 3. Onboard IDE controllers will change 40:75
+ //
+ LocalDiskStart = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+ if ((Private->Disk4075 + 0x80) < LocalDiskStart) {
+ //
+ // Update table since onboard IDE drives found
+ //
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = 0xff;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = (UINT8) (Private->Disk4075 + 0x80);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = LocalDiskStart;
+ Private->LegacyEfiHddTableIndex ++;
+ Private->Disk4075 = (UINT8) (LocalDiskStart & 0x7f);
+ Private->DiskEnd = LocalDiskStart;
+ }
+
+ if (PciHandle != mVgaHandle) {
+
+ EnablePs2Keyboard ();
+
+ //
+ // Store current mode settings since PrepareToScanRom may change mode.
+ //
+ VideoMode = *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE));
+ }
+ //
+ // Notify the platform that we are about to scan the ROM
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookPrepareToScanRom,
+ 0,
+ PciHandle,
+ &InitAddress,
+ NULL,
+ NULL
+ );
+
+ //
+ // If Status returned is EFI_UNSUPPORTED then abort due to platform
+ // policy.
+ //
+ if (Status == EFI_UNSUPPORTED) {
+ goto Done;
+ }
+
+ //
+ // Report corresponding status code
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_CSM_LEGACY_ROM_INIT)
+ );
+
+ //
+ // Generate number of ticks since midnight for BDA. Some OPROMs require
+ // this. Place result in 40:6C-6F
+ //
+ gRT->GetTime (&BootTime, NULL);
+ LocalTime = BootTime.Hour * 3600 + BootTime.Minute * 60 + BootTime.Second;
+
+ //
+ // Multiply result by 18.2 for number of ticks since midnight.
+ // Use 182/10 to avoid floating point math.
+ //
+ LocalTime = (LocalTime * 182) / 10;
+ BdaPtr = (UINT32 *) ((UINTN) 0x46C);
+ *BdaPtr = LocalTime;
+
+ //
+ // Pass in handoff data
+ //
+ PciEnableStatus = EFI_UNSUPPORTED;
+ ZeroMem (&Regs, sizeof (Regs));
+ if (PciHandle != NULL) {
+
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Enable command register.
+ //
+ PciEnableStatus = PciIo->Attributes (
+ PciIo,
+ EfiPciIoAttributeOperationEnable,
+ EFI_PCI_DEVICE_ENABLE,
+ NULL
+ );
+
+ PciIo->GetLocation (
+ PciIo,
+ &Segment,
+ &Bus,
+ &Device,
+ &Function
+ );
+ DEBUG ((EFI_D_INFO, "Shadowing OpROM on the PCI device %x/%x/%x\n", Bus, Device, Function));
+ }
+
+ mIgnoreBbsUpdateFlag = FALSE;
+ Regs.X.AX = Legacy16DispatchOprom;
+
+ //
+ // Generate DispatchOpRomTable data
+ //
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckSegment = Private->Legacy16Table->PnPInstallationCheckSegment;
+ Private->IntThunk->DispatchOpromTable.PnPInstallationCheckOffset = Private->Legacy16Table->PnPInstallationCheckOffset;
+ Private->IntThunk->DispatchOpromTable.OpromSegment = (UINT16) (InitAddress >> 4);
+ Private->IntThunk->DispatchOpromTable.PciBus = (UINT8) Bus;
+ Private->IntThunk->DispatchOpromTable.PciDeviceFunction = (UINT8) ((Device << 3) | Function);
+ Private->IntThunk->DispatchOpromTable.NumberBbsEntries = (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ Private->IntThunk->DispatchOpromTable.BbsTablePointer = (UINT32) (UINTN) Private->BbsTablePtr;
+ Private->IntThunk->DispatchOpromTable.RuntimeSegment = (UINT16)((OpromRevision < 3) ? 0xffff : (RuntimeAddress >> 4));
+ TempData = (UINTN) &Private->IntThunk->DispatchOpromTable;
+ Regs.X.ES = EFI_SEGMENT ((UINT32) TempData);
+ Regs.X.BX = EFI_OFFSET ((UINT32) TempData);
+ //
+ // Skip dispatching ROM for those PCI devices that can not be enabled by PciIo->Attributes
+ // Otherwise, it may cause the system to hang in some cases
+ //
+ if (!EFI_ERROR (PciEnableStatus)) {
+ DEBUG ((EFI_D_INFO, " Legacy16DispatchOprom - %02x/%02x/%02x\n", Bus, Device, Function));
+ Private->LegacyBios.FarCall86 (
+ &Private->LegacyBios,
+ Private->Legacy16CallSegment,
+ Private->Legacy16CallOffset,
+ &Regs,
+ NULL,
+ 0
+ );
+ } else {
+ Regs.X.BX = 0;
+ }
+
+ if (Private->IntThunk->DispatchOpromTable.NumberBbsEntries != (UINT8) Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries) {
+ Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries = (UINT8) Private->IntThunk->DispatchOpromTable.NumberBbsEntries;
+ mIgnoreBbsUpdateFlag = TRUE;
+ }
+ //
+ // Check if non-BBS compliant drives found
+ //
+ if (Regs.X.BX != 0) {
+ LocalDiskEnd = (UINT8) (LocalDiskStart + Regs.H.BL);
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ //
+ // Skip video mode set, if installing VGA
+ //
+ if (PciHandle != mVgaHandle) {
+ //
+ // Set mode settings since PrepareToScanRom may change mode
+ //
+ if (VideoMode != *(UINT8 *) ((UINTN) (0x400 + BDA_VIDEO_MODE))) {
+ //
+ // The active video mode is changed, restore it to original mode.
+ //
+ Regs.H.AH = 0x00;
+ Regs.H.AL = VideoMode;
+ Private->LegacyBios.Int86 (&Private->LegacyBios, 0x10, &Regs);
+ }
+ }
+ //
+ // Regs.X.AX from the adapter initializion is ignored since some adapters
+ // do not follow the standard of setting AX = 0 on success.
+ //
+ //
+ // The ROM could have updated it's size so we need to read again.
+ //
+ if (((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE) {
+ //
+ // Now we check the signature (0xaa55) to judge whether the run-time code is truly generated by INIT function.
+ // If signature is not valid, that means the INIT function didn't copy the run-time code to RuntimeAddress.
+ //
+ *RuntimeImageLength = 0;
+ } else {
+ *RuntimeImageLength = ((EFI_LEGACY_EXPANSION_ROM_HEADER *) RuntimeAddress)->Size512 * 512;
+ }
+
+ DEBUG ((EFI_D_INFO, " fsize = %x\n", *RuntimeImageLength));
+
+ //
+ // If OpROM runs in 2.0 mode
+ //
+ if (PhysicalAddress == 0) {
+ if (*RuntimeImageLength < ImageSize) {
+ //
+ // Make area from end of shadowed rom to end of original rom all ffs
+ //
+ gBS->SetMem ((VOID *) (InitAddress + *RuntimeImageLength), ImageSize - *RuntimeImageLength, 0xff);
+ }
+ }
+
+ LocalDiskEnd = (UINT8) ((*(UINT8 *) ((UINTN) 0x475)) + 0x80);
+
+ //
+ // Allow platform to perform any required actions after the
+ // OPROM has been initialized.
+ //
+ Status = Private->LegacyBiosPlatform->PlatformHooks (
+ Private->LegacyBiosPlatform,
+ EfiPlatformHookAfterRomInit,
+ 0,
+ PciHandle,
+ &RuntimeAddress,
+ NULL,
+ NULL
+ );
+ if (PciHandle != NULL) {
+ //
+ // If no PCI Handle then no header or Bevs.
+ //
+ if ((*RuntimeImageLength != 0) && (!mIgnoreBbsUpdateFlag)) {
+ StartBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ TempData = RuntimeAddress;
+ UpdateBevBcvTable (
+ Private,
+ (EFI_LEGACY_EXPANSION_ROM_HEADER *) TempData,
+ PciIo
+ );
+ EndBbsIndex = Private->IntThunk->EfiToLegacy16BootTable.NumberBbsEntries;
+ LocalDiskEnd = (UINT8) (LocalDiskStart + (UINT8) (EndBbsIndex - StartBbsIndex));
+ if (LocalDiskEnd != LocalDiskStart) {
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciSegment = (UINT8) Segment;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciBus = (UINT8) Bus;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciDevice = (UINT8) Device;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].PciFunction = (UINT8) Function;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].StartDriveNumber = Private->DiskEnd;
+ Private->DiskEnd = LocalDiskEnd;
+ Private->LegacyEfiHddTable[Private->LegacyEfiHddTableIndex].EndDriveNumber = Private->DiskEnd;
+ Private->LegacyEfiHddTableIndex += 1;
+ }
+ }
+ //
+ // Mark PCI device as having a legacy BIOS ROM loaded.
+ //
+ RomShadow (
+ PciHandle,
+ (UINT32) RuntimeAddress,
+ (UINT32) *RuntimeImageLength,
+ LocalDiskStart,
+ LocalDiskEnd
+ );
+ }
+
+ //
+ // Stuff caller's OPTIONAL return parameters.
+ //
+ if (RomShadowAddress != NULL) {
+ *RomShadowAddress = (VOID *) RuntimeAddress;
+ }
+
+ if (DiskStart != NULL) {
+ *DiskStart = LocalDiskStart;
+ }
+
+ if (DiskEnd != NULL) {
+ *DiskEnd = LocalDiskEnd;
+ }
+
+ Private->OptionRom = (UINT32) (RuntimeAddress + *RuntimeImageLength);
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (PhysicalAddress != 0) {
+ //
+ // Free pages when OpROM is 3.0
+ //
+ gBS->FreePages (PhysicalAddress, EFI_SIZE_TO_PAGES (ImageSize));
+ }
+
+ //
+ // Insure all shadowed areas are locked
+ //
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xC0000,
+ 0x40000,
+ &Granularity
+ );
+
+ return Status;
+}
+
+/**
+ Load a legacy PC-AT OPROM on the PciHandle device. Return information
+ about how many disks were added by the OPROM and the shadow address and
+ size. DiskStart & DiskEnd are INT 13h drive letters. Thus 0x80 is C:
+
+ @param This Protocol instance pointer.
+ @param PciHandle The PCI PC-AT OPROM from this devices ROM BAR will
+ be loaded. This value is NULL if RomImage is
+ non-NULL. This is the normal case.
+ @param RomImage A PCI PC-AT ROM image. This argument is non-NULL
+ if there is no hardware associated with the ROM
+ and thus no PciHandle, otherwise is must be NULL.
+ Example is PXE base code.
+ @param Flags Indicates if ROM found and if PC-AT.
+ @param DiskStart Disk number of first device hooked by the ROM. If
+ DiskStart is the same as DiskEnd no disked were
+ hooked.
+ @param DiskEnd Disk number of the last device hooked by the ROM.
+ @param RomShadowAddress Shadow address of PC-AT ROM
+ @param RomShadowedSize Size of RomShadowAddress in bytes
+
+ @retval EFI_SUCCESS Legacy ROM loaded for this device
+ @retval EFI_INVALID_PARAMETER PciHandle not found
+ @retval EFI_UNSUPPORTED There is no PCI ROM in the ROM BAR or no onboard
+ ROM
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBiosInstallPciRom (
+ IN EFI_LEGACY_BIOS_PROTOCOL * This,
+ IN EFI_HANDLE PciHandle,
+ IN VOID **RomImage,
+ OUT UINTN *Flags,
+ OUT UINT8 *DiskStart, OPTIONAL
+ OUT UINT8 *DiskEnd, OPTIONAL
+ OUT VOID **RomShadowAddress, OPTIONAL
+ OUT UINT32 *RomShadowedSize OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ VOID *LocalRomImage;
+ UINTN ImageSize;
+ UINTN RuntimeImageLength;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ PCI_TYPE01 PciConfigHeader;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN PciSegment;
+ UINTN PciBus;
+ UINTN PciDevice;
+ UINTN PciFunction;
+ UINTN LastBus;
+ UINTN Index;
+ UINT8 OpromRevision;
+ UINT32 Granularity;
+ PCI_3_0_DATA_STRUCTURE *Pcir;
+
+ OpromRevision = 0;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+ if (Private->Legacy16Table->LastPciBus == 0) {
+ //
+ // Get last bus number if not already found
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ LastBus = 0;
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ Status = PciIo->GetLocation (
+ PciIo,
+ &PciSegment,
+ &PciBus,
+ &PciDevice,
+ &PciFunction
+ );
+ if (PciBus > LastBus) {
+ LastBus = PciBus;
+ }
+ }
+
+ Private->LegacyRegion->UnLock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ Private->Legacy16Table->LastPciBus = (UINT8) LastBus;
+ Private->LegacyRegion->Lock (
+ Private->LegacyRegion,
+ 0xE0000,
+ 0x20000,
+ &Granularity
+ );
+ }
+
+ *Flags = 0;
+ if ((PciHandle != NULL) && (RomImage == NULL)) {
+ //
+ // If PciHandle has OpRom to Execute
+ // and OpRom are all associated with Hardware
+ //
+ Status = gBS->HandleProtocol (
+ PciHandle,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo
+ );
+
+ if (!EFI_ERROR (Status)) {
+ PciIo->Pci.Read (
+ PciIo,
+ EfiPciIoWidthUint32,
+ 0,
+ sizeof (PciConfigHeader) / sizeof (UINT32),
+ &PciConfigHeader
+ );
+
+ //
+ // if video installed & OPROM is video return
+ //
+ if (
+ (
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_OLD) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_OLD_VGA))
+ ||
+ ((PciConfigHeader.Hdr.ClassCode[2] == PCI_CLASS_DISPLAY) &&
+ (PciConfigHeader.Hdr.ClassCode[1] == PCI_CLASS_DISPLAY_VGA))
+ )
+ &&
+ (!Private->VgaInstalled)
+ ) {
+ mVgaInstallationInProgress = TRUE;
+
+ //
+ // return EFI_UNSUPPORTED;
+ //
+ }
+ }
+ //
+ // To run any legacy image, the VGA needs to be installed first.
+ // if installing the video, then don't need the thunk as already installed.
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+
+ if (!EFI_ERROR (Status)) {
+ mVgaHandle = HandleBuffer[0];
+ if ((!Private->VgaInstalled) && (PciHandle != mVgaHandle)) {
+ //
+ // A return status of EFI_NOT_FOUND is considered valid (No EFI
+ // driver is controlling video.
+ //
+ mVgaInstallationInProgress = TRUE;
+ Status = LegacyBiosInstallVgaRom (Private);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+ }
+ } else {
+ mVgaInstallationInProgress = FALSE;
+ }
+ }
+ }
+ //
+ // See if the option ROM for PciHandle has already been executed
+ //
+ Status = IsLegacyRom (PciHandle);
+
+ if (!EFI_ERROR (Status)) {
+ mVgaInstallationInProgress = FALSE;
+ GetShadowedRomParameters (
+ PciHandle,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress,
+ (UINTN *) RomShadowedSize
+ );
+ return EFI_SUCCESS;
+ }
+
+ Status = LegacyBiosCheckPciRomEx (
+ &Private->LegacyBios,
+ PciHandle,
+ &LocalRomImage,
+ &ImageSize,
+ &RuntimeImageLength,
+ Flags,
+ &OpromRevision,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // There is no PCI ROM in the ROM BAR or no onboard ROM
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ if ((RomImage == NULL) || (*RomImage == NULL)) {
+ //
+ // If PciHandle is NULL, and no OpRom is to be associated
+ //
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformVgaHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ if ((!EFI_ERROR (Status)) && (!Private->VgaInstalled)) {
+ //
+ // A return status of EFI_NOT_FOUND is considered valid (No EFI
+ // driver is controlling video.
+ //
+ mVgaInstallationInProgress = TRUE;
+ Status = LegacyBiosInstallVgaRom (Private);
+ if (EFI_ERROR (Status)) {
+ if (Status != EFI_NOT_FOUND) {
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+ }
+ } else {
+ mVgaInstallationInProgress = FALSE;
+ }
+ }
+
+ LocalRomImage = *RomImage;
+ if (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->Signature != PCI_EXPANSION_ROM_HEADER_SIGNATURE ||
+ ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset == 0 ||
+ (((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset & 3 ) != 0) {
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
+ Pcir = (PCI_3_0_DATA_STRUCTURE *)
+ ((UINT8 *) LocalRomImage + ((PCI_EXPANSION_ROM_HEADER *) LocalRomImage)->PcirOffset);
+
+ if ((Pcir->Signature != PCI_DATA_STRUCTURE_SIGNATURE) || (Pcir->CodeType != PCI_CODE_TYPE_PCAT_IMAGE)) {
+ mVgaInstallationInProgress = FALSE;
+ return EFI_UNSUPPORTED;
+ }
+
+ ImageSize = Pcir->ImageLength * 512;
+ if (Pcir->Length >= 0x1C) {
+ OpromRevision = Pcir->Revision;
+ } else {
+ OpromRevision = 0;
+ }
+ if (Pcir->Revision < 3) {
+ RuntimeImageLength = 0;
+ } else {
+ RuntimeImageLength = Pcir->MaxRuntimeImageLength * 512;
+ }
+ }
+ //
+ // Shadow and initialize the OpROM.
+ //
+ ASSERT (Private->TraceIndex < 0x200);
+ Private->Trace[Private->TraceIndex] = LEGACY_PCI_TRACE_000;
+ Private->TraceIndex ++;
+ Private->TraceIndex = (UINT16) (Private->TraceIndex % 0x200);
+ Status = LegacyBiosInstallRom (
+ This,
+ Private,
+ PciHandle,
+ OpromRevision,
+ LocalRomImage,
+ ImageSize,
+ &RuntimeImageLength,
+ DiskStart,
+ DiskEnd,
+ RomShadowAddress
+ );
+ if (RomShadowedSize != NULL) {
+ *RomShadowedSize = (UINT32) RuntimeImageLength;
+ }
+
+ mVgaInstallationInProgress = FALSE;
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
new file mode 100644
index 0000000000..f82121c607
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacySio.c
@@ -0,0 +1,234 @@
+/** @file
+ Collect Sio information from Native EFI Drivers.
+ Sio is floppy, parallel, serial, ... hardware
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+
+/**
+ Collect EFI Info about legacy devices.
+
+ @param Private Legacy BIOS Instance data
+
+ @retval EFI_SUCCESS It should always work.
+
+**/
+EFI_STATUS
+LegacyBiosBuildSioData (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ DEVICE_PRODUCER_DATA_HEADER *SioPtr;
+ DEVICE_PRODUCER_SERIAL *Sio1Ptr;
+ DEVICE_PRODUCER_PARALLEL *Sio2Ptr;
+ DEVICE_PRODUCER_FLOPPY *Sio3Ptr;
+ EFI_HANDLE IsaBusController;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+ UINTN ResourceIndex;
+ UINTN ChildIndex;
+ EFI_ISA_IO_PROTOCOL *IsaIo;
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ EFI_ISA_ACPI_RESOURCE *IoResource;
+ EFI_ISA_ACPI_RESOURCE *DmaResource;
+ EFI_ISA_ACPI_RESOURCE *InterruptResource;
+ UINTN EntryCount;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ //
+ // Get the pointer to the SIO data structure
+ //
+ SioPtr = &Private->IntThunk->EfiToLegacy16BootTable.SioData;
+
+ //
+ // Zero the data in the SIO data structure
+ //
+ gBS->SetMem (SioPtr, sizeof (DEVICE_PRODUCER_DATA_HEADER), 0);
+
+ //
+ // Find the ISA Bus Controller used for legacy
+ //
+ Status = Private->LegacyBiosPlatform->GetPlatformHandle (
+ Private->LegacyBiosPlatform,
+ EfiGetPlatformIsaBusHandle,
+ 0,
+ &HandleBuffer,
+ &HandleCount,
+ NULL
+ );
+ IsaBusController = HandleBuffer[0];
+ if (!EFI_ERROR (Status)) {
+ //
+ // Force ISA Bus Controller to produce all ISA devices
+ //
+ gBS->ConnectController (IsaBusController, NULL, NULL, TRUE);
+ }
+ //
+ // Get the list of ISA controllers in the system
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiIsaIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+ //
+ // Collect legacy information from each of the ISA controllers in the system
+ //
+ for (Index = 0; Index < HandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiIsaIoProtocolGuid, (VOID **) &IsaIo);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ ResourceList = IsaIo->ResourceList;
+
+ if (ResourceList == NULL) {
+ continue;
+ }
+ //
+ // Collect the resource types neededto fill in the SIO data structure
+ //
+ IoResource = NULL;
+ DmaResource = NULL;
+ InterruptResource = NULL;
+ for (ResourceIndex = 0;
+ ResourceList->ResourceItem[ResourceIndex].Type != EfiIsaAcpiResourceEndOfList;
+ ResourceIndex++
+ ) {
+ switch (ResourceList->ResourceItem[ResourceIndex].Type) {
+ case EfiIsaAcpiResourceIo:
+ IoResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceMemory:
+ break;
+
+ case EfiIsaAcpiResourceDma:
+ DmaResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ case EfiIsaAcpiResourceInterrupt:
+ InterruptResource = &ResourceList->ResourceItem[ResourceIndex];
+ break;
+
+ default:
+ break;
+ }
+ }
+ //
+ // See if this is an ISA serial port
+ //
+ // Ignore DMA resource since it is always returned NULL
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x500) || ResourceList->Device.HID == EISA_PNP_ID (0x501)) {
+
+ if (ResourceList->Device.UID <= 3 &&
+ IoResource != NULL &&
+ InterruptResource != NULL
+ ) {
+ //
+ // Get the handle of the child device that has opened the ISA I/O Protocol
+ //
+ Status = gBS->OpenProtocolInformation (
+ HandleBuffer[Index],
+ &gEfiIsaIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ //
+ // We want resource for legacy even if no 32-bit driver installed
+ //
+ for (ChildIndex = 0; ChildIndex < EntryCount; ChildIndex++) {
+ Sio1Ptr = &SioPtr->Serial[ResourceList->Device.UID];
+ Sio1Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio1Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio1Ptr->Mode = DEVICE_SERIAL_MODE_NORMAL | DEVICE_SERIAL_MODE_DUPLEX_HALF;
+ }
+
+ FreePool (OpenInfoBuffer);
+ }
+ }
+ //
+ // See if this is an ISA parallel port
+ //
+ // Ignore DMA resource since it is always returned NULL, port
+ // only used in output mode.
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x400) || ResourceList->Device.HID == EISA_PNP_ID (0x401)) {
+ if (ResourceList->Device.UID <= 2 &&
+ IoResource != NULL &&
+ InterruptResource != NULL &&
+ DmaResource != NULL
+ ) {
+ Sio2Ptr = &SioPtr->Parallel[ResourceList->Device.UID];
+ Sio2Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio2Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio2Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio2Ptr->Mode = DEVICE_PARALLEL_MODE_MODE_OUTPUT_ONLY;
+ }
+ }
+ //
+ // See if this is an ISA floppy controller
+ //
+ if (ResourceList->Device.HID == EISA_PNP_ID (0x604)) {
+ if (IoResource != NULL && InterruptResource != NULL && DmaResource != NULL) {
+ Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiBlockIoProtocolGuid, (VOID **) &BlockIo);
+ if (!EFI_ERROR (Status)) {
+ Sio3Ptr = &SioPtr->Floppy;
+ Sio3Ptr->Address = (UINT16) IoResource->StartRange;
+ Sio3Ptr->Irq = (UINT8) InterruptResource->StartRange;
+ Sio3Ptr->Dma = (UINT8) DmaResource->StartRange;
+ Sio3Ptr->NumberOfFloppy++;
+ }
+ }
+ }
+ //
+ // See if this is a mouse
+ // Always set mouse found so USB hot plug will work
+ //
+ // Ignore lower byte of HID. Pnp0fxx is any type of mouse.
+ //
+ // Hid = ResourceList->Device.HID & 0xff00ffff;
+ // PnpId = EISA_PNP_ID(0x0f00);
+ // if (Hid == PnpId) {
+ // if (ResourceList->Device.UID == 1) {
+ // Status = gBS->HandleProtocol (HandleBuffer[Index], &gEfiSimplePointerProtocolGuid, &SimplePointer);
+ // if (!EFI_ERROR (Status)) {
+ //
+ SioPtr->MousePresent = 0x01;
+ //
+ // }
+ // }
+ // }
+ //
+ }
+
+ FreePool (HandleBuffer);
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
new file mode 100644
index 0000000000..3d9a8b9649
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/Thunk.c
@@ -0,0 +1,419 @@
+/** @file
+ Call into 16-bit BIOS code, Use AsmThunk16 function of BaseLib.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LegacyBiosInterface.h"
+
+THUNK_CONTEXT mThunkContext;
+
+/**
+ Sets the counter value for Timer #0 in a legacy 8254 timer.
+
+ @param Count - The 16-bit counter value to program into Timer #0 of the legacy 8254 timer.
+
+**/
+VOID
+SetPitCount (
+ IN UINT16 Count
+ )
+{
+ IoWrite8 (TIMER_CONTROL_PORT, TIMER0_CONTROL_WORD);
+ IoWrite8 (TIMER0_COUNT_PORT, (UINT8) (Count & 0xFF));
+ IoWrite8 (TIMER0_COUNT_PORT, (UINT8) ((Count>>8) & 0xFF));
+}
+
+/**
+ Thunk to 16-bit real mode and execute a software interrupt with a vector
+ of BiosInt. Regs will contain the 16-bit register context on entry and
+ exit.
+
+ @param This Protocol instance pointer.
+ @param BiosInt Processor interrupt vector to invoke
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosInt86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT8 BiosInt,
+ IN EFI_IA32_REGISTER_SET *Regs
+ )
+{
+ UINT32 *VectorBase;
+
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 0;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+ //
+ // The base address of legacy interrupt vector table is 0.
+ // We use this base address to get the legacy interrupt handler.
+ //
+ VectorBase = 0;
+
+ return InternalLegacyBiosFarCall (
+ This,
+ (UINT16) ((VectorBase)[BiosInt] >> 16),
+ (UINT16) (VectorBase)[BiosInt],
+ Regs,
+ &Regs->X.Flags,
+ sizeof (Regs->X.Flags)
+ );
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from
+ thunk to 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in
+ the target code. See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+LegacyBiosFarCall86 (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ Regs->X.Flags.Reserved1 = 1;
+ Regs->X.Flags.Reserved2 = 0;
+ Regs->X.Flags.Reserved3 = 0;
+ Regs->X.Flags.Reserved4 = 0;
+ Regs->X.Flags.IOPL = 3;
+ Regs->X.Flags.NT = 0;
+ Regs->X.Flags.IF = 1;
+ Regs->X.Flags.TF = 0;
+ Regs->X.Flags.CF = 0;
+
+ return InternalLegacyBiosFarCall (This, Segment, Offset, Regs, Stack, StackSize);
+}
+
+/**
+ Provide NULL interrupt handler which is used to check
+ if there is more than one HW interrupt registers with the CPU AP.
+
+ @param InterruptType - The type of interrupt that occured
+ @param SystemContext - A pointer to the system context when the interrupt occured
+
+**/
+VOID
+EFIAPI
+LegacyBiosNullInterruptHandler (
+ IN EFI_EXCEPTION_TYPE InterruptType,
+ IN EFI_SYSTEM_CONTEXT SystemContext
+ )
+{
+}
+
+/**
+ Thunk to 16-bit real mode and call Segment:Offset. Regs will contain the
+ 16-bit register context on entry and exit. Arguments can be passed on
+ the Stack argument
+
+ @param This Protocol instance pointer.
+ @param Segment Segemnt of 16-bit mode call
+ @param Offset Offset of 16-bit mdoe call
+ @param Regs Register contexted passed into (and returned) from thunk to
+ 16-bit mode
+ @param Stack Caller allocated stack used to pass arguments
+ @param StackSize Size of Stack in bytes
+
+ @retval FALSE Thunk completed, and there were no BIOS errors in the target code.
+ See Regs for status.
+ @retval TRUE There was a BIOS erro in the target code.
+
+**/
+BOOLEAN
+EFIAPI
+InternalLegacyBiosFarCall (
+ IN EFI_LEGACY_BIOS_PROTOCOL *This,
+ IN UINT16 Segment,
+ IN UINT16 Offset,
+ IN EFI_IA32_REGISTER_SET *Regs,
+ IN VOID *Stack,
+ IN UINTN StackSize
+ )
+{
+ UINTN Status;
+ LEGACY_BIOS_INSTANCE *Private;
+ UINT16 *Stack16;
+ EFI_TPL OriginalTpl;
+ IA32_REGISTER_SET ThunkRegSet;
+ BOOLEAN InterruptState;
+ UINT64 TimerPeriod;
+
+ Private = LEGACY_BIOS_INSTANCE_FROM_THIS (This);
+
+ ZeroMem (&ThunkRegSet, sizeof (ThunkRegSet));
+ ThunkRegSet.X.DI = Regs->X.DI;
+ ThunkRegSet.X.SI = Regs->X.SI;
+ ThunkRegSet.X.BP = Regs->X.BP;
+ ThunkRegSet.X.BX = Regs->X.BX;
+ ThunkRegSet.X.DX = Regs->X.DX;
+ //
+ // Sometimes, ECX is used to pass in 32 bit data. For example, INT 1Ah, AX = B10Dh is
+ // "PCI BIOS v2.0c + Write Configuration DWORD" and ECX has the dword to write.
+ //
+ ThunkRegSet.E.ECX = Regs->E.ECX;
+ ThunkRegSet.X.AX = Regs->X.AX;
+ ThunkRegSet.E.DS = Regs->X.DS;
+ ThunkRegSet.E.ES = Regs->X.ES;
+
+ CopyMem (&(ThunkRegSet.E.EFLAGS.UintN), &(Regs->X.Flags), sizeof (Regs->X.Flags));
+
+ //
+ // Clear the error flag; thunk code may set it. Stack16 should be the high address
+ // Make Statk16 address the low 16 bit must be not zero.
+ //
+ Stack16 = (UINT16 *)((UINT8 *) mThunkContext.RealModeBuffer + mThunkContext.RealModeBufferSize - sizeof (UINT16));
+
+ //
+ // Save current rate of DXE Timer
+ //
+ Private->Timer->GetTimerPeriod (Private->Timer, &TimerPeriod);
+
+ //
+ // Disable DXE Timer while executing in real mode
+ //
+ Private->Timer->SetTimerPeriod (Private->Timer, 0);
+
+ //
+ // Save and disable interrupt of debug timer
+ //
+ InterruptState = SaveAndSetDebugTimerInterrupt (FALSE);
+
+ //
+ // The call to Legacy16 is a critical section to EFI
+ //
+ OriginalTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ //
+ // Check to see if there is more than one HW interrupt registers with the CPU AP.
+ // If there is, then ASSERT() since that is not compatible with the CSM because
+ // interupts other than the Timer interrupt that was disabled above can not be
+ // handled properly from real mode.
+ //
+ DEBUG_CODE (
+ UINTN Vector;
+ UINTN Count;
+
+ for (Vector = 0x20, Count = 0; Vector < 0x100; Vector++) {
+ Status = Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, LegacyBiosNullInterruptHandler);
+ if (Status == EFI_ALREADY_STARTED) {
+ Count++;
+ }
+ if (Status == EFI_SUCCESS) {
+ Private->Cpu->RegisterInterruptHandler (Private->Cpu, Vector, NULL);
+ }
+ }
+ if (Count >= 2) {
+ DEBUG ((EFI_D_ERROR, "ERROR: More than one HW interrupt active with CSM enabled\n"));
+ }
+ ASSERT (Count < 2);
+ );
+
+ //
+ // If the Timer AP has enabled the 8254 timer IRQ and the current 8254 timer
+ // period is less than the CSM required rate of 54.9254, then force the 8254
+ // PIT counter to 0, which is the CSM required rate of 54.9254 ms
+ //
+ if (Private->TimerUses8254 && TimerPeriod < 549254) {
+ SetPitCount (0);
+ }
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy Stack to low memory stack
+ //
+ Stack16 -= StackSize / sizeof (UINT16);
+ CopyMem (Stack16, Stack, StackSize);
+ }
+
+ ThunkRegSet.E.SS = (UINT16) (((UINTN) Stack16 >> 16) << 12);
+ ThunkRegSet.E.ESP = (UINT16) (UINTN) Stack16;
+ ThunkRegSet.E.CS = Segment;
+ ThunkRegSet.E.Eip = Offset;
+
+ mThunkContext.RealModeState = &ThunkRegSet;
+
+ //
+ // Set Legacy16 state. 0x08, 0x70 is legacy 8259 vector bases.
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259LegacyMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ AsmThunk16 (&mThunkContext);
+
+ //
+ // OPROM may allocate EBDA range by itself and change EBDA base and EBDA size.
+ // Get the current EBDA base address, and compared with pre-allocate minimum
+ // EBDA base address, if the current EBDA base address is smaller, it indicates
+ // PcdEbdaReservedMemorySize should be adjusted to larger for more OPROMs.
+ //
+ DEBUG_CODE (
+ {
+ UINTN EbdaBaseAddress;
+ UINTN ReservedEbdaBaseAddress;
+
+ EbdaBaseAddress = (*(UINT16 *) (UINTN) 0x40E) << 4;
+ ReservedEbdaBaseAddress = CONVENTIONAL_MEMORY_TOP - PcdGet32 (PcdEbdaReservedMemorySize);
+ ASSERT (ReservedEbdaBaseAddress <= EbdaBaseAddress);
+ }
+ );
+
+ if (Stack != NULL && StackSize != 0) {
+ //
+ // Copy low memory stack to Stack
+ //
+ CopyMem (Stack, Stack16, StackSize);
+ }
+
+ //
+ // Restore protected mode interrupt state
+ //
+ Status = Private->Legacy8259->SetMode (Private->Legacy8259, Efi8259ProtectedMode, NULL, NULL);
+ ASSERT_EFI_ERROR (Status);
+
+ mThunkContext.RealModeState = NULL;
+
+ //
+ // Enable and restore rate of DXE Timer
+ //
+ Private->Timer->SetTimerPeriod (Private->Timer, TimerPeriod);
+
+ //
+ // End critical section
+ //
+ gBS->RestoreTPL (OriginalTpl);
+
+ //
+ // Restore interrupt of debug timer
+ //
+ SaveAndSetDebugTimerInterrupt (InterruptState);
+
+ Regs->E.EDI = ThunkRegSet.E.EDI;
+ Regs->E.ESI = ThunkRegSet.E.ESI;
+ Regs->E.EBP = ThunkRegSet.E.EBP;
+ Regs->E.EBX = ThunkRegSet.E.EBX;
+ Regs->E.EDX = ThunkRegSet.E.EDX;
+ Regs->E.ECX = ThunkRegSet.E.ECX;
+ Regs->E.EAX = ThunkRegSet.E.EAX;
+ Regs->X.SS = ThunkRegSet.E.SS;
+ Regs->X.CS = ThunkRegSet.E.CS;
+ Regs->X.DS = ThunkRegSet.E.DS;
+ Regs->X.ES = ThunkRegSet.E.ES;
+
+ CopyMem (&(Regs->X.Flags), &(ThunkRegSet.E.EFLAGS.UintN), sizeof (Regs->X.Flags));
+
+ return (BOOLEAN) (Regs->X.Flags.CF == 1);
+}
+
+/**
+ Allocate memory < 1 MB and copy the thunker code into low memory. Se up
+ all the descriptors.
+
+ @param Private Private context for Legacy BIOS
+
+ @retval EFI_SUCCESS Should only pass.
+
+**/
+EFI_STATUS
+LegacyBiosInitializeThunk (
+ IN LEGACY_BIOS_INSTANCE *Private
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS MemoryAddress;
+ UINT8 TimerVector;
+
+ MemoryAddress = (EFI_PHYSICAL_ADDRESS) (UINTN) Private->IntThunk;
+
+ mThunkContext.RealModeBuffer = (VOID *) (UINTN) (MemoryAddress + ((sizeof (LOW_MEMORY_THUNK) / EFI_PAGE_SIZE) + 1) * EFI_PAGE_SIZE);
+ mThunkContext.RealModeBufferSize = EFI_PAGE_SIZE;
+ mThunkContext.ThunkAttributes = THUNK_ATTRIBUTE_BIG_REAL_MODE | THUNK_ATTRIBUTE_DISABLE_A20_MASK_INT_15;
+
+ AsmPrepareThunk16 (&mThunkContext);
+
+ //
+ // Get the interrupt vector number corresponding to IRQ0 from the 8259 driver
+ //
+ TimerVector = 0;
+ Status = Private->Legacy8259->GetVector (Private->Legacy8259, Efi8259Irq0, &TimerVector);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Check to see if the Timer AP has hooked the IRQ0 from the 8254 PIT
+ //
+ Status = Private->Cpu->RegisterInterruptHandler (
+ Private->Cpu,
+ TimerVector,
+ LegacyBiosNullInterruptHandler
+ );
+ if (Status == EFI_SUCCESS) {
+ //
+ // If the Timer AP has not enabled the 8254 timer IRQ, then force the 8254 PIT
+ // counter to 0, which is the CSM required rate of 54.9254 ms
+ //
+ Private->Cpu->RegisterInterruptHandler (
+ Private->Cpu,
+ TimerVector,
+ NULL
+ );
+ SetPitCount (0);
+
+ //
+ // Save status that the Timer AP is not using the 8254 PIT
+ //
+ Private->TimerUses8254 = FALSE;
+ } else if (Status == EFI_ALREADY_STARTED) {
+ //
+ // Save status that the Timer AP is using the 8254 PIT
+ //
+ Private->TimerUses8254 = TRUE;
+ } else {
+ //
+ // Unexpected status from CPU AP RegisterInterruptHandler()
+ //
+ ASSERT (FALSE);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S
new file mode 100644
index 0000000000..0c9ce01d5b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.S
@@ -0,0 +1,72 @@
+## @file
+# Interrupt Redirection Template
+#
+# Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+#text SEGMENT
+
+
+#----------------------------------------------------------------------------
+# Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+#
+# Input: None
+#
+# Output: None
+#
+# Prototype: VOID
+# InterruptRedirectionTemplate (
+# VOID
+# );
+#
+# Saves: None
+#
+# Modified: None
+#
+# Description: Contains the code that is copied into low memory (below 640K).
+# This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+# This template must be copied into low memory, and the IDT entries
+# 0x68-0x6F must be point to the low memory copy of this code. Each
+# entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+# computed.
+#
+#----------------------------------------------------------------------------
+
+ASM_GLOBAL ASM_PFX(InterruptRedirectionTemplate)
+ASM_PFX(InterruptRedirectionTemplate):
+ int $0x08
+ .byte 0x0cf # IRET
+ nop
+ int $0x09
+ .byte 0x0cf # IRET
+ nop
+ int $0x0a
+ .byte 0x0cf # IRET
+ nop
+ int $0x0b
+ .byte 0x0cf # IRET
+ nop
+ int $0x0c
+ .byte 0x0cf # IRET
+ nop
+ int $0x0d
+ .byte 0x0cf # IRET
+ nop
+ int $0x0e
+ .byte 0x0cf # IRET
+ nop
+ int $0x0f
+ .byte 0x0cf # IRET
+ nop
+
+#END
diff --git a/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm
new file mode 100644
index 0000000000..750423e5b7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Csm/LegacyBiosDxe/X64/InterruptTable.asm
@@ -0,0 +1,71 @@
+;; @file
+; Interrupt Redirection Template
+;
+; Copyright (c) 2006, Intel Corporation. All rights reserved.<BR>
+;
+; This program and the accompanying materials
+; are licensed and made available under the terms and conditions
+; of the BSD License which accompanies this distribution. The
+; full text of the license may be found at
+; http://opensource.org/licenses/bsd-license.php
+;
+; THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+; WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+;
+;;
+
+text SEGMENT
+
+;----------------------------------------------------------------------------
+; Procedure: InterruptRedirectionTemplate: Redirects interrupts 0x68-0x6F
+;
+; Input: None
+;
+; Output: None
+;
+; Prototype: VOID
+; InterruptRedirectionTemplate (
+; VOID
+; );
+;
+; Saves: None
+;
+; Modified: None
+;
+; Description: Contains the code that is copied into low memory (below 640K).
+; This code reflects interrupts 0x68-0x6f to interrupts 0x08-0x0f.
+; This template must be copied into low memory, and the IDT entries
+; 0x68-0x6F must be point to the low memory copy of this code. Each
+; entry is 4 bytes long, so IDT entries 0x68-0x6F can be easily
+; computed.
+;
+;----------------------------------------------------------------------------
+
+InterruptRedirectionTemplate PROC
+ int 08h
+ DB 0cfh ; IRET
+ nop
+ int 09h
+ DB 0cfh ; IRET
+ nop
+ int 0ah
+ DB 0cfh ; IRET
+ nop
+ int 0bh
+ DB 0cfh ; IRET
+ nop
+ int 0ch
+ DB 0cfh ; IRET
+ nop
+ int 0dh
+ DB 0cfh ; IRET
+ nop
+ int 0eh
+ DB 0cfh ; IRET
+ nop
+ int 0fh
+ DB 0cfh ; IRET
+ nop
+InterruptRedirectionTemplate ENDP
+
+END \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/AcpiVariableCompatibility.h b/Core/IntelFrameworkModulePkg/Include/Guid/AcpiVariableCompatibility.h
new file mode 100644
index 0000000000..6c9f851543
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/AcpiVariableCompatibility.h
@@ -0,0 +1,69 @@
+/** @file
+ Definitions for data structures used in S3 resume.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ACPI_VARIABLE_COMPATIBILITY_H_
+#define _ACPI_VARIABLE_COMPATIBILITY_H_
+
+#define EFI_ACPI_VARIABLE_COMPATIBILITY_GUID \
+ { \
+ 0xc020489e, 0x6db2, 0x4ef2, {0x9a, 0xa5, 0xca, 0x6, 0xfc, 0x11, 0xd3, 0x6a } \
+ }
+
+#define ACPI_GLOBAL_VARIABLE L"AcpiGlobalVariable"
+
+extern EFI_GUID gEfiAcpiVariableCompatiblityGuid;
+
+typedef struct {
+ BOOLEAN APState;
+ BOOLEAN S3BootPath;
+ EFI_PHYSICAL_ADDRESS WakeUpBuffer;
+ EFI_PHYSICAL_ADDRESS GdtrProfile;
+ EFI_PHYSICAL_ADDRESS IdtrProfile;
+ EFI_PHYSICAL_ADDRESS CpuPrivateData;
+ EFI_PHYSICAL_ADDRESS StackAddress;
+ EFI_PHYSICAL_ADDRESS MicrocodePointerBuffer;
+ EFI_PHYSICAL_ADDRESS SmramBase;
+ EFI_PHYSICAL_ADDRESS SmmStartImageBase;
+ UINT32 SmmStartImageSize;
+ UINT32 NumberOfCpus;
+} ACPI_CPU_DATA_COMPATIBILITY;
+
+typedef struct {
+ //
+ // Acpi Related variables
+ //
+ EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase;
+ UINT32 AcpiReservedMemorySize;
+ EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase;
+ EFI_PHYSICAL_ADDRESS AcpiBootScriptTable;
+ EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase;
+ EFI_PHYSICAL_ADDRESS AcpiFacsTable;
+ UINT64 SystemMemoryLength;
+ ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData;
+ //
+ // VGA OPROM to support Video Re-POST for Linux S3
+ //
+ EFI_PHYSICAL_ADDRESS VideoOpromAddress;
+ UINT32 VideoOpromSize;
+
+ //
+ // S3 Debug extension
+ //
+ EFI_PHYSICAL_ADDRESS S3DebugBufferAddress;
+ EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint;
+} ACPI_VARIABLE_SET_COMPATIBILITY;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/BdsHii.h b/Core/IntelFrameworkModulePkg/Include/Guid/BdsHii.h
new file mode 100644
index 0000000000..e22babc5b6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/BdsHii.h
@@ -0,0 +1,55 @@
+/** @file
+ GUIDs used as HII FormSet and HII Package list GUID in BdsDxe driver.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __BDS_HII_GUIDS_H__
+#define __BDS_HII_GUIDS_H__
+
+#define FRONT_PAGE_FORMSET_GUID \
+ { \
+ 0x9e0c30bc, 0x3f06, 0x4ba6, {0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe} \
+ }
+
+#define BOOT_MANAGER_FORMSET_GUID \
+ { \
+ 0x847bc3fe, 0xb974, 0x446d, {0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b} \
+ }
+
+#define DEVICE_MANAGER_FORMSET_GUID \
+ { \
+ 0x3ebfa8e6, 0x511d, 0x4b5b, {0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27} \
+ }
+
+#define DRIVER_HEALTH_FORMSET_GUID \
+ { \
+ 0xf76e0a70, 0xb5ed, 0x4c38, {0xac, 0x9a, 0xe5, 0xf5, 0x4b, 0xf1, 0x6e, 0x34} \
+ }
+
+#define BOOT_MAINT_FORMSET_GUID \
+ { \
+ 0x642237c7, 0x35d4, 0x472d, {0x83, 0x65, 0x12, 0xe0, 0xcc, 0xf2, 0x7a, 0x22} \
+ }
+
+#define FILE_EXPLORE_FORMSET_GUID \
+ { \
+ 0x1f2d63e1, 0xfebd, 0x4dc7, {0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, 0x5b} \
+ }
+
+extern EFI_GUID gFrontPageFormSetGuid;
+extern EFI_GUID gBootMaintFormSetGuid;
+extern EFI_GUID gFileExploreFormSetGuid;
+extern EFI_GUID gBootManagerFormSetGuid;
+extern EFI_GUID gDeviceManagerFormSetGuid;
+extern EFI_GUID gDriverHealthFormSetGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/BdsLibHii.h b/Core/IntelFrameworkModulePkg/Include/Guid/BdsLibHii.h
new file mode 100644
index 0000000000..1a2bb024c4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/BdsLibHii.h
@@ -0,0 +1,25 @@
+/** @file
+ GUID used as HII Package list GUID in GenericBdsLib module.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __BDS_LIB_HII_GUID_H__
+#define __BDS_LIB_HII_GUID_H__
+
+#define BDS_LIB_STRING_PACKAGE_GUID \
+ { \
+ 0x3b4d9b23, 0x95ac, 0x44f6, { 0x9f, 0xcd, 0xe, 0x95, 0x94, 0x58, 0x6c, 0x72 } \
+ }
+
+extern EFI_GUID gBdsLibStringPackageGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/BlockIoVendor.h b/Core/IntelFrameworkModulePkg/Include/Guid/BlockIoVendor.h
new file mode 100644
index 0000000000..71aa05a595
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/BlockIoVendor.h
@@ -0,0 +1,31 @@
+/** @file
+ Guid for unrecognized EDD 3.0 device.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __BLOCKIO_VENDOR_H__
+#define __BLOCKIO_VENDOR_H__
+
+//
+// Guid is to specifiy the unrecognized EDD 3.0 device.
+//
+#define BLOCKIO_VENDOR_GUID \
+ { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b} }
+
+typedef struct {
+ VENDOR_DEVICE_PATH DevicePath;
+ UINT8 LegacyDriveLetter;
+} BLOCKIO_VENDOR_DEVICE_PATH;
+
+extern GUID gBlockIoVendorGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/CapsuleDataFile.h b/Core/IntelFrameworkModulePkg/Include/Guid/CapsuleDataFile.h
new file mode 100644
index 0000000000..7e97d17f23
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/CapsuleDataFile.h
@@ -0,0 +1,23 @@
+/** @file
+ GUID to specify which FFS file to store the updated capsule data.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UPDATE_DATA_FILE_GUID_H__
+#define __UPDATE_DATA_FILE_GUID_H__
+
+#define EFI_UPDATE_DATA_FILE_GUID \
+ { 0x283fa2ee, 0x532c, 0x484d, { 0x93, 0x83, 0x9f, 0x93, 0xb3, 0x6f, 0xb, 0x7e } }
+
+extern GUID gEfiUpdateDataFileGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/DataHubStatusCodeRecord.h b/Core/IntelFrameworkModulePkg/Include/Guid/DataHubStatusCodeRecord.h
new file mode 100644
index 0000000000..a03a09712c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/DataHubStatusCodeRecord.h
@@ -0,0 +1,61 @@
+/** @file
+ GUID used to identify Data Hub records logged by Status Code Protocol.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DATA_HUB_STATUS_CODE_RECORD_H__
+#define __DATA_HUB_STATUS_CODE_RECORD_H__
+
+///
+/// The Global ID used to identify a structure of type DATA_HUB_STATUS_CODE_DATA_RECORD.
+///
+#define EFI_DATA_HUB_STATUS_CODE_RECORD_GUID \
+ { \
+ 0xd083e94c, 0x6560, 0x42e4, {0xb6, 0xd4, 0x2d, 0xf7, 0x5a, 0xdf, 0x6a, 0x2a } \
+ }
+
+///
+/// The Data Hub data record that is used to store all the parameters passed into
+/// the ReportStatusCode() service of the EFI_STATUS_CODE_PROTOCOL.
+///
+typedef struct {
+ ///
+ /// Status Code type to be reported.
+ ///
+ EFI_STATUS_CODE_TYPE CodeType;
+
+ ///
+ /// An operation, plus value information about the class and subclass, used to
+ /// classify the hardware and software entity.
+ ///
+ EFI_STATUS_CODE_VALUE Value;
+
+ ///
+ /// The enumeration of a hardware or software entity within
+ /// the system. Valid instance numbers start with 1.
+ ///
+ UINT32 Instance;
+
+ ///
+ /// Identify the caller.
+ ///
+ EFI_GUID CallerId;
+
+ ///
+ /// Additional status code data.
+ ///
+ EFI_STATUS_CODE_DATA Data;
+} DATA_HUB_STATUS_CODE_DATA_RECORD;
+
+extern EFI_GUID gEfiDataHubStatusCodeRecordGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/HdBootVariable.h b/Core/IntelFrameworkModulePkg/Include/Guid/HdBootVariable.h
new file mode 100644
index 0000000000..fae0839791
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/HdBootVariable.h
@@ -0,0 +1,31 @@
+/** @file
+ GUID used as EFI Variable for the device path of Boot file on HardDevice.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __HD_DEVICE_PATH_VARIABLE_GUID_H__
+#define __HD_DEVICE_PATH_VARIABLE_GUID_H__
+
+///
+/// This GUID is used for an EFI Variable that stores the front device pathes
+/// for a partial device path that starts with the HD node.
+///
+#define HD_BOOT_DEVICE_PATH_VARIABLE_GUID \
+ { \
+ 0xfab7e9e1, 0x39dd, 0x4f2b, { 0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde } \
+ }
+
+#define HD_BOOT_DEVICE_PATH_VARIABLE_NAME L"HDDP"
+
+extern EFI_GUID gHdBootDevicePathVariablGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/IntelFrameworkModulePkgTokenSpace.h b/Core/IntelFrameworkModulePkg/Include/Guid/IntelFrameworkModulePkgTokenSpace.h
new file mode 100644
index 0000000000..a80c2315ba
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/IntelFrameworkModulePkgTokenSpace.h
@@ -0,0 +1,27 @@
+/** @file
+ GUID for IntelFrameworkModulePkg PCD Token Space
+
+Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#ifndef _INTEL_FRAMEWOKR_MODULEPKG_TOKEN_SPACE_GUID_H_
+#define _INTEL_FRAMEWOKR_MODULEPKG_TOKEN_SPACE_GUID_H_
+
+///
+/// The Global ID for the IntelFrameworkModulePkg PCD Token Space .
+///
+#define INTEL_FRAMEWORK_MODULEPKG_TOKEN_SPACE_GUID \
+ { \
+ 0xD3705011, 0xBC19, 0x4af7, { 0xBE, 0x16, 0xF6, 0x80, 0x30, 0x37, 0x8C, 0x15 } \
+ }
+
+extern EFI_GUID gEfiIntelFrameworkModulePkgTokenSpaceGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/LastEnumLang.h b/Core/IntelFrameworkModulePkg/Include/Guid/LastEnumLang.h
new file mode 100644
index 0000000000..8d9e37fab2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/LastEnumLang.h
@@ -0,0 +1,31 @@
+/** @file
+ GUID used as EFI variable to store platform language at last time enumeration.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __LAST_ENUM_LANGUAGE_GUID_H__
+#define __LAST_ENUM_LANGUAGE_GUID_H__
+
+///
+/// This GUID is used for Set/Get platform language into/from variable at last time enumeration
+/// to ensure the enumeration will only execute once.
+///
+#define LAST_ENUM_LANGUAGE_GUID \
+ { \
+ 0xe8c545b, 0xa2ee, 0x470d, { 0x8e, 0x26, 0xbd, 0xa1, 0xa1, 0x3c, 0xa, 0xa3 } \
+ }
+
+#define LAST_ENUM_LANGUAGE_VARIABLE_NAME L"LastEnumLang"
+
+extern EFI_GUID gLastEnumLangGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h b/Core/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h
new file mode 100644
index 0000000000..1fcea9ccfb
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/LegacyBios.h
@@ -0,0 +1,36 @@
+/** @file
+ Defines a Tag GUID used to mark a UEFI legacy BIOS thunk driver based
+ on legacy BIOS services and legacy option ROM. This Tag GUID must be installed on
+ the ImageHandle of any module that follows the EFI Driver Model and uses
+ the Int86() or FarCall() services of the Legacy Bios Protocol to produce
+ a standard UEFI I/O Protocol.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _LEGACY_BIOS_H_
+#define _LEGACY_BIOS_H_
+
+///
+/// The Global ID for the Legacy BIOS GUID that must be installed onto the ImageHandle
+/// of any module follows the EFI Driver Model and uses the Int86() or FarCall()
+/// services of the Legacy BIOS Protocol to produce a standard UEFI I/O Protocol.
+///
+#define EFI_LEGACY_BIOS_GUID \
+ { \
+ 0x2e3044ac, 0x879f, 0x490f, {0x97, 0x60, 0xbb, 0xdf, 0xaf, 0x69, 0x5f, 0x50 } \
+ }
+
+extern EFI_GUID gEfiLegacyBiosGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/LegacyDevOrder.h b/Core/IntelFrameworkModulePkg/Include/Guid/LegacyDevOrder.h
new file mode 100644
index 0000000000..684f098d58
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/LegacyDevOrder.h
@@ -0,0 +1,45 @@
+/** @file
+ Guid of a NV Variable which store the information about the
+ FD/HD/CD/NET/BEV order.
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __LEGACY_DEV_ORDER_VARIABLE_GUID_H__
+#define __LEGACY_DEV_ORDER_VARIABLE_GUID_H__
+
+///
+/// Name and Guid of a NV Variable which stores the information about the
+/// FD/HD/CD/NET/BEV order
+///
+#define EFI_LEGACY_DEV_ORDER_VARIABLE_GUID \
+ { \
+ 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52} \
+ }
+
+typedef UINT8 BBS_TYPE;
+
+#pragma pack(1)
+typedef struct {
+ BBS_TYPE BbsType;
+ ///
+ /// Length = sizeof (UINT16) + sizeof (Data)
+ ///
+ UINT16 Length;
+ UINT16 Data[1];
+} LEGACY_DEV_ORDER_ENTRY;
+#pragma pack()
+
+#define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder"
+
+extern EFI_GUID gEfiLegacyDevOrderVariableGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Guid/TianoDecompress.h b/Core/IntelFrameworkModulePkg/Include/Guid/TianoDecompress.h
new file mode 100644
index 0000000000..7c2a6a6b93
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Guid/TianoDecompress.h
@@ -0,0 +1,28 @@
+/** @file
+ Tiano Custom decompress Guid definition.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __TIANO_CUSTOM_DECOMPRESS_GUID_H__
+#define __TIANO_CUSTOM_DECOMPRESS_GUID_H__
+
+///
+/// The Global ID used to identify a section of an FFS file of type
+/// EFI_SECTION_GUID_DEFINED, whose contents have been compressed using
+/// Tiano Custom compression.
+///
+#define TIANO_CUSTOM_DECOMPRESS_GUID \
+ { 0xA31280AD, 0x481E, 0x41B6, { 0x95, 0xE8, 0x12, 0x7F, 0x4C, 0x98, 0x47, 0x79 } }
+
+extern GUID gTianoCustomDecompressGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Library/GenericBdsLib.h b/Core/IntelFrameworkModulePkg/Include/Library/GenericBdsLib.h
new file mode 100644
index 0000000000..ecd68a003b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Library/GenericBdsLib.h
@@ -0,0 +1,1114 @@
+/** @file
+ Generic BDS library defines general interfaces for a BDS driver, including:
+ 1) BDS boot policy interface.
+ 2) BDS boot device connect interface.
+ 3) BDS Misc interfaces for mainting boot variable, ouput string.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _GENERIC_BDS_LIB_H_
+#define _GENERIC_BDS_LIB_H_
+
+#include <Protocol/UserManager.h>
+
+///
+/// Constants which are variable names used to access variables.
+///
+#define VAR_LEGACY_DEV_ORDER L"LegacyDevOrder"
+
+///
+/// Data structures and defines.
+///
+#define FRONT_PAGE_QUESTION_ID 0x0000
+#define FRONT_PAGE_DATA_WIDTH 0x01
+
+///
+/// ConnectType
+///
+#define CONSOLE_OUT 0x00000001
+#define STD_ERROR 0x00000002
+#define CONSOLE_IN 0x00000004
+#define CONSOLE_ALL (CONSOLE_OUT | CONSOLE_IN | STD_ERROR)
+
+///
+/// Load Option Attributes
+///
+#define LOAD_OPTION_ACTIVE 0x00000001
+#define LOAD_OPTION_FORCE_RECONNECT 0x00000002
+
+#define LOAD_OPTION_HIDDEN 0x00000008
+#define LOAD_OPTION_CATEGORY 0x00001F00
+
+#define LOAD_OPTION_CATEGORY_BOOT 0x00000000
+#define LOAD_OPTION_CATEGORY_APP 0x00000100
+
+#define EFI_BOOT_OPTION_SUPPORT_KEY 0x00000001
+#define EFI_BOOT_OPTION_SUPPORT_APP 0x00000002
+
+#define IS_LOAD_OPTION_TYPE(_c, _Mask) (BOOLEAN) (((_c) & (_Mask)) != 0)
+
+///
+/// Define the maximum characters that will be accepted.
+///
+#define MAX_CHAR 480
+#define MAX_CHAR_SIZE (MAX_CHAR * 2)
+
+///
+/// Define maximum characters for boot option variable "BootXXXX".
+///
+#define BOOT_OPTION_MAX_CHAR 10
+
+//
+// This data structure is the part of BDS_CONNECT_ENTRY
+//
+#define BDS_LOAD_OPTION_SIGNATURE SIGNATURE_32 ('B', 'd', 'C', 'O')
+
+typedef struct {
+
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ CHAR16 *OptionName;
+ UINTN OptionNumber;
+ UINT16 BootCurrent;
+ UINT32 Attribute;
+ CHAR16 *Description;
+ VOID *LoadOptions;
+ UINT32 LoadOptionsSize;
+ CHAR16 *StatusString;
+
+} BDS_COMMON_OPTION;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN ConnectType;
+} BDS_CONSOLE_CONNECT_ENTRY;
+
+//
+// Bds boot related lib functions
+//
+/**
+ Boot from the UEFI spec defined "BootNext" variable.
+
+**/
+VOID
+EFIAPI
+BdsLibBootNext (
+ VOID
+ );
+
+/**
+ Process the boot option according to the UEFI specification. The legacy boot option device path includes BBS_DEVICE_PATH.
+
+ @param Option The boot option to be processed.
+ @param DevicePath The device path describing where to load the
+ boot image or the legcy BBS device path to boot
+ the legacy OS.
+ @param ExitDataSize The size of exit data.
+ @param ExitData Data returned when Boot image failed.
+
+ @retval EFI_SUCCESS Boot from the input boot option succeeded.
+ @retval EFI_NOT_FOUND The Device Path is not found in the system.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBootViaBootOption (
+ IN BDS_COMMON_OPTION * Option,
+ IN EFI_DEVICE_PATH_PROTOCOL * DevicePath,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ );
+
+
+/**
+ This function will enumerate all possible boot devices in the system, and
+ automatically create boot options for Network, Shell, Removable BlockIo,
+ and Non-BlockIo Simplefile devices.
+
+ BDS separates EFI boot options into six types:
+ 1. Network - The boot option points to the SimpleNetworkProtocol device.
+ Bds will try to automatically create this type of boot option during enumeration.
+ 2. Shell - The boot option points to internal flash shell.
+ Bds will try to automatically create this type of boot option during enumeration.
+ 3. Removable BlockIo - The boot option points to a removable media
+ device, such as a USB flash drive or DVD drive.
+ These devices should contain a *removable* blockIo
+ protocol in their device handle.
+ Bds will try to automatically create this type boot option
+ when enumerate.
+ 4. Fixed BlockIo - The boot option points to a Fixed blockIo device,
+ such as a hard disk.
+ These devices should contain a *fixed* blockIo
+ protocol in their device handle.
+ BDS will skip fixed blockIo devices, and not
+ automatically create boot option for them. But BDS
+ will help to delete those fixed blockIo boot options,
+ whose description rules conflict with other auto-created
+ boot options.
+ 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
+ has SimpleFileSystem Protocol, but has no blockio
+ protocol. These devices do not offer blockIo
+ protocol, but BDS still can get the
+ \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
+ Protocol.
+ 6. File - The boot option points to a file. These boot options are usually
+ created by the user, either manually or with an OS loader. BDS will not delete or modify
+ these boot options.
+
+ This function will enumerate all possible boot devices in the system, and
+ automatically create boot options for Network, Shell, Removable BlockIo,
+ and Non-BlockIo Simplefile devices.
+ It will excute once every boot.
+
+ @param BdsBootOptionList The header of the linked list that indexed all
+ current boot options.
+
+ @retval EFI_SUCCESS Finished all the boot device enumerations and
+ created the boot option based on the boot device.
+
+ @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create
+ the boot option list.
+**/
+EFI_STATUS
+EFIAPI
+BdsLibEnumerateAllBootOption (
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ );
+
+/**
+ Build the boot option with the handle parsed in.
+
+ @param Handle The handle representing the device path for which
+ to create a boot option.
+ @param BdsBootOptionList The header of the link list that indexed all
+ current boot options.
+ @param String The description of the boot option.
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromHandle (
+ IN EFI_HANDLE Handle,
+ IN LIST_ENTRY *BdsBootOptionList,
+ IN CHAR16 *String
+ );
+
+
+/**
+ Build the on flash shell boot option with the handle parsed in.
+
+ @param Handle The handle which present the device path to create
+ the on flash shell boot option.
+ @param BdsBootOptionList The header of the link list that indexed all
+ current boot options.
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromShell (
+ IN EFI_HANDLE Handle,
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ );
+
+//
+// Bds misc lib functions
+//
+/**
+ Get boot mode by looking up the configuration table and parsing the HOB list.
+
+ @param BootMode The boot mode from PEI handoff HOB.
+
+ @retval EFI_SUCCESS Successfully got boot mode.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetBootMode (
+ OUT EFI_BOOT_MODE *BootMode
+ );
+
+
+/**
+ The function will go through the driver option link list, and then load and start
+ every driver to which the driver option device path points.
+
+ @param BdsDriverLists The header of the current driver option link list.
+
+**/
+VOID
+EFIAPI
+BdsLibLoadDrivers (
+ IN LIST_ENTRY *BdsDriverLists
+ );
+
+
+/**
+ This function processes BootOrder or DriverOrder variables, by calling
+
+ BdsLibVariableToOption () for each UINT16 in the variables.
+
+ @param BdsCommonOptionList The header of the option list base on the variable
+ VariableName.
+ @param VariableName An EFI Variable name indicate the BootOrder or
+ DriverOrder.
+
+ @retval EFI_SUCCESS Successfully created the boot option or driver option
+ list.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or the driver option list.
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBuildOptionFromVar (
+ IN LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ );
+
+/**
+ This function reads the EFI variable (VendorGuid/Name) and returns a dynamically allocated
+ buffer and the size of the buffer. If it fails, return NULL.
+
+ @param Name The string part of the EFI variable name.
+ @param VendorGuid The GUID part of the EFI variable name.
+ @param VariableSize Returns the size of the EFI variable that was read.
+
+ @return Dynamically allocated memory that contains a copy
+ of the EFI variable. The caller is responsible for
+ freeing the buffer.
+ @retval NULL The variable was not read.
+
+**/
+VOID *
+EFIAPI
+BdsLibGetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ );
+
+
+/**
+ This function prints a series of strings.
+
+ @param ConOut A pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.
+ @param ... A variable argument list containing a series of
+ strings, the last string must be NULL.
+
+ @retval EFI_SUCCESS Successfully printed out the string using ConOut.
+ @retval EFI_STATUS Return the status of the ConOut->OutputString ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibOutputStrings (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ ...
+ );
+
+/**
+ Build the boot#### or driver#### option from the VariableName. The
+ build boot#### or driver#### will also be linked to BdsCommonOptionList.
+
+ @param BdsCommonOptionList The header of the boot#### or driver#### option
+ link list.
+ @param VariableName EFI Variable name, indicates if it is boot#### or
+ driver####.
+
+ @retval BDS_COMMON_OPTION The option that was created.
+ @retval NULL Failed to get the new option.
+
+**/
+BDS_COMMON_OPTION *
+EFIAPI
+BdsLibVariableToOption (
+ IN OUT LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ );
+
+/**
+ This function registers the new boot#### or driver#### option based on
+ the VariableName. The new registered boot#### or driver#### will be linked
+ to BdsOptionList and also update to the VariableName. After the boot#### or
+ driver#### updated, the BootOrder or DriverOrder will also be updated.
+
+ @param BdsOptionList The header of the boot#### or driver#### link list.
+ @param DevicePath The device path that the boot#### or driver####
+ option present.
+ @param String The description of the boot#### or driver####.
+ @param VariableName Indicate if the boot#### or driver#### option.
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been successfully
+ registered.
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibRegisterNewOption (
+ IN LIST_ENTRY *BdsOptionList,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CHAR16 *String,
+ IN CHAR16 *VariableName
+ );
+
+//
+// Bds connect and disconnect driver lib funcions
+//
+/**
+ This function connects all system drivers with the corresponding controllers.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllDriversToAllControllers (
+ VOID
+ );
+
+/**
+ This function connects all system drivers to controllers.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAll (
+ VOID
+ );
+
+/**
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path to be connected. Can be
+ a multi-instance device path.
+
+ @retval EFI_SUCCESS All handles associates with every device path node
+ were created.
+ @retval EFI_OUT_OF_RESOURCES Not enough resources to create new handles.
+ @retval EFI_NOT_FOUND At least one handle could not be created.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ );
+
+/**
+ This function will connect all current system handles recursively.
+ gBS->ConnectController() service is invoked for each handle exist in system handler buffer.
+ If the handle is bus type handler, all childrens also will be connected recursively by gBS->ConnectController().
+
+ @retval EFI_SUCCESS All handles and child handles have been
+ connected.
+ @retval EFI_STATUS Return the status of gBS->LocateHandleBuffer().
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllEfi (
+ VOID
+ );
+
+/**
+ This function will disconnect all current system handles.
+ gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
+ If handle is a bus type handle, all childrens also are disconnected recursively by gBS->DisconnectController().
+
+ @retval EFI_SUCCESS All handles have been disconnected.
+ @retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibDisconnectAllEfi (
+ VOID
+ );
+
+//
+// Bds console related lib functions
+//
+/**
+ This function will search every simpletxt device in the current system,
+ and make every simpletxt device a potential console device.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllConsoles (
+ VOID
+ );
+
+
+/**
+ This function will connect console device based on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConIn and ConOut devices have
+ been connected.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsoles (
+ VOID
+ );
+
+
+/**
+ This function will connect console device except ConIn base on the console
+ device variable ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConOut device have
+ been connected success.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsolesWithOutConIn (
+ VOID
+ );
+
+
+/**
+ This function updates the console variable based on ConVarName. It can
+ add or remove one specific console device path from the variable
+
+ @param ConVarName The console-related variable name: ConIn, ConOut,
+ ErrOut.
+ @param CustomizedConDevicePath The console device path to be added to
+ the console variable ConVarName. Cannot be multi-instance.
+ @param ExclusiveDevicePath The console device path to be removed
+ from the console variable ConVarName. Cannot be multi-instance.
+
+ @retval EFI_UNSUPPORTED The added device path is the same as a removed one.
+ @retval EFI_SUCCESS Successfully added or removed the device path from the
+ console variable.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateConsoleVariable (
+ IN CHAR16 *ConVarName,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ );
+
+/**
+ Connect the console device base on the variable ConVarName, if
+ device path of the ConVarName is multi-instance device path and
+ anyone of the instances is connected success, then this function
+ will return success.
+ If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param ConVarName Console related variable name, ConIn, ConOut,
+ ErrOut.
+
+ @retval EFI_NOT_FOUND There is not any console devices connected
+ success
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectConsoleVariable (
+ IN CHAR16 *ConVarName
+ );
+
+//
+// Bds device path related lib functions
+//
+/**
+ Delete the instance in Multi that overlaps with Single.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @return This function removes the device path instances in Multi that overlap
+ Single, and returns the resulting device path. If there is no
+ remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsLibDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+/**
+ This function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @retval TRUE If the Single device path is contained within a
+ Multi device path.
+ @retval FALSE The Single device path is not contained within a
+ Multi device path.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ );
+
+/**
+ This function converts an input device structure to a Unicode string.
+
+ @param DevPath A pointer to the device path structure.
+
+ @return A newly allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+//
+// Internal definitions
+//
+typedef struct {
+ CHAR16 *Str;
+ UINTN Len;
+ UINTN Maxlen;
+} POOL_PRINT;
+
+typedef
+VOID
+(*DEV_PATH_FUNCTION) (
+ IN OUT POOL_PRINT *Str,
+ IN VOID *DevPath
+ );
+
+typedef struct {
+ UINT8 Type;
+ UINT8 SubType;
+ DEV_PATH_FUNCTION Function;
+} DEVICE_PATH_STRING_TABLE;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ EFI_GUID Guid;
+ UINT8 VendorDefinedData[1];
+} VENDOR_DEVICE_PATH_WITH_DATA;
+
+typedef struct {
+ EFI_DEVICE_PATH_PROTOCOL Header;
+ UINT16 NetworkProtocol;
+ UINT16 LoginOption;
+ UINT64 Lun;
+ UINT16 TargetPortalGroupTag;
+ CHAR16 TargetName[1];
+} ISCSI_DEVICE_PATH_WITH_NAME;
+
+//
+// BBS support macros and functions
+//
+
+#if defined(MDE_CPU_IA32) || defined(MDE_CPU_X64)
+#define REFRESH_LEGACY_BOOT_OPTIONS \
+ BdsDeleteAllInvalidLegacyBootOptions ();\
+ BdsAddNonExistingLegacyBootOptions (); \
+ BdsUpdateLegacyDevOrder ()
+#else
+#define REFRESH_LEGACY_BOOT_OPTIONS
+#endif
+
+/**
+ Delete all the invalid legacy boot options.
+
+ @retval EFI_SUCCESS All invalid legacy boot options are deleted.
+ @retval EFI_OUT_OF_RESOURCES Failed to allocate necessary memory.
+ @retval EFI_NOT_FOUND Failed to retrieve variable of boot order.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ );
+
+/**
+ Add the legacy boot options from BBS table if they do not exist.
+
+ @retval EFI_SUCCESS The boot options were added successfully,
+ or they are already in boot options.
+ @retval EFI_NOT_FOUND No legacy boot options is found.
+ @retval EFI_OUT_OF_RESOURCE No enough memory.
+ @return Other value LegacyBoot options are not added.
+**/
+EFI_STATUS
+EFIAPI
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ );
+
+/**
+ Add the legacy boot devices from BBS table into
+ the legacy device boot order.
+
+ @retval EFI_SUCCESS The boot devices were added successfully.
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.
+ @retval EFI_OUT_OF_RESOURCES Memory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Failed to add the legacy device boot order into EFI variable
+ because of a hardware error.
+**/
+EFI_STATUS
+EFIAPI
+BdsUpdateLegacyDevOrder (
+ VOID
+ );
+
+/**
+ Refresh the boot priority for BBS entries based on boot option entry and boot order.
+
+ @param Entry The boot option is to be checked for a refreshed BBS table.
+
+ @retval EFI_SUCCESS The boot priority for BBS entries refreshed successfully.
+ @retval EFI_NOT_FOUND BBS entries can't be found.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+EFIAPI
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ );
+
+/**
+ Delete the Boot Option from EFI Variable. The Boot Order Arrray
+ is also updated.
+
+ @param OptionNumber The number of Boot options wanting to be deleted.
+ @param BootOrder The Boot Order array.
+ @param BootOrderSize The size of the Boot Order Array.
+
+ @retval EFI_SUCCESS The Boot Option Variable was found and removed.
+ @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible.
+ @retval EFI_NOT_FOUND The Boot Option Variable was not found.
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteBootOption (
+ IN UINTN OptionNumber,
+ IN OUT UINT16 *BootOrder,
+ IN OUT UINTN *BootOrderSize
+ );
+
+//
+//The interface functions related to the Setup Browser Reset Reminder feature
+//
+/**
+ Enable the setup browser reset reminder feature.
+ This routine is used in a platform tip. If the platform policy needs the feature, use the routine to enable it.
+
+**/
+VOID
+EFIAPI
+EnableResetReminderFeature (
+ VOID
+ );
+
+/**
+ Disable the setup browser reset reminder feature.
+ This routine is used in a platform tip. If the platform policy does not want the feature, use the routine to disable it.
+
+**/
+VOID
+EFIAPI
+DisableResetReminderFeature (
+ VOID
+ );
+
+/**
+ Record the info that a reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+EnableResetRequired (
+ VOID
+ );
+
+
+/**
+ Record the info that no reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+DisableResetRequired (
+ VOID
+ );
+
+/**
+ Check whether platform policy enables the reset reminder feature. The default is enabled.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetReminderFeatureEnable (
+ VOID
+ );
+
+/**
+ Check if the user changed any option setting that needs a system reset to be effective.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+ VOID
+ );
+
+/**
+ Check whether a reset is needed, and finish the reset reminder feature.
+ If a reset is needed, pop up a menu to notice user, and finish the feature
+ according to the user selection.
+
+**/
+VOID
+EFIAPI
+SetupResetReminder (
+ VOID
+ );
+
+
+///
+/// Define the boot type with which to classify the boot option type.
+/// Different boot option types could have different boot behaviors.
+/// Use their device path node (Type + SubType) as the type value.
+/// The boot type here can be added according to requirements.
+///
+
+///
+/// ACPI boot type. For ACPI devices, using sub-types to distinguish devices is not allowed, so hardcode their values.
+///
+#define BDS_EFI_ACPI_FLOPPY_BOOT 0x0201
+///
+/// Message boot type
+/// If a device path of boot option only points to a message node, the boot option is a message boot type.
+///
+#define BDS_EFI_MESSAGE_ATAPI_BOOT 0x0301 // Type 03; Sub-Type 01
+#define BDS_EFI_MESSAGE_SCSI_BOOT 0x0302 // Type 03; Sub-Type 02
+#define BDS_EFI_MESSAGE_USB_DEVICE_BOOT 0x0305 // Type 03; Sub-Type 05
+#define BDS_EFI_MESSAGE_SATA_BOOT 0x0312 // Type 03; Sub-Type 18
+#define BDS_EFI_MESSAGE_MAC_BOOT 0x030b // Type 03; Sub-Type 11
+#define BDS_EFI_MESSAGE_MISC_BOOT 0x03FF
+
+///
+/// Media boot type
+/// If a device path of boot option contains a media node, the boot option is media boot type.
+///
+#define BDS_EFI_MEDIA_HD_BOOT 0x0401 // Type 04; Sub-Type 01
+#define BDS_EFI_MEDIA_CDROM_BOOT 0x0402 // Type 04; Sub-Type 02
+///
+/// BBS boot type
+/// If a device path of boot option contains a BBS node, the boot option is BBS boot type.
+///
+#define BDS_LEGACY_BBS_BOOT 0x0501 // Type 05; Sub-Type 01
+
+#define BDS_EFI_UNSUPPORT 0xFFFF
+
+/**
+ Check whether an instance in BlockIoDevicePath has the same partition node as the HardDriveDevicePath device path.
+
+ @param BlockIoDevicePath Multi device path instances to check.
+ @param HardDriveDevicePath A device path starting with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+BOOLEAN
+EFIAPI
+MatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+
+/**
+ Expand a device path that starts with a hard drive media device path node to be a
+ full device path that includes the full hardware path to the device. This function enables the device to boot.
+ To avoid requiring a connect on every boot, the front match is saved in a variable (the part point
+ to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ).
+ All successful history device paths
+ that point to the front part of the partition node will be saved.
+
+ @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
+ drive media device path.
+ @return A Pointer to the full device path, or NULL if a valid Hard Drive devic path
+ cannot be found.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsExpandPartitionPartialDevicePathToFull (
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ );
+
+/**
+ Return the bootable media handle.
+ First, check whether the device is connected.
+ Second, check whether the device path points to a device that supports SimpleFileSystemProtocol.
+ Third, detect the the default boot file in the Media, and return the removable Media handle.
+
+ @param DevicePath The Device Path to a bootable device.
+
+ @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+
+**/
+EFI_HANDLE
+EFIAPI
+BdsLibGetBootableHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+
+/**
+ Checks whether the Device path in a boot option points to a valid bootable device, and if the device
+ is ready to boot now.
+
+ @param DevPath The Device path in a boot option.
+ @param CheckMedia If true, check whether the device is ready to boot now.
+
+ @retval TRUE The Device path is valid.
+ @retval FALSE The Device path is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia
+ );
+
+/**
+ Checks whether the Device path in a boot option points to a valid bootable device, and if the device
+ is ready to boot now.
+ If Description is not NULL and the device path points to a fixed BlockIo
+ device, this function checks whether the description conflicts with other auto-created
+ boot options.
+
+ @param DevPath The Device path in a boot option.
+ @param CheckMedia If true, checks if the device is ready to boot now.
+ @param Description The description of a boot option.
+
+ @retval TRUE The Device path is valid.
+ @retval FALSE The Device path is invalid.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePathExt (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia,
+ IN CHAR16 *Description
+ );
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check.
+
+ @retval BDS_EFI_MEDIA_HD_BOOT The given device path contains MEDIA_DEVICE_PATH type device path node,
+ whose subtype is MEDIA_HARDDRIVE_DP.
+ @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node,
+ whose subtype is MEDIA_CDROM_DP.
+ @retval BDS_EFI_ACPI_FLOPPY_BOOT A given device path contains ACPI_DEVICE_PATH type device path node,
+ whose HID is floppy device.
+ @retval BDS_EFI_MESSAGE_ATAPI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node,
+ and its last device path node's subtype is MSG_ATAPI_DP.
+ @retval BDS_EFI_MESSAGE_SCSI_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node,
+ and its last device path node's subtype is MSG_SCSI_DP.
+ @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT A given device path contains MESSAGING_DEVICE_PATH type device path node,
+ and its last device path node's subtype is MSG_USB_DP.
+ @retval BDS_EFI_MESSAGE_MISC_BOOT The device path does not contain any media device path node, and
+ its last device path node points to a message device path node.
+ @retval BDS_LEGACY_BBS_BOOT A given device path contains BBS_DEVICE_PATH type device path node.
+ @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path does not point to a media and message device.
+
+ **/
+UINT32
+EFIAPI
+BdsGetBootTypeFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+
+/**
+ This routine registers a function to adjust the different types of memory page numbers
+ just before booting, and saves the updated info into the variable for the next boot to use.
+
+**/
+VOID
+EFIAPI
+BdsLibSaveMemoryTypeInformation (
+ VOID
+ );
+
+/**
+ Identify a user and, if authenticated, returns the current user profile handle.
+
+ @param[out] User Points to the user profile handle.
+
+ @retval EFI_SUCCESS The user is successfully identified, or user identification
+ is not supported.
+ @retval EFI_ACCESS_DENIED The user was not successfully identified.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUserIdentify (
+ OUT EFI_USER_PROFILE_HANDLE *User
+ );
+
+/**
+ This function checks if a Fv file device path is valid, according to a file GUID. If it is invalid,
+ it tries to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use this funciton
+ could promise the Fv file device path is right.
+
+ @param DevicePath On input, the Fv file device path to check. On
+ output, the updated valid Fv file device path
+ @param FileGuid the Fv file GUID.
+
+ @retval EFI_INVALID_PARAMETER The input DevicePath or FileGuid is invalid.
+ @retval EFI_UNSUPPORTED The input DevicePath does not contain an Fv file
+ GUID at all.
+ @retval EFI_ALREADY_STARTED The input DevicePath has pointed to the Fv file and is
+ valid.
+ @retval EFI_SUCCESS Successfully updated the invalid DevicePath
+ and returned the updated device path in DevicePath.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid
+ );
+
+
+/**
+ Connect the specific USB device that matches the RemainingDevicePath,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci
+ (0xFF).
+ @param RemainingDevicePath A short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path.
+
+ @retval EFI_SUCCESS The specific Usb device is connected successfully.
+ @retval EFI_INVALID_PARAMETER Invalid HostControllerPi (not 0x00, 0x20 or 0xFF)
+ or RemainingDevicePath is not the USB class device path.
+ @retval EFI_NOT_FOUND The device specified by device path is not found.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectUsbDevByShortFormDP(
+ IN UINT8 HostControllerPI,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ );
+
+
+//
+// The implementation of this function is provided by Platform code.
+//
+/**
+ Convert Vendor device path to a device name.
+
+ @param Str The buffer storing device name.
+ @param DevPath The pointer to vendor device path.
+
+**/
+VOID
+DevPathVendor (
+ IN OUT POOL_PRINT *Str,
+ IN VOID *DevPath
+ );
+
+/**
+ Concatenates a formatted unicode string to an allocated pool.
+ The caller must free the resulting buffer.
+
+ @param Str Tracks the allocated pool, size in use, and amount of pool allocated.
+ @param Fmt The format string.
+ @param ... The data will be printed.
+
+ @return Allocated buffer with the formatted string printed in it.
+ The caller must free the allocated buffer.
+ The buffer allocation is not packed.
+
+**/
+CHAR16 *
+EFIAPI
+CatPrint (
+ IN OUT POOL_PRINT *Str,
+ IN CHAR16 *Fmt,
+ ...
+ );
+
+/**
+ Use SystemTable ConOut to stop video based Simple Text Out consoles from going
+ to the video device. Put up LogoFile on every video device that is a console.
+
+ @param[in] LogoFile The file name of logo to display on the center of the screen.
+
+ @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
+ @retval EFI_UNSUPPORTED Logo not found.
+
+**/
+EFI_STATUS
+EFIAPI
+EnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ );
+
+
+/**
+ Use SystemTable ConOut to turn on video based Simple Text Out consoles. The
+ Simple Text Out screens will now be synced up with all non-video output devices.
+
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
+
+**/
+EFI_STATUS
+EFIAPI
+DisableQuietBoot (
+ VOID
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Include/Library/PlatformBdsLib.h b/Core/IntelFrameworkModulePkg/Include/Library/PlatformBdsLib.h
new file mode 100644
index 0000000000..af237a6030
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Library/PlatformBdsLib.h
@@ -0,0 +1,156 @@
+/** @file
+ Platform BDS library definition. A platform can implement
+ instances to support platform-specific behavior.
+
+Copyright (c) 2008 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PLATFORM_BDS_LIB_H_
+#define __PLATFORM_BDS_LIB_H_
+
+#include <Protocol/GenericMemoryTest.h>
+#include <Library/GenericBdsLib.h>
+
+/**
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+ @param Level The memory test intensive level.
+
+ @retval EFI_STATUS Successfully test all the system memory, and update
+ the memory resource
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *BASEM_MEMORY_TEST)(
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ );
+
+/**
+ This routine is called to see if there are any capsules we need to process.
+ If the boot mode is not UPDATE, then we do nothing. Otherwise, find the
+ capsule HOBS and produce firmware volumes for them via the DXE service.
+ Then call the dispatcher to dispatch drivers from them. Finally, check
+ the status of the updates.
+
+ This function should be called by BDS in case we need to do some
+ sort of processing even if there is no capsule to process. We
+ need to do this if an earlier update went away and we need to
+ clear the capsule variable so on the next reset PEI does not see it and
+ think there is a capsule available.
+
+ @param BootMode The current boot mode
+
+ @retval EFI_INVALID_PARAMETER The boot mode is not correct for an update.
+ @retval EFI_SUCCESS There is no error when processing a capsule.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *PROCESS_CAPSULES)(
+ IN EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Platform Bds initialization. Includes the platform firmware vendor, revision
+ and so crc check.
+
+**/
+VOID
+EFIAPI
+PlatformBdsInit (
+ VOID
+ );
+
+/**
+ The function will excute with as the platform policy, current policy
+ is driven by boot mode. IBV/OEM can customize this code for their specific
+ policy action.
+
+ @param DriverOptionList The header of the driver option link list
+ @param BootOptionList The header of the boot option link list
+ @param ProcessCapsules A pointer to ProcessCapsules()
+ @param BaseMemoryTest A pointer to BaseMemoryTest()
+
+**/
+VOID
+EFIAPI
+PlatformBdsPolicyBehavior (
+ IN LIST_ENTRY *DriverOptionList,
+ IN LIST_ENTRY *BootOptionList,
+ IN PROCESS_CAPSULES ProcessCapsules,
+ IN BASEM_MEMORY_TEST BaseMemoryTest
+ );
+
+/**
+ Hook point for a user-provided function, for after a boot attempt fails.
+
+ @param Option A pointer to Boot Option that failed to boot.
+ @param Status The status returned from failed boot.
+ @param ExitData The exit data returned from failed boot.
+ @param ExitDataSize The exit data size returned from failed boot.
+
+**/
+VOID
+EFIAPI
+PlatformBdsBootFail (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_STATUS Status,
+ IN CHAR16 *ExitData,
+ IN UINTN ExitDataSize
+ );
+
+/**
+ Hook point after a boot attempt succeeds. We don't expect a boot option to
+ return, so the UEFI 2.0 specification defines that you will default to an
+ interactive mode and stop processing the BootOrder list in this case. This
+ is also a platform implementation, and can be customized by an IBV/OEM.
+
+ @param Option A pointer to the Boot Option that successfully booted.
+
+**/
+VOID
+EFIAPI
+PlatformBdsBootSuccess (
+ IN BDS_COMMON_OPTION *Option
+ );
+
+
+/**
+ This function locks platform flash that is not allowed to be updated during normal boot path.
+ The flash layout is platform specific.
+
+ **/
+VOID
+EFIAPI
+PlatformBdsLockNonUpdatableFlash (
+ VOID
+ );
+
+/**
+ Lock the ConsoleIn device in system table. All key
+ presses will be ignored until the Password is typed in. The only way to
+ disable the password is to type it in to a ConIn device.
+
+ @param Password The password used to lock ConIn device.
+
+ @retval EFI_SUCCESS Lock the Console In Spliter virtual handle successfully.
+ @retval EFI_UNSUPPORTED Password not found.
+
+**/
+EFI_STATUS
+EFIAPI
+LockKeyboards (
+ IN CHAR16 *Password
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/ExitPmAuth.h b/Core/IntelFrameworkModulePkg/Include/Protocol/ExitPmAuth.h
new file mode 100644
index 0000000000..748ab96620
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/ExitPmAuth.h
@@ -0,0 +1,25 @@
+/** @file
+ Defines the ExitPmAuth protocol.
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EXIT_PM_AUTH_PROTOCOL_H_
+#define _EXIT_PM_AUTH_PROTOCOL_H_
+
+#define EXIT_PM_AUTH_PROTOCOL_GUID \
+ { 0xd088a413, 0xa70, 0x4217, { 0xba, 0x55, 0x9a, 0x3c, 0xb6, 0x5c, 0x41, 0xb3 }}
+
+extern EFI_GUID gExitPmAuthProtocolGuid;
+
+#endif // #ifndef _EXIT_PM_AUTH_PROTOCOL_H_
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/IsaAcpi.h b/Core/IntelFrameworkModulePkg/Include/Protocol/IsaAcpi.h
new file mode 100644
index 0000000000..7de3504417
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/IsaAcpi.h
@@ -0,0 +1,304 @@
+/** @file
+ EFI ISA ACPI Protocol is used to enumerate and manage all the ISA controllers on
+ the platform's ISA Bus.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __ISA_ACPI_H_
+#define __ISA_ACPI_H_
+
+///
+/// Global ID for the EFI ISA ACPI Protocol.
+///
+#define EFI_ISA_ACPI_PROTOCOL_GUID \
+ { \
+ 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 } \
+ }
+
+///
+/// Forward declaration fo the EFI ISA ACPI Protocol
+///
+typedef struct _EFI_ISA_ACPI_PROTOCOL EFI_ISA_ACPI_PROTOCOL;
+
+///
+/// ISA ACPI Protocol interrupt resource attributes.
+///
+#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_EDGE_SENSITIVE 0x01 ///< Edge triggered interrupt on a rising edge.
+#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_EDGE_SENSITIVE 0x02 ///< Edge triggered interrupt on a falling edge.
+#define EFI_ISA_ACPI_IRQ_TYPE_HIGH_TRUE_LEVEL_SENSITIVE 0x04 ///< Level sensitive interrupt active high.
+#define EFI_ISA_ACPI_IRQ_TYPE_LOW_TRUE_LEVEL_SENSITIVE 0x08 ///< Level sensitive interrupt active low.
+
+///
+/// ISA ACPI Protocol DMA resource attributes.
+///
+#define EFI_ISA_ACPI_DMA_SPEED_TYPE_MASK 0x03 ///< Bit mask of supported DMA speed attributes.
+#define EFI_ISA_ACPI_DMA_SPEED_TYPE_COMPATIBILITY 0x00 ///< ISA controller supports compatibility mode DMA transfers.
+#define EFI_ISA_ACPI_DMA_SPEED_TYPE_A 0x01 ///< ISA controller supports type A DMA transfers.
+#define EFI_ISA_ACPI_DMA_SPEED_TYPE_B 0x02 ///< ISA controller supports type B DMA transfers.
+#define EFI_ISA_ACPI_DMA_SPEED_TYPE_F 0x03 ///< ISA controller supports type F DMA transfers.
+#define EFI_ISA_ACPI_DMA_COUNT_BY_BYTE 0x04 ///< ISA controller increments DMA address by bytes (8-bit).
+#define EFI_ISA_ACPI_DMA_COUNT_BY_WORD 0x08 ///< ISA controller increments DMA address by words (16-bit).
+#define EFI_ISA_ACPI_DMA_BUS_MASTER 0x10 ///< ISA controller is a DMA bus master.
+#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT 0x20 ///< ISA controller only supports 8-bit DMA transfers.
+#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_8_BIT_AND_16_BIT 0x40 ///< ISA controller both 8-bit and 16-bit DMA transfers.
+#define EFI_ISA_ACPI_DMA_TRANSFER_TYPE_16_BIT 0x80 ///< ISA controller only supports 16-bit DMA transfers.
+
+///
+/// ISA ACPI Protocol MMIO resource attributes
+///
+#define EFI_ISA_ACPI_MEMORY_WIDTH_MASK 0x03 ///< Bit mask of supported ISA memory width attributes.
+#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT 0x00 ///< ISA MMIO region only supports 8-bit access.
+#define EFI_ISA_ACPI_MEMORY_WIDTH_16_BIT 0x01 ///< ISA MMIO region only supports 16-bit access.
+#define EFI_ISA_ACPI_MEMORY_WIDTH_8_BIT_AND_16_BIT 0x02 ///< ISA MMIO region supports both 8-bit and 16-bit access.
+#define EFI_ISA_ACPI_MEMORY_WRITEABLE 0x04 ///< ISA MMIO region supports write transactions.
+#define EFI_ISA_ACPI_MEMORY_CACHEABLE 0x08 ///< ISA MMIO region supports being cached.
+#define EFI_ISA_ACPI_MEMORY_SHADOWABLE 0x10 ///< ISA MMIO region may be shadowed.
+#define EFI_ISA_ACPI_MEMORY_EXPANSION_ROM 0x20 ///< ISA MMIO region is an expansion ROM.
+
+///
+/// ISA ACPI Protocol I/O resource attributes
+///
+#define EFI_ISA_ACPI_IO_DECODE_10_BITS 0x01 ///< ISA controllers uses a 10-bit address decoder for I/O cycles.
+#define EFI_ISA_ACPI_IO_DECODE_16_BITS 0x02 ///< ISA controllers uses a 16-bit address decoder for I/O cycles.
+
+///
+/// EFI ISA ACPI resource type
+///
+typedef enum {
+ EfiIsaAcpiResourceEndOfList, ///< Marks the end if a resource list.
+ EfiIsaAcpiResourceIo, ///< ISA I/O port resource range.
+ EfiIsaAcpiResourceMemory, ///< ISA MMIO resource range.
+ EfiIsaAcpiResourceDma, ///< ISA DMA resource.
+ EfiIsaAcpiResourceInterrupt ///< ISA interrupt resource.
+} EFI_ISA_ACPI_RESOURCE_TYPE;
+
+///
+/// EFI ISA ACPI generic resource structure
+///
+typedef struct {
+ EFI_ISA_ACPI_RESOURCE_TYPE Type; ///< The type of resource (I/O, MMIO, DMA, Interrupt).
+ UINT32 Attribute; ///< Bit mask of attributes associated with this resource. See EFI_ISA_ACPI_xxx macros for valid combinations.
+ UINT32 StartRange; ///< The start of the resource range.
+ UINT32 EndRange; ///< The end of the resource range.
+} EFI_ISA_ACPI_RESOURCE;
+
+///
+/// EFI ISA ACPI resource device identifier
+///
+typedef struct {
+ UINT32 HID; ///< The ACPI Hardware Identifier value associated with an ISA controller. Matchs ACPI DSDT contents.
+ UINT32 UID; ///< The ACPI Unique Identifier value associated with an ISA controller. Matches ACPI DSDT contents.
+} EFI_ISA_ACPI_DEVICE_ID;
+
+///
+/// EFI ISA ACPI resource list
+///
+typedef struct {
+ EFI_ISA_ACPI_DEVICE_ID Device; ///< The ACPI HID/UID associated with an ISA controller.
+ EFI_ISA_ACPI_RESOURCE *ResourceItem; ///< A pointer to the list of resources associated with an ISA controller.
+} EFI_ISA_ACPI_RESOURCE_LIST;
+
+/**
+ Enumerates the ISA controllers on an ISA bus.
+
+ This service allows all the ISA controllers on an ISA bus to be enumerated. If
+ Device is a pointer to a NULL value, then the first ISA controller on the ISA
+ bus is returned in Device and EFI_SUCCESS is returned. If Device is a pointer
+ to a value that was returned on a prior call to DeviceEnumerate(), then the next
+ ISA controller on the ISA bus is returned in Device and EFI_SUCCESS is returned.
+ If Device is a pointer to the last ISA controller on the ISA bus, then
+ EFI_NOT_FOUND is returned.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[out] Device The pointer to an ISA controller named by ACPI HID/UID.
+
+ @retval EFI_SUCCESS The next ISA controller on the ISA bus was returned.
+ @retval EFI_NOT_FOUND No device found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_DEVICE_ENUMERATE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ OUT EFI_ISA_ACPI_DEVICE_ID **Device
+ );
+
+/**
+ Sets the power state of an ISA controller.
+
+ This services sets the power state of the ISA controller specified by Device to
+ the power state specified by OnOff. TRUE denotes on, FALSE denotes off.
+ If the power state is sucessfully set on the ISA Controller, then
+ EFI_SUCCESS is returned.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to an ISA controller named by ACPI HID/UID.
+ @param[in] OnOff TRUE denotes on, FALSE denotes off.
+
+ @retval EFI_SUCCESS Successfully set the power state of the ISA controller.
+ @retval Other The ISA controller could not be placed in the requested power state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_SET_DEVICE_POWER)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device,
+ IN BOOLEAN OnOff
+ );
+
+/**
+ Retrieves the current set of resources associated with an ISA controller.
+
+ Retrieves the set of I/O, MMIO, DMA, and interrupt resources currently
+ assigned to the ISA controller specified by Device. These resources
+ are returned in ResourceList.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to an ISA controller named by ACPI HID/UID.
+ @param[out] ResourceList The pointer to the current resource list for Device.
+
+ @retval EFI_SUCCESS Successfully retrieved the current resource list.
+ @retval EFI_NOT_FOUND The resource list could not be retrieved.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_GET_CUR_RESOURCE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device,
+ OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList
+ );
+
+/**
+ Retrieves the set of possible resources that may be assigned to an ISA controller
+ with SetResource().
+
+ Retrieves the possible sets of I/O, MMIO, DMA, and interrupt resources for the
+ ISA controller specified by Device. The sets are returned in ResourceList.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to an ISA controller named by ACPI HID/UID.
+ @param[out] ResourceList The pointer to the returned list of resource lists.
+
+ @retval EFI_UNSUPPORTED This service is not supported.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_GET_POS_RESOURCE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device,
+ OUT EFI_ISA_ACPI_RESOURCE_LIST **ResourceList
+ );
+
+/**
+ Assigns resources to an ISA controller.
+
+ Assigns the I/O, MMIO, DMA, and interrupt resources specified by ResourceList
+ to the ISA controller specified by Device. ResourceList must match a resource list returned by GetPosResource() for the same ISA controller.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to an ISA controller named by ACPI HID/UID.
+ @param[in] ResourceList The pointer to a resources list that must be one of the
+ resource lists returned by GetPosResource() for the
+ ISA controller specified by Device.
+
+ @retval EFI_SUCCESS Successfully set resources on the ISA controller.
+ @retval Other The resources could not be set for the ISA controller.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_SET_RESOURCE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device,
+ IN EFI_ISA_ACPI_RESOURCE_LIST *ResourceList
+ );
+
+/**
+ Enables or disables an ISA controller.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to the ISA controller to enable/disable.
+ @param[in] Enable TRUE to enable the ISA controller. FALSE to disable the
+ ISA controller.
+
+ @retval EFI_SUCCESS Successfully enabled/disabled the ISA controller.
+ @retval Other The ISA controller could not be placed in the requested state.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_ENABLE_DEVICE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device,
+ IN BOOLEAN Enable
+ );
+
+/**
+ Initializes an ISA controller, so that it can be used. This service must be called
+ before SetResource(), EnableDevice(), or SetPower() will behave as expected.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+ @param[in] Device The pointer to an ISA controller named by ACPI HID/UID.
+
+ @retval EFI_SUCCESS Successfully initialized an ISA controller.
+ @retval Other The ISA controller could not be initialized.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_INIT_DEVICE)(
+ IN EFI_ISA_ACPI_PROTOCOL *This,
+ IN EFI_ISA_ACPI_DEVICE_ID *Device
+ );
+
+/**
+ Initializes all the HW states required for the ISA controllers on the ISA bus
+ to be enumerated and managed by the rest of the services in this prorotol.
+ This service must be called before any of the other services in this
+ protocol will function as expected.
+
+ @param[in] This The pointer to the EFI_ISA_ACPI_PROTOCOL instance.
+
+ @retval EFI_SUCCESS Successfully initialized all required hardware states.
+ @retval Other The ISA interface could not be initialized.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_ACPI_INTERFACE_INIT)(
+ IN EFI_ISA_ACPI_PROTOCOL *This
+ );
+
+///
+/// The EFI_ISA_ACPI_PROTOCOL provides the services to enumerate and manage
+/// ISA controllers on an ISA bus. These services include the ability to initialize,
+/// enable, disable, and manage the power state of ISA controllers. It also
+/// includes services to query current resources, query possible resources,
+/// and assign resources to an ISA controller.
+///
+struct _EFI_ISA_ACPI_PROTOCOL {
+ EFI_ISA_ACPI_DEVICE_ENUMERATE DeviceEnumerate;
+ EFI_ISA_ACPI_SET_DEVICE_POWER SetPower;
+ EFI_ISA_ACPI_GET_CUR_RESOURCE GetCurResource;
+ EFI_ISA_ACPI_GET_POS_RESOURCE GetPosResource;
+ EFI_ISA_ACPI_SET_RESOURCE SetResource;
+ EFI_ISA_ACPI_ENABLE_DEVICE EnableDevice;
+ EFI_ISA_ACPI_INIT_DEVICE InitDevice;
+ EFI_ISA_ACPI_INTERFACE_INIT InterfaceInit;
+};
+
+extern EFI_GUID gEfiIsaAcpiProtocolGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/IsaIo.h b/Core/IntelFrameworkModulePkg/Include/Protocol/IsaIo.h
new file mode 100644
index 0000000000..cf6632e737
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/IsaIo.h
@@ -0,0 +1,362 @@
+/** @file
+ ISA I/O Protocol is used by ISA device drivers to perform I/O, MMIO and DMA
+ operations on the ISA controllers they manage.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_ISA_IO_H_
+#define _EFI_ISA_IO_H_
+
+#include <Protocol/IsaAcpi.h>
+
+///
+/// Global ID for the EFI_ISA_IO_PROTOCOL
+///
+#define EFI_ISA_IO_PROTOCOL_GUID \
+ { \
+ 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d } \
+ }
+
+///
+/// Forward declaration for the EFI_ISA_IO_PROTOCOL.
+///
+typedef struct _EFI_ISA_IO_PROTOCOL EFI_ISA_IO_PROTOCOL;
+
+///
+/// Width of EFI_ISA_IO_PROTOCOL I/O Port and MMIO operations.
+///
+typedef enum {
+ EfiIsaIoWidthUint8 = 0, ///< 8-bit operation.
+ EfiIsaIoWidthUint16, ///< 16-bit operation.
+ EfiIsaIoWidthUint32, ///< 32-bit operation
+ EfiIsaIoWidthReserved,
+ EfiIsaIoWidthFifoUint8, ///< 8-bit FIFO operation.
+ EfiIsaIoWidthFifoUint16, ///< 16-bit FIFO operation.
+ EfiIsaIoWidthFifoUint32, ///< 32-bit FIFO operation.
+ EfiIsaIoWidthFifoReserved,
+ EfiIsaIoWidthFillUint8, ///< 8-bit Fill operation.
+ EfiIsaIoWidthFillUint16, ///< 16-bit Fill operation.
+ EfiIsaIoWidthFillUint32, ///< 32-bit Fill operation.
+ EfiIsaIoWidthFillReserved,
+ EfiIsaIoWidthMaximum
+} EFI_ISA_IO_PROTOCOL_WIDTH;
+
+///
+/// Attributes for the EFI_ISA_IO_PROTOCOL common DMA buffer allocations.
+///
+#define EFI_ISA_IO_ATTRIBUTE_MEMORY_WRITE_COMBINE 0x080 ///< Map a memory range so write are combined.
+#define EFI_ISA_IO_ATTRIBUTE_MEMORY_CACHED 0x800 ///< Map a memory range so all read and write accesses are cached.
+#define EFI_ISA_IO_ATTRIBUTE_MEMORY_DISABLE 0x1000 ///< Disable a memory range.
+
+///
+/// Channel attribute for EFI_ISA_IO_PROTOCOL slave DMA requests
+///
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_COMPATIBLE 0x001 ///< Set the speed of the DMA transfer in compatible mode.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_A 0x002 ///< Not supported.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_B 0x004 ///< Not supported.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SPEED_C 0x008 ///< Not supported.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_8 0x010 ///< Request 8-bit DMA transfers. Only available on channels 0..3.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_WIDTH_16 0x020 ///< Request 16-bit DMA transfers. Only available on channels 4..7.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_SINGLE_MODE 0x040 ///< Request a single DMA transfer.
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_DEMAND_MODE 0x080 ///< Request multiple DMA transfers until TC (Terminal Count) or EOP (End of Process).
+#define EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_AUTO_INITIALIZE 0x100 ///< Automatically reload base and count at the end of the DMA transfer.
+
+///
+/// The DMA opreration type for EFI_ISA_IO_PROTOCOL DMA requests.
+///
+typedef enum {
+ ///
+ /// A read operation from system memory by a bus master.
+ ///
+ EfiIsaIoOperationBusMasterRead,
+ ///
+ /// A write operation to system memory by a bus master.
+ ///
+ EfiIsaIoOperationBusMasterWrite,
+ ///
+ /// Provides both read and write access to system memory by both the processor
+ /// and a bus master. The buffer is coherent from both the processor's and the
+ /// bus master's point of view.
+ ///
+ EfiIsaIoOperationBusMasterCommonBuffer,
+ ///
+ /// A read operation from system memory by a slave device.
+ ///
+ EfiIsaIoOperationSlaveRead,
+ ///
+ /// A write operation to system memory by a slave master.
+ ///
+ EfiIsaIoOperationSlaveWrite,
+ EfiIsaIoOperationMaximum
+} EFI_ISA_IO_PROTOCOL_OPERATION;
+
+/**
+ Performs ISA I/O and MMIO Read/Write Cycles
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the I/O or MMIO operation.
+ @param[in] Offset The offset into the ISA I/O or MMIO space to start the
+ operation.
+ @param[in] Count The number of I/O or MMIO operations to perform.
+ @param[in, out] Buffer For read operations, the destination buffer to store
+ the results. For write operations, the source buffer to
+ write data from.
+
+ @retval EFI_SUCCESS The data was successfully read from or written to the device.
+ @retval EFI_UNSUPPORTED The Offset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_IO_MEM)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 Offset,
+ IN UINTN Count,
+ IN OUT VOID *Buffer
+ );
+
+///
+/// Structure of functions for accessing ISA I/O and MMIO space.
+///
+typedef struct {
+ ///
+ /// Read from ISA I/O or MMIO space.
+ ///
+ EFI_ISA_IO_PROTOCOL_IO_MEM Read;
+ ///
+ /// Write to ISA I/O or MMIO space.
+ ///
+ EFI_ISA_IO_PROTOCOL_IO_MEM Write;
+} EFI_ISA_IO_PROTOCOL_ACCESS;
+
+/**
+ Copies data from one region of ISA MMIO space to another region of ISA
+ MMIO space.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Width Specifies the width of the MMIO copy operation.
+ @param[in] DestOffset The offset of the destination in ISA MMIO space.
+ @param[in] SrcOffset The offset of the source in ISA MMIO space.
+ @param[in] Count The number tranfers to perform for this copy operation.
+
+ @retval EFI_SUCCESS The data was copied sucessfully.
+ @retval EFI_UNSUPPORTED The DestOffset or SrcOffset is not valid for this device.
+ @retval EFI_INVALID_PARAMETER Width or Count, or both, were invalid.
+ @retval EFI_OUT_OF_RESOURCES The request could not be completed due to a lack of resources.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_COPY_MEM)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_WIDTH Width,
+ IN UINT32 DestOffset,
+ IN UINT32 SrcOffset,
+ IN UINTN Count
+ );
+
+/**
+ Maps a memory region for DMA.
+
+ This function returns the device-specific addresses required to access system memory.
+ This function is used to map system memory for ISA DMA operations. All ISA DMA
+ operations must be performed through their mapped addresses, and such mappings must
+ be freed with EFI_ISA_IO_PROTOCOL.Unmap() after the DMA operation is completed.
+
+ If the DMA operation is a single read or write data transfer through an ISA bus
+ master, then EfiIsaIoOperationBusMasterRead or EfiIsaIoOperationBusMasterWrite
+ is used and the range is unmapped to complete the operation. If the DMA operation
+ is a single read or write data transfer through an ISA slave controller, then
+ EfiIsaIoOperationSlaveRead or EfiIsaIoOperationSlaveWrite is used and the range
+ is unmapped to complete the operation.
+
+ If performing a DMA read operation, all the data must be present in system memory before the Map() is performed. Similarly,
+ if performing a DMA write operation, the data must not be accessed in system
+ memory until EFI_ISA_IO_PROTOCOL.Unmap() is performed. Bus master operations that
+ require both read and write access or require multiple host device interactions
+ within the same mapped region must use EfiIsaIoOperationBusMasterCommonBuffer.
+ However, only memory allocated via the EFI_ISA_IO_PROTOCOL.AllocateBuffer() interface
+ is guaranteed to be able to be mapped for this operation type. In all mapping
+ requests the NumberOfBytes returned may be less than originally requested. It is
+ the caller's responsibility to make additional requests to complete the entire
+ transfer.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Operation Indicates the type of DMA (slave or bus master),
+ and if the DMA operation is going to read or
+ write to system memory.
+ @param[in] ChannelNumber The slave channel number to use for this DMA
+ operation. If Operation and ChannelAttributes
+ shows that this device performs bus mastering
+ DMA, then this field is ignored. The legal
+ range for this field is 0..7.
+ @param[in] ChannelAttributes A bitmask of the attributes used to configure
+ the slave DMA channel for this DMA operation.
+ See EFI_ISA_IO_SLAVE_DMA_ATTRIBUTE_* for the
+ legal bit combinations.
+ @param[in] HostAddress The system memory address to map to the device.
+ @param[in, out] NumberOfBytes On input the number of bytes to map. On
+ output the number of bytes that were mapped.
+ @param[out] DeviceAddress The resulting map address for the bus master
+ device to use to access the hosts HostAddress.
+ @param[out] Mapping A returned value that must be passed to into
+ EFI_ISA_IO_PROTOCOL.Unmap() to free all the the
+ resources associated with this map request.
+
+ @retval EFI_SUCCESS The range was mapped for the returned NumberOfBytes.
+ @retval EFI_INVALID_PARAMETER The Operation is undefined.
+ @retval EFI_INVALID_PARAMETER The HostAddress is undefined.
+ @retval EFI_UNSUPPORTED The HostAddress can not be mapped as a common buffer.
+ @retval EFI_DEVICE_ERROR The system hardware could not map the requested address.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_MAP)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ISA_IO_PROTOCOL_OPERATION Operation,
+ IN UINT8 ChannelNumber OPTIONAL,
+ IN UINT32 ChannelAttributes,
+ IN VOID *HostAddress,
+ IN OUT UINTN *NumberOfBytes,
+ OUT EFI_PHYSICAL_ADDRESS *DeviceAddress,
+ OUT VOID **Mapping
+ );
+
+/**
+ Unmaps a memory region that was previously mapped with EFI_ISA_IO_PROTOCOL.Map().
+
+ The EFI_ISA_IO_PROTOCOL.Map() operation is completed and any corresponding
+ resources are released. If the operation was EfiIsaIoOperationSlaveWrite
+ or EfiIsaIoOperationBusMasterWrite, the data is committed to system memory.
+ Any resources used for the mapping are freed.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Mapping The mapping value returned from EFI_ISA_IO_PROTOCOL.Map().
+
+ @retval EFI_SUCCESS The memory region was unmapped.
+ @retval EFI_DEVICE_ERROR The data was not committed to the target system memory.
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_UNMAP)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN VOID *Mapping
+ );
+
+/**
+ Allocates pages that are suitable for an EfiIsaIoOperationBusMasterCommonBuffer
+ mapping.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Type The type allocation to perform.
+ @param[in] MemoryType The type of memory to allocate.
+ @param[in] Pages The number of pages to allocate.
+ @param[out] HostAddress A pointer to store the base address of the allocated range.
+ @param[in] Attributes The requested bit mask of attributes for the allocated range.
+
+ @retval EFI_SUCCESS The requested memory pages were allocated.
+ @retval EFI_INVALID_PARAMETER Type is invalid.
+ @retval EFI_INVALID_PARAMETER MemoryType is invalid.
+ @retval EFI_INVALID_PARAMETER HostAddress is NULL.
+ @retval EFI_UNSUPPORTED Attributes is unsupported.
+ @retval EFI_UNSUPPORTED The memory range specified by HostAddress, Pages,
+ and Type is not available for common buffer use.
+ @retval EFI_OUT_OF_RESOURCES The memory pages could not be allocated.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN EFI_ALLOCATE_TYPE Type,
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Pages,
+ OUT VOID **HostAddress,
+ IN UINT64 Attributes
+ );
+
+/**
+ Frees a common buffer that was allocated with EFI_ISA_IO_PROTOCOL.AllocateBuffer().
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+ @param[in] Pages The number of pages to free from the previously allocated common buffer.
+ @param[in] HostAddress The base address of the previously allocated common buffer.
+
+
+ @retval EFI_SUCCESS The requested memory pages were freed.
+ @retval EFI_INVALID_PARAMETER The memory was not allocated with EFI_ISA_IO.AllocateBufer().
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_FREE_BUFFER)(
+ IN EFI_ISA_IO_PROTOCOL *This,
+ IN UINTN Pages,
+ IN VOID *HostAddress
+ );
+
+/**
+ Flushes a DMA buffer, which forces all DMA posted write transactions to complete.
+
+ @param[in] This A pointer to the EFI_ISA_IO_PROTOCOL instance.
+
+ @retval EFI_SUCCESS The DMA buffers were flushed.
+ @retval EFI_DEVICE_ERROR The buffers were not flushed due to a hardware error.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_ISA_IO_PROTOCOL_FLUSH)(
+ IN EFI_ISA_IO_PROTOCOL *This
+ );
+
+///
+/// The EFI_ISA_IO_PROTOCOL provides the basic Memory, I/O, and DMA interfaces
+/// used to abstract accesses to ISA controllers. There is one EFI_ISA_IO_PROTOCOL
+/// instance for each ISA controller on a ISA bus. A device driver that wishes
+/// to manage an ISA controller in a system will have to retrieve the
+/// ISA_PCI_IO_PROTOCOL instance associated with the ISA controller.
+///
+struct _EFI_ISA_IO_PROTOCOL {
+ EFI_ISA_IO_PROTOCOL_ACCESS Mem;
+ EFI_ISA_IO_PROTOCOL_ACCESS Io;
+ EFI_ISA_IO_PROTOCOL_COPY_MEM CopyMem;
+ EFI_ISA_IO_PROTOCOL_MAP Map;
+ EFI_ISA_IO_PROTOCOL_UNMAP Unmap;
+ EFI_ISA_IO_PROTOCOL_ALLOCATE_BUFFER AllocateBuffer;
+ EFI_ISA_IO_PROTOCOL_FREE_BUFFER FreeBuffer;
+ EFI_ISA_IO_PROTOCOL_FLUSH Flush;
+ ///
+ /// The list of I/O , MMIO, DMA, and Interrupt resources associated with the
+ /// ISA controller abstracted by this instance of the EFI_ISA_IO_PROTOCOL.
+ ///
+ EFI_ISA_ACPI_RESOURCE_LIST *ResourceList;
+ ///
+ /// The size, in bytes, of the ROM image.
+ ///
+ UINT32 RomSize;
+ ///
+ /// A pointer to the in memory copy of the ROM image. The ISA Bus Driver is responsible
+ /// for allocating memory for the ROM image, and copying the contents of the ROM to memory
+ /// during ISA Bus initialization.
+ ///
+ VOID *RomImage;
+};
+
+extern EFI_GUID gEfiIsaIoProtocolGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/OEMBadging.h b/Core/IntelFrameworkModulePkg/Include/Protocol/OEMBadging.h
new file mode 100644
index 0000000000..c56b7e725b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/OEMBadging.h
@@ -0,0 +1,88 @@
+/** @file
+ The OEM Badging Protocol defines the interface to get the OEM badging
+ image with the display attribute. This protocol can be produced based on OEM badging images.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __EFI_OEM_BADGING_H__
+#define __EFI_OEM_BADGING_H__
+
+//
+// GUID for EFI OEM Badging Protocol
+//
+#define EFI_OEM_BADGING_PROTOCOL_GUID \
+ { 0x170e13c0, 0xbf1b, 0x4218, {0x87, 0x1d, 0x2a, 0xbd, 0xc6, 0xf8, 0x87, 0xbc } }
+
+
+typedef struct _EFI_OEM_BADGING_PROTOCOL EFI_OEM_BADGING_PROTOCOL;
+
+typedef enum {
+ EfiBadgingFormatBMP,
+ EfiBadgingFormatJPEG,
+ EfiBadgingFormatTIFF,
+ EfiBadgingFormatGIF,
+ EfiBadgingFormatUnknown
+} EFI_BADGING_FORMAT;
+
+typedef enum {
+ EfiBadgingDisplayAttributeLeftTop,
+ EfiBadgingDisplayAttributeCenterTop,
+ EfiBadgingDisplayAttributeRightTop,
+ EfiBadgingDisplayAttributeCenterRight,
+ EfiBadgingDisplayAttributeRightBottom,
+ EfiBadgingDisplayAttributeCenterBottom,
+ EfiBadgingDisplayAttributeLeftBottom,
+ EfiBadgingDisplayAttributeCenterLeft,
+ EfiBadgingDisplayAttributeCenter,
+ EfiBadgingDisplayAttributeCustomized
+} EFI_BADGING_DISPLAY_ATTRIBUTE;
+
+/**
+
+ Load an OEM badge image and return its data and attributes.
+
+ @param This The pointer to this protocol instance.
+ @param Instance The visible image instance is found.
+ @param Format The format of the image. Examples: BMP, JPEG.
+ @param ImageData The image data for the badge file. Currently only
+ supports the .bmp file format.
+ @param ImageSize The size of the image returned.
+ @param Attribute The display attributes of the image returned.
+ @param CoordinateX The X coordinate of the image.
+ @param CoordinateY The Y coordinate of the image.
+
+ @retval EFI_SUCCESS The image was fetched successfully.
+ @retval EFI_NOT_FOUND The specified image could not be found.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_BADGING_GET_IMAGE)(
+ IN EFI_OEM_BADGING_PROTOCOL *This,
+ IN OUT UINT32 *Instance,
+ OUT EFI_BADGING_FORMAT *Format,
+ OUT UINT8 **ImageData,
+ OUT UINTN *ImageSize,
+ OUT EFI_BADGING_DISPLAY_ATTRIBUTE *Attribute,
+ OUT UINTN *CoordinateX,
+ OUT UINTN *CoordinateY
+);
+
+
+struct _EFI_OEM_BADGING_PROTOCOL {
+ EFI_BADGING_GET_IMAGE GetImage;
+};
+
+
+extern EFI_GUID gEfiOEMBadgingProtocolGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/Ps2Policy.h b/Core/IntelFrameworkModulePkg/Include/Protocol/Ps2Policy.h
new file mode 100644
index 0000000000..8e915edaf5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/Ps2Policy.h
@@ -0,0 +1,41 @@
+/** @file
+ PS/2 policy protocol abstracts the specific platform initialization and settings.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _PS2_POLICY_PROTOCOL_H_
+#define _PS2_POLICY_PROTOCOL_H_
+
+#define EFI_PS2_POLICY_PROTOCOL_GUID \
+ { \
+ 0x4df19259, 0xdc71, 0x4d46, {0xbe, 0xf1, 0x35, 0x7b, 0xb5, 0x78, 0xc4, 0x18 } \
+ }
+
+#define EFI_KEYBOARD_CAPSLOCK 0x0004
+#define EFI_KEYBOARD_NUMLOCK 0x0002
+#define EFI_KEYBOARD_SCROLLLOCK 0x0001
+
+typedef
+EFI_STATUS
+(EFIAPI *EFI_PS2_INIT_HARDWARE) (
+ IN EFI_HANDLE Handle
+ );
+
+typedef struct {
+ UINT8 KeyboardLight;
+ EFI_PS2_INIT_HARDWARE Ps2InitHardware;
+} EFI_PS2_POLICY_PROTOCOL;
+
+extern EFI_GUID gEfiPs2PolicyProtocolGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Include/Protocol/VgaMiniPort.h b/Core/IntelFrameworkModulePkg/Include/Protocol/VgaMiniPort.h
new file mode 100644
index 0000000000..e912eed213
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Include/Protocol/VgaMiniPort.h
@@ -0,0 +1,94 @@
+/** @file
+ The VGA Mini Port Protocol used to set the text display mode of a VGA controller.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials are licensed and made available under
+the terms and conditions of the BSD License that accompanies this distribution.
+The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php.
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __VGA_MINI_PORT_H_
+#define __VGA_MINI_PORT_H_
+
+///
+/// Global ID for the EFI_VGA_MINI_PORT_PROTOCOL.
+///
+#define EFI_VGA_MINI_PORT_PROTOCOL_GUID \
+ { \
+ 0xc7735a2f, 0x88f5, 0x4882, {0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3 } \
+ }
+
+///
+/// Forward declaration for the EFI_VGA_MINI_PORT_PROTOCOL.
+///
+typedef struct _EFI_VGA_MINI_PORT_PROTOCOL EFI_VGA_MINI_PORT_PROTOCOL;
+
+/**
+ Sets the text display mode of a VGA controller.
+
+ Sets the text display mode of the VGA controller to the mode specified by
+ ModeNumber. A ModeNumber of 0 is a request for an 80x25 text mode. A
+ ModeNumber of 1 is a request for an 80x50 text mode. If ModeNumber is greater
+ than MaxModeNumber, then EFI_UNSUPPORTED is returned. If the VGA controller
+ is not functioning properly, then EFI_DEVICE_ERROR is returned. If the VGA
+ controller is sucessfully set to the mode number specified by ModeNumber, then
+ EFI_SUCCESS is returned.
+
+ @param[in] This A pointer to the EFI_VGA_MINI_PORT_PROTOCOL instance.
+ @param[in] ModeNumber The requested mode number. 0 for 80x25. 1 for 80x5.
+
+ @retval EFI_SUCCESS The mode number was set.
+ @retval EFI_UNSUPPORTED The mode number specified by ModeNumber is not supported.
+ @retval EFI_DEVICE_ERROR The device is not functioning properly.
+
+**/
+typedef
+EFI_STATUS
+(EFIAPI *EFI_VGA_MINI_PORT_SET_MODE)(
+ IN EFI_VGA_MINI_PORT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+struct _EFI_VGA_MINI_PORT_PROTOCOL {
+ EFI_VGA_MINI_PORT_SET_MODE SetMode;
+ ///
+ /// MMIO base address of the VGA text mode framebuffer. Typically set to 0xB8000.
+ ///
+ UINT64 VgaMemoryOffset;
+ ///
+ /// I/O Port address for the VGA CRTC address register. Typically set to 0x3D4.
+ ///
+ UINT64 CrtcAddressRegisterOffset;
+ ///
+ /// I/O Port address for the VGA CRTC data register. Typically set to 0x3D5.
+ ///
+ UINT64 CrtcDataRegisterOffset;
+ ///
+ /// PCI Controller MMIO BAR index of the VGA text mode frame buffer. Typically
+ /// set to EFI_PCI_IO_PASS_THROUGH_BAR
+ ///
+ UINT8 VgaMemoryBar;
+ ///
+ /// PCI Controller I/O BAR index of the VGA CRTC address register. Typically
+ /// set to EFI_PCI_IO_PASS_THROUGH_BAR
+ ///
+ UINT8 CrtcAddressRegisterBar;
+ ///
+ /// PCI Controller I/O BAR index of the VGA CRTC data register. Typically set
+ /// to EFI_PCI_IO_PASS_THROUGH_BAR
+ ///
+ UINT8 CrtcDataRegisterBar;
+ ///
+ /// The maximum number of text modes that this VGA controller supports.
+ ///
+ UINT8 MaxMode;
+};
+
+extern EFI_GUID gEfiVgaMiniPortProtocolGuid;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
new file mode 100644
index 0000000000..8bbde8e2c9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
@@ -0,0 +1,283 @@
+## @file
+# Intel Framework Module Package.
+#
+# This package contains the definitions and module implementation
+# which follows Intel EFI Framework Specification.
+#
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ DEC_SPECIFICATION = 0x00010005
+ PACKAGE_NAME = IntelFrameworkModulePkg
+ PACKAGE_UNI_FILE = IntelFrameworkModulePkg.uni
+ PACKAGE_GUID = 88894582-7553-4822-B484-624E24B6DECF
+ PACKAGE_VERSION = 0.96
+
+[Includes]
+ Include # Root include for the package
+
+[LibraryClasses]
+ ## @libraryclass Platform BDS library definition about platform specific behavior.
+ PlatformBdsLib|Include/Library/PlatformBdsLib.h
+
+ ## @libraryclass Generic BDS library definition, include the data structure and function.
+ GenericBdsLib|Include/Library/GenericBdsLib.h
+
+[Guids]
+ ## IntelFrameworkModule package token space guid
+ # Include/Guid/IntelFrameworkModulePkgTokenSpace.h
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid = { 0xD3705011, 0xBC19, 0x4af7, { 0xBE, 0x16, 0xF6, 0x80, 0x30, 0x37, 0x8C, 0x15 }}
+
+ ## GUID identifies Data Hub records logged by Status Code Runtime Protocol.
+ # Include/Guid/DataHubStatusCodeRecord.h
+ gEfiDataHubStatusCodeRecordGuid = { 0xD083E94C, 0x6560, 0x42E4, { 0xB6, 0xD4, 0x2D, 0xF7, 0x5A, 0xDF, 0x6A, 0x2A }}
+
+ ## GUID indicates the tiano custom compress/decompress algorithm.
+ # Include/Guid/TianoDecompress.h
+ gTianoCustomDecompressGuid = { 0xA31280AD, 0x481E, 0x41B6, { 0x95, 0xE8, 0x12, 0x7F, 0x4C, 0x98, 0x47, 0x79 }}
+
+ ## Include/Guid/AcpiVariable.h
+ gEfiAcpiVariableCompatiblityGuid = { 0xc020489e, 0x6db2, 0x4ef2, { 0x9a, 0xa5, 0xca, 0x6, 0xfc, 0x11, 0xd3, 0x6a }}
+
+ ## Include/Guid/LegacyBios.h
+ gEfiLegacyBiosGuid = { 0x2E3044AC, 0x879F, 0x490F, { 0x97, 0x60, 0xBB, 0xDF, 0xAF, 0x69, 0x5F, 0x50 }}
+
+ ## Include/Guid/LegacyDevOrder.h
+ gEfiLegacyDevOrderVariableGuid = { 0xa56074db, 0x65fe, 0x45f7, {0xbd, 0x21, 0x2d, 0x2b, 0xdd, 0x8e, 0x96, 0x52 }}
+
+ ## Include/Guid/CapsuleDataFile.h
+ gEfiUpdateDataFileGuid = { 0x283fa2ee, 0x532c, 0x484d, { 0x93, 0x83, 0x9f, 0x93, 0xb3, 0x6f, 0xb, 0x7e }}
+
+ ## Include/Guid/BlockIoVendor.h
+ gBlockIoVendorGuid = { 0xcf31fac5, 0xc24e, 0x11d2, {0x85, 0xf3, 0x0, 0xa0, 0xc9, 0x3e, 0xc9, 0x3b }}
+
+ ## Include/Guid/BdsHii.h
+ gFrontPageFormSetGuid = { 0x9e0c30bc, 0x3f06, 0x4ba6, {0x82, 0x88, 0x9, 0x17, 0x9b, 0x85, 0x5d, 0xbe }}
+ gBootManagerFormSetGuid = { 0x847bc3fe, 0xb974, 0x446d, {0x94, 0x49, 0x5a, 0xd5, 0x41, 0x2e, 0x99, 0x3b }}
+ gDeviceManagerFormSetGuid = { 0x3ebfa8e6, 0x511d, 0x4b5b, {0xa9, 0x5f, 0xfb, 0x38, 0x26, 0xf, 0x1c, 0x27 }}
+ gDriverHealthFormSetGuid = { 0xf76e0a70, 0xb5ed, 0x4c38, {0xac, 0x9a, 0xe5, 0xf5, 0x4b, 0xf1, 0x6e, 0x34 }}
+ gBootMaintFormSetGuid = { 0x642237c7, 0x35d4, 0x472d, {0x83, 0x65, 0x12, 0xe0, 0xcc, 0xf2, 0x7a, 0x22 }}
+ gFileExploreFormSetGuid = { 0x1f2d63e1, 0xfebd, 0x4dc7, {0x9c, 0xc5, 0xba, 0x2b, 0x1c, 0xef, 0x9c, 0x5b }}
+
+ ## Include/Guid/BdsLibHii.h
+ gBdsLibStringPackageGuid = { 0x3b4d9b23, 0x95ac, 0x44f6, {0x9f, 0xcd, 0xe, 0x95, 0x94, 0x58, 0x6c, 0x72 }}
+
+ ## Include/Guid/LastEnumLang.h
+ gLastEnumLangGuid = { 0xe8c545b, 0xa2ee, 0x470d, {0x8e, 0x26, 0xbd, 0xa1, 0xa1, 0x3c, 0xa, 0xa3 }}
+
+ ## Include/Guid/HdBootVariable.h
+ gHdBootDevicePathVariablGuid = { 0xfab7e9e1, 0x39dd, 0x4f2b, {0x84, 0x8, 0xe2, 0xe, 0x90, 0x6c, 0xb6, 0xde }}
+
+[Protocols]
+ ## Vga Mini port binding for a VGA controller
+ # Include/Protocol/VgaMiniPort.h
+ gEfiVgaMiniPortProtocolGuid = { 0xc7735a2f, 0x88f5, 0x4882, { 0xae, 0x63, 0xfa, 0xac, 0x8c, 0x8b, 0x86, 0xb3 }}
+
+ ## ISA I/O Protocol is used to perform ISA device Io/Mem operations.
+ # Include/Protocol/IsaIo.h
+ gEfiIsaIoProtocolGuid = { 0x7ee2bd44, 0x3da0, 0x11d4, { 0x9a, 0x38, 0x0, 0x90, 0x27, 0x3f, 0xc1, 0x4d }}
+
+ ## ISA Acpi Protocol is used to operate and communicate with ISA device.
+ # Include/Protocol/IsaAcpi.h
+ gEfiIsaAcpiProtocolGuid = { 0x64a892dc, 0x5561, 0x4536, { 0x92, 0xc7, 0x79, 0x9b, 0xfc, 0x18, 0x33, 0x55 }}
+
+ ## PS/2 policy protocol abstracts the specific platform initialization and setting.
+ # Include/Protocol/Ps2Policy.h
+ gEfiPs2PolicyProtocolGuid = { 0x4DF19259, 0xDC71, 0x4D46, { 0xBE, 0xF1, 0x35, 0x7B, 0xB5, 0x78, 0xC4, 0x18 }}
+
+ ## OEM Badging Protocol defines the interface to get the OEM badging image with the dispaly attribute.
+ # Include/Protocol/OEMBadging.h
+ gEfiOEMBadgingProtocolGuid = { 0x170E13C0, 0xBF1B, 0x4218, { 0x87, 0x1D, 0x2A, 0xBD, 0xC6, 0xF8, 0x87, 0xBC }}
+
+ ## Include/Protocol/ExitPmAuth.h
+ gExitPmAuthProtocolGuid = { 0xd088a413, 0xa70, 0x4217, { 0xba, 0x55, 0x9a, 0x3c, 0xb6, 0x5c, 0x41, 0xb3 }}
+
+#
+# [Error.gEfiIntelFrameworkModulePkgTokenSpaceGuid]
+# 0x80000001 | Invalid value provided.
+# 0x80000002 | Reserved bits must be set to zero.
+#
+
+[PcdsFeatureFlag]
+ ## Indicates if OEM device is enabled as StatusCode report device.
+ # It is only used in Framework StatusCode implementation. <BR><BR>
+ # TRUE - Enable OEM device.<BR>
+ # FALSE - Disable OEM device.<BR>
+ # @Prompt Report StatusCode via OEM Device
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseOEM|FALSE|BOOLEAN|0x00010024
+
+ ## Indicates if StatusCode report is loged into DataHub.<BR><BR>
+ # TRUE - Log StatusCode report into DataHub.<BR>
+ # FALSE - Does not log StatusCode report into DataHub.<BR>
+ # @Prompt Log StatusCode into DataHub
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseDataHub|FALSE|BOOLEAN|0x00010029
+
+ ## Indicates if Serial device uses half hand shake.<BR><BR>
+ # TRUE - Serial device uses half hand shake.<BR>
+ # FALSE - Serial device doesn't use half hand shake.<BR>
+ # @Prompt Enable Serial device Half Hand Shake
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE|BOOLEAN|0x00010043
+
+ ## Indicates if Legacy support is needed for ACPI S3 Save.<BR><BR>
+ # TRUE - Support Legacy OS with S3 boot.<BR>
+ # FALSE - Does not support Legacy OS with S3 boot.<BR>
+ # @Prompt Turn on Legacy Support in S3 Boot
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport|TRUE|BOOLEAN|0x00010044
+
+ ## Indicates if PS2 keyboard does a extended verification during start.
+ # Extended verification will take some performance. It can be set to FALSE for boot performance.<BR><BR>
+ # TRUE - Turn on PS2 keyboard extended verification.<BR>
+ # FALSE - Turn off PS2 keyboard extended verification.<BR>
+ # @Prompt Turn on PS2 Keyboard Extended Verification
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2KbdExtendedVerification|TRUE|BOOLEAN|0x00010045
+
+ ## Indicates if Framework Acpi Support protocol is installed.<BR><BR>
+ # TRUE - Install Framework Acpi Support protocol.<BR>
+ # FALSE - Doesn't install Framework Acpi Support protocol.<BR>
+ # @Prompt Enable Framework Acpi Support
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdInstallAcpiSupportProtocol|TRUE|BOOLEAN|0x00010046
+
+
+ ## Indicates if PS2 mouse does a extended verification during start.
+ # Extended verification will take some performance. It can be set to FALSE for boot performance.<BR><BR>
+ # TRUE - Turn on PS2 mouse extended verification. <BR>
+ # FALSE - Turn off PS2 mouse extended verification. <BR>
+ # @Prompt Turn on PS2 Mouse Extended Verification
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPs2MouseExtendedVerification|TRUE|BOOLEAN|0x00010047
+
+ ## Indicates if only Boot logo is showed and all message output is disabled in BDS.<BR><BR>
+ # TRUE - Only Boot Logo is showed in boot.<BR>
+ # FALSE - All messages and Boot Logo are showed in boot.<BR>
+ # @Prompt Enable Boot Logo only
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootlogoOnlyEnable|FALSE|BOOLEAN|0x00010048
+
+[PcdsFixedAtBuild, PcdsPatchableInModule]
+ ## FFS filename to find the default BMP Logo file.
+ # @Prompt FFS Name of Boot Logo File
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLogoFile |{ 0x99, 0x8b, 0xB2, 0x7B, 0xBB, 0x61, 0xD5, 0x11, 0x9A, 0x5D, 0x00, 0x90, 0x27, 0x3F, 0xC1, 0x4D }|VOID*|0x40000003
+
+ ## FFS filename to find the shell application.
+ # @Prompt FFS Name of Shell Application
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile|{ 0xB7, 0xD6, 0x7A, 0xC5, 0x15, 0x05, 0xA8, 0x40, 0x9D, 0x21, 0x55, 0x16, 0x52, 0x85, 0x4E, 0x37 }|VOID*|0x40000004
+
+ ## ISA Bus features to support DMA, SlaveDMA and ISA Memory. <BR><BR>
+ # BIT0 indicates if DMA is supported<BR>
+ # BIT1 indicates if only slave DMA is supported<BR>
+ # BIT2 indicates if ISA memory is supported<BR>
+ # Other BITs are reseved and must be zero.
+ # If more than one features are supported, the different BIT will be enabled at the same time.
+ # @Prompt ISA Bus Features
+ # @Expression 0x80000002 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSupportedFeatures & 0xF8) == 0
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSupportedFeatures|0x05|UINT8|0x00010040
+
+[PcdsDynamic, PcdsDynamicEx]
+ ## Indicates if the machine has completed one boot cycle before.
+ # After the complete boot, BootState will be set to FALSE.<BR><BR>
+ # TRUE - The complete boot cycle has not happened before.<BR>
+ # FALSE - The complete boot cycle has happened before.<BR>
+ # @Prompt Boot State Flag
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState|TRUE|BOOLEAN|0x0001002f
+
+[PcdsFixedAtBuild, PcdsDynamic, PcdsDynamicEx, PcdsPatchableInModule]
+ ## I/O Base address of floppy device controller.
+ # @Prompt I/O Base Address of Floppy Device Controller
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFdcBaseAddress|0x3f0|UINT16|0x30000000
+
+ ## Indicates if BiosVideo driver will switch to 80x25 Text VGA Mode when exiting boot service.<BR><BR>
+ # TRUE - Switch to Text VGA Mode.<BR>
+ # FALSE - Does not switch to Text VGA Mode.<BR>
+ # @Prompt Switch to Text VGA Mode on UEFI Boot
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoSetTextVgaModeEnable|FALSE|BOOLEAN|0x30000001
+
+ ## Indicates if BiosVideo driver will check for VESA BIOS Extension service support.<BR><BR>
+ # TRUE - Check for VESA BIOS Extension service.<BR>
+ # FALSE - Does not check for VESA BIOS Extension service.<BR>
+ # @Prompt Enable Check for VESA BIOS Extension Service
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVbeEnable|TRUE|BOOLEAN|0x30000002
+
+ ## Indicates if BiosVideo driver will check for VGA service support.
+ # NOTE: If both PcdBiosVideoCheckVbeEnable and PcdBiosVideoCheckVgaEnable are set to FALSE,
+ # that means Graphics Output protocol will not be installed, the VGA miniport protocol will be installed instead.<BR><BR>
+ # TRUE - Check for VGA service.<BR>
+ # FALSE - Does not check for VGA service.<BR>
+ # @Prompt Enable Check for VGA Service
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBiosVideoCheckVgaEnable|TRUE|BOOLEAN|0x30000003
+
+ ## Indicates if memory space for legacy region will be set as cacheable.<BR><BR>
+ # TRUE - Set cachebility for legacy region.<BR>
+ # FALSE - Does not set cachebility for legacy region.<BR>
+ # @Prompt Enable Cachebility for Legacy Region
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLegacyBiosCacheLegacyRegion|TRUE|BOOLEAN|0x00000004
+
+ ## Specify memory size with bytes to reserve EBDA below 640K for OPROM.
+ # The value should be a multiple of 4KB.
+ # @Prompt Reserved EBDA Memory Size
+ # @Expression 0x80000001 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize < 0xA0000) AND ((gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize & 0x1000) == 0)
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEbdaReservedMemorySize|0x8000|UINT32|0x30000005
+
+ ## Specify memory base address for OPROM to find free memory.
+ # Some OPROMs do not use EBDA or PMM to allocate memory for its usage,
+ # instead they find the memory filled with zero from 0x20000.
+ # The value should be a multiple of 4KB.
+ # The range should be below the EBDA reserved range from
+ # (CONVENTIONAL_MEMORY_TOP - Reserved EBDA Memory Size) to CONVENTIONAL_MEMORY_TOP.
+ # @Prompt Reserved Memory Base Address for OPROM
+ # @Expression 0x80000001 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase >= 0x20000) AND ((gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase & 0x1000) == 0)
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemoryBase|0x60000|UINT32|0x3000000c
+
+ ## Specify memory size with bytes for OPROM to find free memory.
+ # The value should be a multiple of 4KB. And the range should be below the EBDA reserved range from
+ # (CONVENTIONAL_MEMORY_TOP - Reserved EBDA Memory Size) to CONVENTIONAL_MEMORY_TOP.
+ # @Prompt Reserved Memory Size for OPROM
+ # @Expression 0x80000001 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize < 0x80000) AND ((gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize & 0x1000) == 0)
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdOpromReservedMemorySize|0x28000|UINT32|0x3000000d
+
+ ## Specify memory size with page number for a pre-allocated reserved memory to be used
+ # by PEI in S3 phase. The default size 32K. When changing the value make sure the memory size
+ # is large enough to meet PEI requirement in the S3 phase.
+ # @Prompt Reserved S3 Boot ACPI Memory Size
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3AcpiReservedMemorySize|0x8000|UINT32|0x30000006
+
+ ## Specify memory size for boot script executor stack usage in S3 phase.
+ # The default size 32K. When changing the value make sure the memory size is large enough
+ # to meet boot script executor requirement in the S3 phase.
+ # @Prompt Reserved S3 Boot Script Stack ACPI Memory Size
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize|0x8000|UINT32|0x30000007
+
+ ## Specify the end of address below 1MB for the OPROM.
+ # The last shadowed OpROM should not exceed this address.
+ # @Prompt Top Address of Shadowed Legacy OpROM
+ # @Expression 0x80000001 | gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEndOpromShadowAddress < 0x100000
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdEndOpromShadowAddress|0xdffff|UINT32|0x30000008
+
+ ## Specify the low PMM (Post Memory Manager) size with bytes below 1MB.
+ # The value should be a multiple of 4KB.
+ # @Prompt Low PMM (Post Memory Manager) Size
+ # @Expression 0x80000001 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLowPmmMemorySize < 0x100000) AND ((gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLowPmmMemorySize & 0x1000) == 0)
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdLowPmmMemorySize|0x10000|UINT32|0x30000009
+
+ ## Specify the high PMM (Post Memory Manager) size with bytes above 1MB.
+ # The value should be a multiple of 4KB.
+ # @Prompt High PMM (Post Memory Manager) Size
+ # @Expression 0x80000001 | (gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHighPmmMemorySize & 0x1000) == 0
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdHighPmmMemorySize|0x400000|UINT32|0x3000000a
+
+ ## Indicates if to use the optimized timing for best PS2 detection performance.
+ # Note this PCD could be set to TRUE for best boot performance and set to FALSE for best device compatibility.<BR><BR>
+ # TRUE - Use the optimized timing for best PS2 detection performance.<BR>
+ # FALSE - Use the normal timing to detect PS2.<BR>
+ # @Prompt Enable fast PS2 detection
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdFastPS2Detection|FALSE|BOOLEAN|0x3000000b
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ IntelFrameworkModulePkgExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
new file mode 100644
index 0000000000..b4adab11ef
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.dsc
@@ -0,0 +1,198 @@
+## @file
+# Intel Framework Reference Module Package for All Architectures
+#
+# This file is used to build all modules in IntelFrameworkModulePkg.
+#
+#Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+#This program and the accompanying materials are licensed and made available under
+#the terms and conditions of the BSD License that accompanies this distribution.
+#The full text of the license may be found at
+#http://opensource.org/licenses/bsd-license.php.
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+################################################################################
+#
+# Defines Section - statements that will be processed to create a Makefile.
+#
+################################################################################
+[Defines]
+ PLATFORM_NAME = IntelFrameworkModuleAll
+ PLATFORM_GUID = FFF87D9A-E5BB-4AFF-9ADE-8645492E8087
+ PLATFORM_VERSION = 0.96
+ DSC_SPECIFICATION = 0x00010005
+ OUTPUT_DIRECTORY = Build/IntelFrameworkModuleAll
+ SUPPORTED_ARCHITECTURES = IA32|IPF|X64|EBC|ARM
+ BUILD_TARGETS = DEBUG|RELEASE
+ SKUID_IDENTIFIER = DEFAULT
+
+################################################################################
+#
+# SKU Identification section - list of all SKU IDs supported by this
+# Platform.
+#
+################################################################################
+[SkuIds]
+ 0|DEFAULT # The entry: 0|DEFAULT is reserved and always required.
+
+[LibraryClasses]
+ CacheMaintenanceLib|MdePkg/Library/BaseCacheMaintenanceLib/BaseCacheMaintenanceLib.inf
+ DebugAgentLib|MdeModulePkg/Library/DebugAgentLibNull/DebugAgentLibNull.inf
+ DebugLib|MdePkg/Library/BaseDebugLibNull/BaseDebugLibNull.inf
+ DebugPrintErrorLevelLib|MdePkg/Library/BaseDebugPrintErrorLevelLib/BaseDebugPrintErrorLevelLib.inf
+ BaseLib|MdePkg/Library/BaseLib/BaseLib.inf
+ SynchronizationLib|MdePkg/Library/BaseSynchronizationLib/BaseSynchronizationLib.inf
+ BaseMemoryLib|MdePkg/Library/BaseMemoryLib/BaseMemoryLib.inf
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ PerformanceLib|MdePkg/Library/BasePerformanceLibNull/BasePerformanceLibNull.inf
+ PrintLib|MdePkg/Library/BasePrintLib/BasePrintLib.inf
+ TimerLib|MdePkg/Library/BaseTimerLibNullTemplate/BaseTimerLibNullTemplate.inf
+ OemHookStatusCodeLib|MdeModulePkg/Library/OemHookStatusCodeLibNull/OemHookStatusCodeLibNull.inf
+ SerialPortLib|MdePkg/Library/BaseSerialPortLibNull/BaseSerialPortLibNull.inf
+ DevicePathLib|MdePkg/Library/UefiDevicePathLib/UefiDevicePathLib.inf
+ GenericBdsLib|IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
+ UefiHiiServicesLib|MdeModulePkg/Library/UefiHiiServicesLib/UefiHiiServicesLib.inf
+ HiiLib|MdeModulePkg/Library/UefiHiiLib/UefiHiiLib.inf
+ PlatformBdsLib|IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
+ CapsuleLib|MdeModulePkg/Library/DxeCapsuleLibNull/DxeCapsuleLibNull.inf
+ PeCoffLib|MdePkg/Library/BasePeCoffLib/BasePeCoffLib.inf
+ PeCoffExtraActionLib|MdePkg/Library/BasePeCoffExtraActionLibNull/BasePeCoffExtraActionLibNull.inf
+ PeCoffGetEntryPointLib|MdePkg/Library/BasePeCoffGetEntryPointLib/BasePeCoffGetEntryPointLib.inf
+ DxeServicesLib|MdePkg/Library/DxeServicesLib/DxeServicesLib.inf
+ ReportStatusCodeLib|MdePkg/Library/BaseReportStatusCodeLibNull/BaseReportStatusCodeLibNull.inf
+ PeiServicesTablePointerLib|MdePkg/Library/PeiServicesTablePointerLib/PeiServicesTablePointerLib.inf
+ PeimEntryPoint|MdePkg/Library/PeimEntryPoint/PeimEntryPoint.inf
+ PeiServicesLib|MdePkg/Library/PeiServicesLib/PeiServicesLib.inf
+ UefiBootServicesTableLib|MdePkg/Library/UefiBootServicesTableLib/UefiBootServicesTableLib.inf
+ UefiDriverEntryPoint|MdePkg/Library/UefiDriverEntryPoint/UefiDriverEntryPoint.inf
+ UefiLib|MdePkg/Library/UefiLib/UefiLib.inf
+ UefiRuntimeServicesTableLib|MdePkg/Library/UefiRuntimeServicesTableLib/UefiRuntimeServicesTableLib.inf
+ DxeServicesTableLib|MdePkg/Library/DxeServicesTableLib/DxeServicesTableLib.inf
+ UefiRuntimeLib|MdePkg/Library/UefiRuntimeLib/UefiRuntimeLib.inf
+ PcdLib|MdePkg/Library/DxePcdLib/DxePcdLib.inf
+ PalLib|MdePkg/Library/BasePalLibNull/BasePalLibNull.inf
+
+[LibraryClasses.common.PEIM]
+ HobLib|MdePkg/Library/PeiHobLib/PeiHobLib.inf
+ PcdLib|MdePkg/Library/PeiPcdLib/PeiPcdLib.inf
+ MemoryAllocationLib|MdePkg/Library/PeiMemoryAllocationLib/PeiMemoryAllocationLib.inf
+
+[LibraryClasses.EBC.PEIM]
+ IoLib|MdePkg/Library/PeiIoLibCpuIo/PeiIoLibCpuIo.inf
+
+[LibraryClasses.common.DXE_DRIVER]
+ LockBoxLib|MdeModulePkg/Library/SmmLockBoxLib/SmmLockBoxDxeLib.inf
+
+[LibraryClasses.common.DXE_DRIVER, LibraryClasses.common.DXE_RUNTIME_DRIVER, LibraryClasses.common.UEFI_DRIVER]
+ HobLib|MdePkg/Library/DxeHobLib/DxeHobLib.inf
+ MemoryAllocationLib|MdePkg/Library/UefiMemoryAllocationLib/UefiMemoryAllocationLib.inf
+
+[LibraryClasses.common.DXE_RUNTIME_DRIVER]
+ DebugLib|MdePkg/Library/UefiDebugLibConOut/UefiDebugLibConOut.inf
+
+################################################################################
+#
+# Pcd Section - list of all EDK II PCD Entries defined by this Platform
+#
+################################################################################
+[PcdsFeatureFlag]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdIsaBusSerialUseHalfHandshake|FALSE
+
+[PcdsFixedAtBuild]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask|0x0f
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask|0x06
+ gEfiMdePkgTokenSpaceGuid.PcdPciExpressBaseAddress|0xE0000000
+
+[PcdsFixedAtBuild.IPF]
+ gEfiMdePkgTokenSpaceGuid.PcdIoBlockBaseAddressForIpf|0x0ffffc000000
+
+###################################################################################################
+#
+# Components Section - list of the modules and components that will be processed by compilation
+# tools and the EDK II tools to generate PE32/PE32+/Coff image files.
+#
+# Note: The EDK II DSC file is not used to specify how compiled binary images get placed
+# into firmware volume images. This section is just a list of modules to compile from
+# source into UEFI-compliant binaries.
+# It is the FDF file that contains information on combining binary files into firmware
+# volume images, whose concept is beyond UEFI and is described in PI specification.
+# Binary modules do not need to be listed in this section, as they should be
+# specified in the FDF file. For example: Shell binary (Shell_Full.efi), FAT binary (Fat.efi),
+# Logo (Logo.bmp), and etc.
+# There may also be modules listed in this section that are not required in the FDF file,
+# When a module listed here is excluded from FDF file, then UEFI-compliant binary will be
+# generated for it, but the binary will not be put into any firmware volume.
+#
+###################################################################################################
+
+[Components]
+ IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
+ IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
+ IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.inf
+ IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.inf
+ IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
+ IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.inf
+ IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
+ IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
+ IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
+ IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf
+ IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
+ IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
+
+ IntelFrameworkModulePkg/Bus/Pci/IdeBusDxe/IdeBusDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/IsaBusDxe/IsaBusDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/IsaIoDxe/IsaIoDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/IsaFloppyPei/IsaFloppyPei.inf
+ IntelFrameworkModulePkg/Bus/Isa/IsaFloppyDxe/IsaFloppyDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/IsaSerialDxe/IsaSerialDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/Ps2KeyboardDxe/Ps2keyboardDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/Ps2MouseDxe/Ps2MouseDxe.inf
+ IntelFrameworkModulePkg/Bus/Isa/Ps2MouseAbsolutePointerDxe/Ps2MouseAbsolutePointerDxe.inf
+ IntelFrameworkModulePkg/Bus/Pci/VgaMiniPortDxe/VgaMiniPortDxe.inf
+
+ IntelFrameworkModulePkg/Csm/BiosThunk/KeyboardDxe/KeyboardDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/VideoDxe/VideoDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/BlockIoDxe/BlockIoDxe.inf
+ IntelFrameworkModulePkg/Csm/BiosThunk/Snp16Dxe/Snp16Dxe.inf
+
+ IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.inf
+ IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
+ IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf
+ IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf
+ IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.inf
+ IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf
+ IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
+ IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf
+ IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf
+ IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
+ IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf
+
+[Components.IA32,Components.X64]
+ IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
+ IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
+
+[Components.IA32,Components.X64,Components.IPF]
+ IntelFrameworkModulePkg/Csm/LegacyBiosDxe/LegacyBiosDxe.inf
+
+[Components.IA32]
+ IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf
+ IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf {
+ <LibraryClasses>
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ }
+
+[Components.X64]
+ IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf
+ IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf {
+ <LibraryClasses>
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ }
+
+[Components.IPF]
+ IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf {
+ <LibraryClasses>
+ IoLib|MdePkg/Library/BaseIoLibIntrinsic/BaseIoLibIntrinsic.inf
+ }
diff --git a/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.uni b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.uni
new file mode 100644
index 0000000000..50106e10d5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkg.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkgExtra.uni b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkgExtra.uni
new file mode 100644
index 0000000000..15fdff98ad
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/IntelFrameworkModulePkgExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.c b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.c
new file mode 100644
index 0000000000..2e527234e2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.c
@@ -0,0 +1,1050 @@
+/** @file
+ UEFI and Tiano Custom Decompress Library
+ It will do Tiano or UEFI decompress with different verison parameter.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BaseUefiTianoCustomDecompressLibInternals.h"
+
+/**
+ Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
+
+ @param Sd The global scratch data
+ @param NumOfBits The number of bits to shift and read.
+**/
+VOID
+FillBuf (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfBits
+ )
+{
+ //
+ // Left shift NumOfBits of bits in advance
+ //
+ Sd->mBitBuf = (UINT32) (Sd->mBitBuf << NumOfBits);
+
+ //
+ // Copy data needed in bytes into mSbuBitBuf
+ //
+ while (NumOfBits > Sd->mBitCount) {
+
+ Sd->mBitBuf |= (UINT32) (Sd->mSubBitBuf << (NumOfBits = (UINT16) (NumOfBits - Sd->mBitCount)));
+
+ if (Sd->mCompSize > 0) {
+ //
+ // Get 1 byte into SubBitBuf
+ //
+ Sd->mCompSize--;
+ Sd->mSubBitBuf = 0;
+ Sd->mSubBitBuf = Sd->mSrcBase[Sd->mInBuf++];
+ Sd->mBitCount = 8;
+
+ } else {
+ //
+ // No more bits from the source, just pad zero bit.
+ //
+ Sd->mSubBitBuf = 0;
+ Sd->mBitCount = 8;
+
+ }
+ }
+
+ //
+ // Calculate additional bit count read to update mBitCount
+ //
+ Sd->mBitCount = (UINT16) (Sd->mBitCount - NumOfBits);
+
+ //
+ // Copy NumOfBits of bits from mSubBitBuf into mBitBuf
+ //
+ Sd->mBitBuf |= Sd->mSubBitBuf >> Sd->mBitCount;
+}
+
+/**
+ Get NumOfBits of bits out from mBitBuf
+
+ Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
+ NumOfBits of bits from source. Returns NumOfBits of bits that are
+ popped out.
+
+ @param Sd The global scratch data.
+ @param NumOfBits The number of bits to pop and read.
+
+ @return The bits that are popped out.
+
+**/
+UINT32
+GetBits (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfBits
+ )
+{
+ UINT32 OutBits;
+
+ //
+ // Pop NumOfBits of Bits from Left
+ //
+ OutBits = (UINT32) (Sd->mBitBuf >> (BITBUFSIZ - NumOfBits));
+
+ //
+ // Fill up mBitBuf from source
+ //
+ FillBuf (Sd, NumOfBits);
+
+ return OutBits;
+}
+
+/**
+ Creates Huffman Code mapping table according to code length array.
+
+ Creates Huffman Code mapping table for Extra Set, Char&Len Set
+ and Position Set according to code length array.
+ If TableBits > 16, then ASSERT ().
+
+ @param Sd The global scratch data
+ @param NumOfChar Number of symbols in the symbol set
+ @param BitLen Code length array
+ @param TableBits The width of the mapping table
+ @param Table The table to be created.
+
+ @retval 0 OK.
+ @retval BAD_TABLE The table is corrupted.
+
+**/
+UINT16
+MakeTable (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfChar,
+ IN UINT8 *BitLen,
+ IN UINT16 TableBits,
+ OUT UINT16 *Table
+ )
+{
+ UINT16 Count[17];
+ UINT16 Weight[17];
+ UINT16 Start[18];
+ UINT16 *Pointer;
+ UINT16 Index3;
+ UINT16 Index;
+ UINT16 Len;
+ UINT16 Char;
+ UINT16 JuBits;
+ UINT16 Avail;
+ UINT16 NextCode;
+ UINT16 Mask;
+ UINT16 WordOfStart;
+ UINT16 WordOfCount;
+
+ //
+ // The maximum mapping table width supported by this internal
+ // working function is 16.
+ //
+ ASSERT (TableBits <= 16);
+
+ for (Index = 0; Index <= 16; Index++) {
+ Count[Index] = 0;
+ }
+
+ for (Index = 0; Index < NumOfChar; Index++) {
+ Count[BitLen[Index]]++;
+ }
+
+ Start[0] = 0;
+ Start[1] = 0;
+
+ for (Index = 1; Index <= 16; Index++) {
+ WordOfStart = Start[Index];
+ WordOfCount = Count[Index];
+ Start[Index + 1] = (UINT16) (WordOfStart + (WordOfCount << (16 - Index)));
+ }
+
+ if (Start[17] != 0) {
+ /*(1U << 16)*/
+ return (UINT16) BAD_TABLE;
+ }
+
+ JuBits = (UINT16) (16 - TableBits);
+
+ Weight[0] = 0;
+ for (Index = 1; Index <= TableBits; Index++) {
+ Start[Index] >>= JuBits;
+ Weight[Index] = (UINT16) (1U << (TableBits - Index));
+ }
+
+ while (Index <= 16) {
+ Weight[Index] = (UINT16) (1U << (16 - Index));
+ Index++;
+ }
+
+ Index = (UINT16) (Start[TableBits + 1] >> JuBits);
+
+ if (Index != 0) {
+ Index3 = (UINT16) (1U << TableBits);
+ if (Index < Index3) {
+ SetMem16 (Table + Index, (Index3 - Index) * sizeof (*Table), 0);
+ }
+ }
+
+ Avail = NumOfChar;
+ Mask = (UINT16) (1U << (15 - TableBits));
+
+ for (Char = 0; Char < NumOfChar; Char++) {
+
+ Len = BitLen[Char];
+ if (Len == 0 || Len >= 17) {
+ continue;
+ }
+
+ NextCode = (UINT16) (Start[Len] + Weight[Len]);
+
+ if (Len <= TableBits) {
+
+ for (Index = Start[Len]; Index < NextCode; Index++) {
+ Table[Index] = Char;
+ }
+
+ } else {
+
+ Index3 = Start[Len];
+ Pointer = &Table[Index3 >> JuBits];
+ Index = (UINT16) (Len - TableBits);
+
+ while (Index != 0) {
+ if (*Pointer == 0 && Avail < (2 * NC - 1)) {
+ Sd->mRight[Avail] = Sd->mLeft[Avail] = 0;
+ *Pointer = Avail++;
+ }
+
+ if (*Pointer < (2 * NC - 1)) {
+ if ((Index3 & Mask) != 0) {
+ Pointer = &Sd->mRight[*Pointer];
+ } else {
+ Pointer = &Sd->mLeft[*Pointer];
+ }
+ }
+
+ Index3 <<= 1;
+ Index--;
+ }
+
+ *Pointer = Char;
+
+ }
+
+ Start[Len] = NextCode;
+ }
+ //
+ // Succeeds
+ //
+ return 0;
+}
+
+/**
+ Decodes a position value.
+
+ Get a position value according to Position Huffman Table.
+
+ @param Sd the global scratch data
+
+ @return The position value decoded.
+**/
+UINT32
+DecodeP (
+ IN SCRATCH_DATA *Sd
+ )
+{
+ UINT16 Val;
+ UINT32 Mask;
+ UINT32 Pos;
+
+ Val = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
+
+ if (Val >= MAXNP) {
+ Mask = 1U << (BITBUFSIZ - 1 - 8);
+
+ do {
+
+ if ((Sd->mBitBuf & Mask) != 0) {
+ Val = Sd->mRight[Val];
+ } else {
+ Val = Sd->mLeft[Val];
+ }
+
+ Mask >>= 1;
+ } while (Val >= MAXNP);
+ }
+ //
+ // Advance what we have read
+ //
+ FillBuf (Sd, Sd->mPTLen[Val]);
+
+ Pos = Val;
+ if (Val > 1) {
+ Pos = (UINT32) ((1U << (Val - 1)) + GetBits (Sd, (UINT16) (Val - 1)));
+ }
+
+ return Pos;
+}
+
+/**
+ Reads code lengths for the Extra Set or the Position Set.
+
+ Read in the Extra Set or Pointion Set Length Arrary, then
+ generate the Huffman code mapping for them.
+
+ @param Sd The global scratch data.
+ @param nn Number of symbols.
+ @param nbit Number of bits needed to represent nn.
+ @param Special The special symbol that needs to be taken care of.
+
+ @retval 0 OK.
+ @retval BAD_TABLE Table is corrupted.
+
+**/
+UINT16
+ReadPTLen (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 nn,
+ IN UINT16 nbit,
+ IN UINT16 Special
+ )
+{
+ UINT16 Number;
+ UINT16 CharC;
+ UINT16 Index;
+ UINT32 Mask;
+
+ ASSERT (nn <= NPT);
+ //
+ // Read Extra Set Code Length Array size
+ //
+ Number = (UINT16) GetBits (Sd, nbit);
+
+ if (Number == 0) {
+ //
+ // This represents only Huffman code used
+ //
+ CharC = (UINT16) GetBits (Sd, nbit);
+
+ for (Index = 0; Index < 256; Index++) {
+ Sd->mPTTable[Index] = CharC;
+ }
+
+ SetMem (Sd->mPTLen, nn, 0);
+
+ return 0;
+ }
+
+ Index = 0;
+
+ while (Index < Number && Index < NPT) {
+
+ CharC = (UINT16) (Sd->mBitBuf >> (BITBUFSIZ - 3));
+
+ //
+ // If a code length is less than 7, then it is encoded as a 3-bit
+ // value. Or it is encoded as a series of "1"s followed by a
+ // terminating "0". The number of "1"s = Code length - 4.
+ //
+ if (CharC == 7) {
+ Mask = 1U << (BITBUFSIZ - 1 - 3);
+ while (Mask & Sd->mBitBuf) {
+ Mask >>= 1;
+ CharC += 1;
+ }
+ }
+
+ FillBuf (Sd, (UINT16) ((CharC < 7) ? 3 : CharC - 3));
+
+ Sd->mPTLen[Index++] = (UINT8) CharC;
+
+ //
+ // For Code&Len Set,
+ // After the third length of the code length concatenation,
+ // a 2-bit value is used to indicated the number of consecutive
+ // zero lengths after the third length.
+ //
+ if (Index == Special) {
+ CharC = (UINT16) GetBits (Sd, 2);
+ while ((INT16) (--CharC) >= 0 && Index < NPT) {
+ Sd->mPTLen[Index++] = 0;
+ }
+ }
+ }
+
+ while (Index < nn && Index < NPT) {
+ Sd->mPTLen[Index++] = 0;
+ }
+
+ return MakeTable (Sd, nn, Sd->mPTLen, 8, Sd->mPTTable);
+}
+
+/**
+ Reads code lengths for Char&Len Set.
+
+ Read in and decode the Char&Len Set Code Length Array, then
+ generate the Huffman Code mapping table for the Char&Len Set.
+
+ @param Sd the global scratch data
+
+**/
+VOID
+ReadCLen (
+ SCRATCH_DATA *Sd
+ )
+{
+ UINT16 Number;
+ UINT16 CharC;
+ UINT16 Index;
+ UINT32 Mask;
+
+ Number = (UINT16) GetBits (Sd, CBIT);
+
+ if (Number == 0) {
+ //
+ // This represents only Huffman code used
+ //
+ CharC = (UINT16) GetBits (Sd, CBIT);
+
+ SetMem (Sd->mCLen, NC, 0);
+
+ for (Index = 0; Index < 4096; Index++) {
+ Sd->mCTable[Index] = CharC;
+ }
+
+ return ;
+ }
+
+ Index = 0;
+ while (Index < Number && Index < NC) {
+ CharC = Sd->mPTTable[Sd->mBitBuf >> (BITBUFSIZ - 8)];
+ if (CharC >= NT) {
+ Mask = 1U << (BITBUFSIZ - 1 - 8);
+
+ do {
+
+ if (Mask & Sd->mBitBuf) {
+ CharC = Sd->mRight[CharC];
+ } else {
+ CharC = Sd->mLeft[CharC];
+ }
+
+ Mask >>= 1;
+
+ } while (CharC >= NT);
+ }
+ //
+ // Advance what we have read
+ //
+ FillBuf (Sd, Sd->mPTLen[CharC]);
+
+ if (CharC <= 2) {
+
+ if (CharC == 0) {
+ CharC = 1;
+ } else if (CharC == 1) {
+ CharC = (UINT16) (GetBits (Sd, 4) + 3);
+ } else if (CharC == 2) {
+ CharC = (UINT16) (GetBits (Sd, CBIT) + 20);
+ }
+
+ while ((INT16) (--CharC) >= 0 && Index < NC) {
+ Sd->mCLen[Index++] = 0;
+ }
+
+ } else {
+
+ Sd->mCLen[Index++] = (UINT8) (CharC - 2);
+
+ }
+ }
+
+ SetMem (Sd->mCLen + Index, NC - Index, 0);
+
+ MakeTable (Sd, NC, Sd->mCLen, 12, Sd->mCTable);
+
+ return ;
+}
+
+/**
+ Decode a character/length value.
+
+ Read one value from mBitBuf, Get one code from mBitBuf. If it is at block boundary, generates
+ Huffman code mapping table for Extra Set, Code&Len Set and
+ Position Set.
+
+ @param Sd The global scratch data.
+
+ @return The value decoded.
+
+**/
+UINT16
+DecodeC (
+ SCRATCH_DATA *Sd
+ )
+{
+ UINT16 Index2;
+ UINT32 Mask;
+
+ if (Sd->mBlockSize == 0) {
+ //
+ // Starting a new block
+ // Read BlockSize from block header
+ //
+ Sd->mBlockSize = (UINT16) GetBits (Sd, 16);
+
+ //
+ // Read in the Extra Set Code Length Arrary,
+ // Generate the Huffman code mapping table for Extra Set.
+ //
+ Sd->mBadTableFlag = ReadPTLen (Sd, NT, TBIT, 3);
+ if (Sd->mBadTableFlag != 0) {
+ return 0;
+ }
+
+ //
+ // Read in and decode the Char&Len Set Code Length Arrary,
+ // Generate the Huffman code mapping table for Char&Len Set.
+ //
+ ReadCLen (Sd);
+
+ //
+ // Read in the Position Set Code Length Arrary,
+ // Generate the Huffman code mapping table for the Position Set.
+ //
+ Sd->mBadTableFlag = ReadPTLen (Sd, MAXNP, Sd->mPBit, (UINT16) (-1));
+ if (Sd->mBadTableFlag != 0) {
+ return 0;
+ }
+ }
+
+ //
+ // Get one code according to Code&Set Huffman Table
+ //
+ Sd->mBlockSize--;
+ Index2 = Sd->mCTable[Sd->mBitBuf >> (BITBUFSIZ - 12)];
+
+ if (Index2 >= NC) {
+ Mask = 1U << (BITBUFSIZ - 1 - 12);
+
+ do {
+ if ((Sd->mBitBuf & Mask) != 0) {
+ Index2 = Sd->mRight[Index2];
+ } else {
+ Index2 = Sd->mLeft[Index2];
+ }
+
+ Mask >>= 1;
+ } while (Index2 >= NC);
+ }
+ //
+ // Advance what we have read
+ //
+ FillBuf (Sd, Sd->mCLen[Index2]);
+
+ return Index2;
+}
+
+/**
+ Decode the source data and put the resulting data into the destination buffer.
+
+ @param Sd The global scratch data
+**/
+VOID
+Decode (
+ SCRATCH_DATA *Sd
+ )
+{
+ UINT16 BytesRemain;
+ UINT32 DataIdx;
+ UINT16 CharC;
+
+ BytesRemain = (UINT16) (-1);
+
+ DataIdx = 0;
+
+ for (;;) {
+ //
+ // Get one code from mBitBuf
+ //
+ CharC = DecodeC (Sd);
+ if (Sd->mBadTableFlag != 0) {
+ goto Done;
+ }
+
+ if (CharC < 256) {
+ //
+ // Process an Original character
+ //
+ if (Sd->mOutBuf >= Sd->mOrigSize) {
+ goto Done;
+ } else {
+ //
+ // Write orignal character into mDstBase
+ //
+ Sd->mDstBase[Sd->mOutBuf++] = (UINT8) CharC;
+ }
+
+ } else {
+ //
+ // Process a Pointer
+ //
+ CharC = (UINT16) (CharC - (BIT8 - THRESHOLD));
+
+ //
+ // Get string length
+ //
+ BytesRemain = CharC;
+
+ //
+ // Locate string position
+ //
+ DataIdx = Sd->mOutBuf - DecodeP (Sd) - 1;
+
+ //
+ // Write BytesRemain of bytes into mDstBase
+ //
+ BytesRemain--;
+ while ((INT16) (BytesRemain) >= 0) {
+ Sd->mDstBase[Sd->mOutBuf++] = Sd->mDstBase[DataIdx++];
+ if (Sd->mOutBuf >= Sd->mOrigSize) {
+ goto Done ;
+ }
+
+ BytesRemain--;
+ }
+ }
+ }
+
+Done:
+ return ;
+}
+
+/**
+ Given a compressed source buffer, this function retrieves the size of
+ the uncompressed buffer and the size of the scratch buffer required
+ to decompress the compressed source buffer.
+
+ Retrieves the size of the uncompressed buffer and the temporary scratch buffer
+ required to decompress the buffer specified by Source and SourceSize.
+ If the size of the uncompressed buffer or the size of the scratch buffer cannot
+ be determined from the compressed data specified by Source and SourceData,
+ then RETURN_INVALID_PARAMETER is returned. Otherwise, the size of the uncompressed
+ buffer is returned in DestinationSize, the size of the scratch buffer is returned
+ in ScratchSize, and RETURN_SUCCESS is returned.
+ This function does not have scratch buffer available to perform a thorough
+ checking of the validity of the source data. It just retrieves the "Original Size"
+ field from the beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If Source is NULL, then ASSERT().
+ If DestinationSize is NULL, then ASSERT().
+ If ScratchSize is NULL, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the uncompressed buffer
+ that will be generated when the compressed buffer specified
+ by Source and SourceSize is decompressed..
+ @param ScratchSize A pointer to the size, in bytes, of the scratch buffer that
+ is required to decompress the compressed buffer specified
+ by Source and SourceSize.
+
+ @retval RETURN_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+ @retval RETURN_INVALID_PARAMETER
+ The size of the uncompressed data or the size of
+ the scratch buffer cannot be determined from
+ the compressed data specified by Source
+ and SourceSize.
+**/
+RETURN_STATUS
+EFIAPI
+UefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ UINT32 CompressedSize;
+
+ ASSERT (Source != NULL);
+ ASSERT (DestinationSize != NULL);
+ ASSERT (ScratchSize != NULL);
+
+ if (SourceSize < 8) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ CompressedSize = ReadUnaligned32 ((UINT32 *)Source);
+ if (SourceSize < (CompressedSize + 8)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *ScratchSize = sizeof (SCRATCH_DATA);
+ *DestinationSize = ReadUnaligned32 ((UINT32 *)Source + 1);
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Decompresses a compressed source buffer by EFI or Tiano algorithm.
+
+ Extracts decompressed data to its original form.
+ This function is designed so that the decompression algorithm can be implemented
+ without using any memory services. As a result, this function is not allowed to
+ call any memory allocation services in its implementation. It is the caller's
+ responsibility to allocate and free the Destination and Scratch buffers.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ If Source is NULL, then ASSERT().
+ If Destination is NULL, then ASSERT().
+ If the required scratch buffer size > 0 and Scratch is NULL, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+ @param Version 1 for UEFI Decompress algoruthm, 2 for Tiano Decompess algorithm.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+UefiTianoDecompress (
+ IN CONST VOID *Source,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch,
+ IN UINT32 Version
+ )
+{
+ UINT32 CompSize;
+ UINT32 OrigSize;
+ SCRATCH_DATA *Sd;
+ CONST UINT8 *Src;
+ UINT8 *Dst;
+
+ ASSERT (Source != NULL);
+ ASSERT (Destination != NULL);
+ ASSERT (Scratch != NULL);
+
+ Src = Source;
+ Dst = Destination;
+
+ Sd = (SCRATCH_DATA *) Scratch;
+
+ CompSize = Src[0] + (Src[1] << 8) + (Src[2] << 16) + (Src[3] << 24);
+ OrigSize = Src[4] + (Src[5] << 8) + (Src[6] << 16) + (Src[7] << 24);
+
+ //
+ // If compressed file size is 0, return
+ //
+ if (OrigSize == 0) {
+ return RETURN_SUCCESS;
+ }
+
+ Src = Src + 8;
+
+ SetMem (Sd, sizeof (SCRATCH_DATA), 0);
+
+ //
+ // The length of the field 'Position Set Code Length Array Size' in Block Header.
+ // For UEFI 2.0 de/compression algorithm(Version 1), mPBit = 4
+ // For Tiano de/compression algorithm(Version 2), mPBit = 5
+ //
+ switch (Version) {
+ case 1 :
+ Sd->mPBit = 4;
+ break;
+ case 2 :
+ Sd->mPBit = 5;
+ break;
+ default:
+ ASSERT (FALSE);
+ }
+ Sd->mSrcBase = (UINT8 *)Src;
+ Sd->mDstBase = Dst;
+ //
+ // CompSize and OrigSize are calculated in bytes
+ //
+ Sd->mCompSize = CompSize;
+ Sd->mOrigSize = OrigSize;
+
+ //
+ // Fill the first BITBUFSIZ bits
+ //
+ FillBuf (Sd, BITBUFSIZ);
+
+ //
+ // Decompress it
+ //
+ Decode (Sd);
+
+ if (Sd->mBadTableFlag != 0) {
+ //
+ // Something wrong with the source
+ //
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ return RETURN_SUCCESS;
+}
+
+/**
+ Decompresses a UEFI compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ This function is designed so that the decompression algorithm can be implemented
+ without using any memory services. As a result, this function is not allowed to
+ call any memory allocation services in its implementation. It is the caller's
+ responsibility to allocate and free the Destination and Scratch buffers.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ If Source is NULL, then ASSERT().
+ If Destination is NULL, then ASSERT().
+ If the required scratch buffer size > 0 and Scratch is NULL, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+UefiDecompress (
+ IN CONST VOID *Source,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch OPTIONAL
+ )
+{
+ return UefiTianoDecompress (Source, Destination, Scratch, 1);
+}
+
+/**
+ Examines a GUIDed section and returns the size of the decoded buffer and the
+ size of an optional scratch buffer required to actually decode the data in a GUIDed section.
+
+ Examines a GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports,
+ then RETURN_UNSUPPORTED is returned.
+ If the required information can not be retrieved from InputSection,
+ then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports,
+ then the size required to hold the decoded buffer is returned in OututBufferSize,
+ the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+ from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBufferSize is NULL, then ASSERT().
+ If ScratchBufferSize is NULL, then ASSERT().
+ If SectionAttribute is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required
+ if the buffer specified by InputSection were decoded.
+ @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space
+ if the buffer specified by InputSection were decoded.
+ @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes
+ field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+ @retval RETURN_SUCCESS The information about InputSection was returned.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+TianoDecompressGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+
+{
+ ASSERT (SectionAttribute != NULL);
+
+ if (InputSection == NULL) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gTianoCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Get guid attribute of guid section.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ //
+ // Call Tiano GetInfo to get the required size info.
+ //
+ return UefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gTianoCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+ //
+ // Get guid attribute of guid section.
+ //
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ //
+ // Call Tiano GetInfo to get the required size info.
+ //
+ return UefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a Tiano compressed GUIDed section into a caller allocated output buffer.
+
+ Decodes the GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+ If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+ is decoded into the buffer specified by OutputBuffer and the authentication status of this
+ decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the
+ data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise,
+ the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBuffer is NULL, then ASSERT().
+ If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+ If AuthenticationStatus is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
+ @param[in] ScratchBuffer A caller allocated buffer that may be required by this function
+ as a scratch buffer to perform the decode operation.
+ @param[out] AuthenticationStatus
+ A pointer to the authentication status of the decoded output buffer.
+ See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+ section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+ never be set by this handler.
+
+ @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+TianoDecompress (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ IN VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (InputSection != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gTianoCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Set Authentication to Zero.
+ //
+ *AuthenticationStatus = 0;
+
+ //
+ // Call Tiano Decompress to get the raw data
+ //
+ return UefiTianoDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer,
+ 2
+ );
+ } else {
+ if (!CompareGuid (
+ &gTianoCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Set Authentication to Zero.
+ //
+ *AuthenticationStatus = 0;
+
+ //
+ // Call Tiano Decompress to get the raw data
+ //
+ return UefiTianoDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer,
+ 2
+ );
+ }
+}
+
+/**
+ Registers TianoDecompress and TianoDecompressGetInfo handlers with TianoCustomerDecompressGuid
+
+ @retval RETURN_SUCCESS Register successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+RETURN_STATUS
+EFIAPI
+TianoDecompressLibConstructor (
+)
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gTianoCustomDecompressGuid,
+ TianoDecompressGetInfo,
+ TianoDecompress
+ );
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
new file mode 100644
index 0000000000..18417d1956
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLib.inf
@@ -0,0 +1,48 @@
+## @file
+# This library instance produces UefiDecompressLib and Tiano Custom decompression algorithm.
+# Tiano custom decompression algorithm shares most of code with Uefi Decompress algorithm.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BaseUefiTianoDecompressLib
+ MODULE_UNI_FILE = BaseUefiTianoDecompressLib.uni
+ FILE_GUID = d774c4d9-c121-4da3-a5e2-0f317e3c630c
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = UefiDecompressLib
+ CONSTRUCTOR = TianoDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BaseUefiTianoCustomDecompressLibInternals.h
+ BaseUefiTianoCustomDecompressLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+
+[Guids]
+ gTianoCustomDecompressGuid ## PRODUCES ## UNDEFINED # specifies tiano custom decompress algorithm.
+
diff --git a/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLibInternals.h b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLibInternals.h
new file mode 100644
index 0000000000..6ba3f43f75
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoCustomDecompressLibInternals.h
@@ -0,0 +1,220 @@
+/** @file
+ Internal data structure and interfaces defintions for UEFI and Tiano Decompress Libary.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __BASE_UEFI_TIANO_CUSTOM_DECOMPRESS_LIB_INTERNALS_H__
+#define __BASE_UEFI_TIANO_CUSTOM_DECOMPRESS_LIB_INTERNALS_H__
+
+#include <PiPei.h>
+
+#include <Guid/TianoDecompress.h>
+#include <Library/BaseLib.h>
+#include <Library/UefiDecompressLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+
+//
+// Decompression algorithm begins here
+//
+#define BITBUFSIZ 32
+#define MAXMATCH 256
+#define THRESHOLD 3
+#define CODE_BIT 16
+#define BAD_TABLE - 1
+
+//
+// C: Char&Len Set; P: Position Set; T: exTra Set
+//
+#define NC (0xff + MAXMATCH + 2 - THRESHOLD)
+#define CBIT 9
+#define MAXPBIT 5
+#define TBIT 5
+#define MAXNP ((1U << MAXPBIT) - 1)
+#define NT (CODE_BIT + 3)
+#if NT > MAXNP
+#define NPT NT
+#else
+#define NPT MAXNP
+#endif
+
+typedef struct {
+ UINT8 *mSrcBase; // Starting address of compressed data
+ UINT8 *mDstBase; // Starting address of decompressed data
+ UINT32 mOutBuf;
+ UINT32 mInBuf;
+
+ UINT16 mBitCount;
+ UINT32 mBitBuf;
+ UINT32 mSubBitBuf;
+ UINT16 mBlockSize;
+ UINT32 mCompSize;
+ UINT32 mOrigSize;
+
+ UINT16 mBadTableFlag;
+
+ UINT16 mLeft[2 * NC - 1];
+ UINT16 mRight[2 * NC - 1];
+ UINT8 mCLen[NC];
+ UINT8 mPTLen[NPT];
+ UINT16 mCTable[4096];
+ UINT16 mPTTable[256];
+
+ ///
+ /// The length of the field 'Position Set Code Length Array Size' in Block Header.
+ /// For UEFI 2.0 de/compression algorithm, mPBit = 4
+ /// For Tiano de/compression algorithm, mPBit = 5
+ ///
+ UINT8 mPBit;
+} SCRATCH_DATA;
+
+/**
+ Read NumOfBit of bits from source into mBitBuf.
+
+ Shift mBitBuf NumOfBits left. Read in NumOfBits of bits from source.
+
+ @param Sd The global scratch data
+ @param NumOfBits The number of bits to shift and read.
+
+**/
+VOID
+FillBuf (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfBits
+ );
+
+/**
+ Get NumOfBits of bits out from mBitBuf.
+
+ Get NumOfBits of bits out from mBitBuf. Fill mBitBuf with subsequent
+ NumOfBits of bits from source. Returns NumOfBits of bits that are
+ popped out.
+
+ @param Sd The global scratch data.
+ @param NumOfBits The number of bits to pop and read.
+
+ @return The bits that are popped out.
+
+**/
+UINT32
+GetBits (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfBits
+ );
+
+/**
+ Creates Huffman Code mapping table according to code length array.
+
+ Creates Huffman Code mapping table for Extra Set, Char&Len Set
+ and Position Set according to code length array.
+
+ @param Sd The global scratch data
+ @param NumOfChar Number of symbols in the symbol set
+ @param BitLen Code length array
+ @param TableBits The width of the mapping table
+ @param Table The table to be created.
+
+ @retval 0 OK.
+ @retval BAD_TABLE The table is corrupted.
+
+**/
+UINT16
+MakeTable (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 NumOfChar,
+ IN UINT8 *BitLen,
+ IN UINT16 TableBits,
+ OUT UINT16 *Table
+ );
+
+/**
+ Decodes a position value.
+
+ Get a position value according to Position Huffman Table.
+
+ @param Sd the global scratch data
+
+ @return The position value decoded.
+
+**/
+UINT32
+DecodeP (
+ IN SCRATCH_DATA *Sd
+ );
+
+/**
+ Reads code lengths for the Extra Set or the Position Set.
+
+ Read in the Extra Set or Pointion Set Length Arrary, then
+ generate the Huffman code mapping for them.
+
+ @param Sd The global scratch data.
+ @param nn Number of symbols.
+ @param nbit Number of bits needed to represent nn.
+ @param Special The special symbol that needs to be taken care of.
+
+ @retval 0 OK.
+ @retval BAD_TABLE Table is corrupted.
+
+**/
+UINT16
+ReadPTLen (
+ IN SCRATCH_DATA *Sd,
+ IN UINT16 nn,
+ IN UINT16 nbit,
+ IN UINT16 Special
+ );
+
+/**
+ Reads code lengths for Char&Len Set.
+
+ Read in and decode the Char&Len Set Code Length Array, then
+ generate the Huffman Code mapping table for the Char&Len Set.
+
+ @param Sd the global scratch data
+
+**/
+VOID
+ReadCLen (
+ SCRATCH_DATA *Sd
+ );
+
+/**
+ Decode a character/length value.
+
+ Read one value from mBitBuf, Get one code from mBitBuf. If it is at block boundary, generates
+ Huffman code mapping table for Extra Set, Code&Len Set and
+ Position Set.
+
+ @param Sd The global scratch data.
+
+ @return The value decoded.
+
+**/
+UINT16
+DecodeC (
+ SCRATCH_DATA *Sd
+ );
+
+/**
+ Decode the source data and put the resulting data into the destination buffer.
+
+ @param Sd The global scratch data
+
+**/
+VOID
+Decode (
+ SCRATCH_DATA *Sd
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoDecompressLib.uni b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoDecompressLib.uni
new file mode 100644
index 0000000000..f18b1ff6b1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/BaseUefiTianoCustomDecompressLib/BaseUefiTianoDecompressLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c
new file mode 100644
index 0000000000..fc9b533f2c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.c
@@ -0,0 +1,518 @@
+/** @file
+ Capsule Library instance to process capsule images.
+
+ Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiDxe.h>
+
+#include <Guid/Capsule.h>
+#include <Guid/FmpCapsule.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Protocol/FirmwareManagement.h>
+#include <Protocol/DevicePath.h>
+
+
+/**
+ Function indicate the current completion progress of the firmware
+ update. Platform may override with own specific progress function.
+
+ @param Completion A value between 1 and 100 indicating the current completion progress of the firmware update
+
+ @retval EFI_SUCESS Input capsule is a correct FMP capsule.
+**/
+EFI_STATUS
+EFIAPI
+Update_Image_Progress (
+ IN UINTN Completion
+)
+{
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Validate Fmp capsules layout.
+
+ @param CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is a correct FMP capsule.
+ @retval EFI_INVALID_PARAMETER Input capsule is not a correct FMP capsule.
+**/
+EFI_STATUS
+ValidateFmpCapsule (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ UINT8 *EndOfCapsule;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ UINT8 *EndOfPayload;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+ EndOfCapsule = (UINT8 *) CapsuleHeader + CapsuleHeader->CapsuleImageSize;
+
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ return EFI_INVALID_PARAMETER;
+ }
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ if (ItemNum == FmpCapsuleHeader->EmbeddedDriverCount) {
+ //
+ // No payload element
+ //
+ if (((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]) < EndOfCapsule) {
+ return EFI_SUCCESS;
+ } else {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if (FmpCapsuleHeader->PayloadItemCount != 0) {
+ //
+ // Check if the last payload is within capsule image range
+ //
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[ItemNum - 1]);
+ EndOfPayload = (UINT8 *)(ImageHeader + 1) + ImageHeader->UpdateImageSize + ImageHeader->UpdateVendorCodeSize;
+ } else {
+ //
+ // No driver & payload element in FMP
+ //
+ EndOfPayload = (UINT8 *)(FmpCapsuleHeader + 1);
+ }
+
+ if (EndOfPayload != EndOfCapsule) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // All the address in ItemOffsetList must be stored in ascending order
+ //
+ if (ItemNum >= 2) {
+ for (Index = 0; Index < ItemNum - 1; Index++) {
+ if (ItemOffsetList[Index] >= ItemOffsetList[Index + 1]) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Process Firmware management protocol data capsule.
+
+ @param CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+**/
+EFI_STATUS
+ProcessFmpCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *FmpCapsuleHeader;
+ EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *ImageHeader;
+ EFI_HANDLE ImageHandle;
+ UINT64 *ItemOffsetList;
+ UINT32 ItemNum;
+ UINTN Index;
+ UINTN ExitDataSize;
+ EFI_HANDLE *HandleBuffer;
+ EFI_FIRMWARE_MANAGEMENT_PROTOCOL *Fmp;
+ UINTN NumberOfHandles;
+ UINTN DescriptorSize;
+ UINT8 FmpImageInfoCount;
+ UINT32 FmpImageInfoDescriptorVer;
+ UINTN ImageInfoSize;
+ UINT32 PackageVersion;
+ CHAR16 *PackageVersionName;
+ CHAR16 *AbortReason;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *FmpImageInfoBuf;
+ EFI_FIRMWARE_IMAGE_DESCRIPTOR *TempFmpImageInfo;
+ UINTN DriverLen;
+ UINTN Index1;
+ UINTN Index2;
+ MEMMAP_DEVICE_PATH MemMapNode;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+
+ Status = EFI_SUCCESS;
+ HandleBuffer = NULL;
+ ExitDataSize = 0;
+ DriverDevicePath = NULL;
+
+ FmpCapsuleHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+
+ if (FmpCapsuleHeader->Version > EFI_FIRMWARE_MANAGEMENT_CAPSULE_HEADER_INIT_VERSION) {
+ return EFI_INVALID_PARAMETER;
+ }
+ ItemOffsetList = (UINT64 *)(FmpCapsuleHeader + 1);
+
+ ItemNum = FmpCapsuleHeader->EmbeddedDriverCount + FmpCapsuleHeader->PayloadItemCount;
+
+ //
+ // capsule in which driver count and payload count are both zero is not processed.
+ //
+ if (ItemNum == 0) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // 1. ConnectAll to ensure
+ // All the communication protocol required by driver in capsule installed
+ // All FMP protocols are installed
+ //
+ BdsLibConnectAll();
+
+
+ //
+ // 2. Try to load & start all the drivers within capsule
+ //
+ SetDevicePathNodeLength (&MemMapNode.Header, sizeof (MemMapNode));
+ MemMapNode.Header.Type = HARDWARE_DEVICE_PATH;
+ MemMapNode.Header.SubType = HW_MEMMAP_DP;
+ MemMapNode.MemoryType = EfiBootServicesCode;
+ MemMapNode.StartingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)CapsuleHeader;
+ MemMapNode.EndingAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)((UINT8 *)CapsuleHeader + CapsuleHeader->CapsuleImageSize - 1);
+
+ DriverDevicePath = AppendDevicePathNode (NULL, &MemMapNode.Header);
+ if (DriverDevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < FmpCapsuleHeader->EmbeddedDriverCount; Index++) {
+ if (FmpCapsuleHeader->PayloadItemCount == 0 && Index == (UINTN)FmpCapsuleHeader->EmbeddedDriverCount - 1) {
+ //
+ // When driver is last element in the ItemOffsetList array, the driver size is calculated by reference CapsuleImageSize in EFI_CAPSULE_HEADER
+ //
+ DriverLen = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize - (UINTN)ItemOffsetList[Index];
+ } else {
+ DriverLen = (UINTN)ItemOffsetList[Index + 1] - (UINTN)ItemOffsetList[Index];
+ }
+
+ Status = gBS->LoadImage(
+ FALSE,
+ gImageHandle,
+ DriverDevicePath,
+ (UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index],
+ DriverLen,
+ &ImageHandle
+ );
+ if (EFI_ERROR(Status)) {
+ goto EXIT;
+ }
+
+ Status = gBS->StartImage(
+ ImageHandle,
+ &ExitDataSize,
+ NULL
+ );
+ if (EFI_ERROR(Status)) {
+ DEBUG ((DEBUG_ERROR, "Driver Return Status = %r\n", Status));
+ goto EXIT;
+ }
+ }
+
+ //
+ // Connnect all again to connect drivers within capsule
+ //
+ if (FmpCapsuleHeader->EmbeddedDriverCount > 0) {
+ BdsLibConnectAll();
+ }
+
+ //
+ // 3. Route payload to right FMP instance
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareManagementProtocolGuid,
+ NULL,
+ &NumberOfHandles,
+ &HandleBuffer
+ );
+
+ if (!EFI_ERROR(Status)) {
+ for(Index1 = 0; Index1 < NumberOfHandles; Index1++) {
+ Status = gBS->HandleProtocol(
+ HandleBuffer[Index1],
+ &gEfiFirmwareManagementProtocolGuid,
+ (VOID **)&Fmp
+ );
+ if (EFI_ERROR(Status)) {
+ continue;
+ }
+
+ ImageInfoSize = 0;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ NULL
+ );
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ continue;
+ }
+
+ FmpImageInfoBuf = NULL;
+ FmpImageInfoBuf = AllocateZeroPool (ImageInfoSize);
+ if (FmpImageInfoBuf == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto EXIT;
+ }
+
+ PackageVersionName = NULL;
+ Status = Fmp->GetImageInfo (
+ Fmp,
+ &ImageInfoSize, // ImageInfoSize
+ FmpImageInfoBuf, // ImageInfo
+ &FmpImageInfoDescriptorVer, // DescriptorVersion
+ &FmpImageInfoCount, // DescriptorCount
+ &DescriptorSize, // DescriptorSize
+ &PackageVersion, // PackageVersion
+ &PackageVersionName // PackageVersionName
+ );
+
+ //
+ // If FMP GetInformation interface failed, skip this resource
+ //
+ if (EFI_ERROR(Status)) {
+ FreePool(FmpImageInfoBuf);
+ continue;
+ }
+
+ if (PackageVersionName != NULL) {
+ FreePool(PackageVersionName);
+ }
+
+ TempFmpImageInfo = FmpImageInfoBuf;
+ for (Index2 = 0; Index2 < FmpImageInfoCount; Index2++) {
+ //
+ // Check all the payload entry in capsule payload list
+ //
+ for (Index = FmpCapsuleHeader->EmbeddedDriverCount; Index < ItemNum; Index++) {
+ ImageHeader = (EFI_FIRMWARE_MANAGEMENT_CAPSULE_IMAGE_HEADER *)((UINT8 *)FmpCapsuleHeader + ItemOffsetList[Index]);
+ if (CompareGuid(&ImageHeader->UpdateImageTypeId, &TempFmpImageInfo->ImageTypeId) &&
+ ImageHeader->UpdateImageIndex == TempFmpImageInfo->ImageIndex) {
+ AbortReason = NULL;
+ if (ImageHeader->UpdateVendorCodeSize == 0) {
+ Status = Fmp->SetImage(
+ Fmp,
+ TempFmpImageInfo->ImageIndex, // ImageIndex
+ (UINT8 *)(ImageHeader + 1), // Image
+ ImageHeader->UpdateImageSize, // ImageSize
+ NULL, // VendorCode
+ Update_Image_Progress, // Progress
+ &AbortReason // AbortReason
+ );
+ } else {
+ Status = Fmp->SetImage(
+ Fmp,
+ TempFmpImageInfo->ImageIndex, // ImageIndex
+ (UINT8 *)(ImageHeader + 1), // Image
+ ImageHeader->UpdateImageSize, // ImageSize
+ (UINT8 *)((UINT8 *) (ImageHeader + 1) + ImageHeader->UpdateImageSize), // VendorCode
+ Update_Image_Progress, // Progress
+ &AbortReason // AbortReason
+ );
+ }
+ if (AbortReason != NULL) {
+ DEBUG ((EFI_D_ERROR, "%s\n", AbortReason));
+ FreePool(AbortReason);
+ }
+ }
+ }
+ //
+ // Use DescriptorSize to move ImageInfo Pointer to stay compatible with different ImageInfo version
+ //
+ TempFmpImageInfo = (EFI_FIRMWARE_IMAGE_DESCRIPTOR *)((UINT8 *)TempFmpImageInfo + DescriptorSize);
+ }
+ FreePool(FmpImageInfoBuf);
+ }
+ }
+
+EXIT:
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ if (DriverDevicePath != NULL) {
+ FreePool(DriverDevicePath);
+ }
+
+ return Status;
+}
+
+/**
+ Those capsules supported by the firmwares.
+
+ @param CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Input capsule is supported by firmware.
+ @retval EFI_UNSUPPORTED Input capsule is not supported by the firmware.
+ @retval EFI_INVALID_PARAMETER Input capsule layout is not correct
+**/
+EFI_STATUS
+EFIAPI
+SupportCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ if (CompareGuid (&gEfiCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ return EFI_SUCCESS;
+ }
+
+ if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)) {
+ //
+ // Check layout of FMP capsule
+ //
+ return ValidateFmpCapsule(CapsuleHeader);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ The firmware implements to process the capsule image.
+
+ @param CapsuleHeader Points to a capsule header.
+
+ @retval EFI_SUCESS Process Capsule Image successfully.
+ @retval EFI_UNSUPPORTED Capsule image is not supported by the firmware.
+ @retval EFI_VOLUME_CORRUPTED FV volume in the capsule is corrupted.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory.
+**/
+EFI_STATUS
+EFIAPI
+ProcessCapsuleImage (
+ IN EFI_CAPSULE_HEADER *CapsuleHeader
+ )
+{
+ UINT32 Length;
+ EFI_FIRMWARE_VOLUME_HEADER *FvImage;
+ EFI_FIRMWARE_VOLUME_HEADER *ProcessedFvImage;
+ EFI_STATUS Status;
+ EFI_HANDLE FvProtocolHandle;
+ UINT32 FvAlignment;
+
+ FvImage = NULL;
+ ProcessedFvImage = NULL;
+ Status = EFI_SUCCESS;
+
+ if (SupportCapsuleImage (CapsuleHeader) != EFI_SUCCESS) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check FMP capsule layout
+ //
+ if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
+ Status = ValidateFmpCapsule(CapsuleHeader);
+ if (EFI_ERROR(Status)) {
+ return Status;
+ }
+
+ //
+ // Press EFI FMP Capsule
+ //
+ return ProcessFmpCapsuleImage(CapsuleHeader);
+ }
+
+ //
+ // Skip the capsule header, move to the Firware Volume
+ //
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) CapsuleHeader + CapsuleHeader->HeaderSize);
+ Length = CapsuleHeader->CapsuleImageSize - CapsuleHeader->HeaderSize;
+
+ while (Length != 0) {
+ //
+ // Point to the next firmware volume header, and then
+ // call the DXE service to process it.
+ //
+ if (FvImage->FvLength > (UINTN) Length) {
+ //
+ // Notes: need to stuff this status somewhere so that the
+ // error can be detected at OS runtime
+ //
+ Status = EFI_VOLUME_CORRUPTED;
+ break;
+ }
+
+ FvAlignment = 1 << ((FvImage->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be more than 8 bytes required by FvHeader structure.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+ //
+ // Check FvImage Align is required.
+ //
+ if (((UINTN) FvImage % FvAlignment) == 0) {
+ ProcessedFvImage = FvImage;
+ } else {
+ //
+ // Allocate new aligned buffer to store FvImage.
+ //
+ ProcessedFvImage = (EFI_FIRMWARE_VOLUME_HEADER *) AllocateAlignedPages ((UINTN) EFI_SIZE_TO_PAGES ((UINTN) FvImage->FvLength), (UINTN) FvAlignment);
+ if (ProcessedFvImage == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ CopyMem (ProcessedFvImage, FvImage, (UINTN) FvImage->FvLength);
+ }
+
+ Status = gDS->ProcessFirmwareVolume (
+ (VOID *) ProcessedFvImage,
+ (UINTN) ProcessedFvImage->FvLength,
+ &FvProtocolHandle
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ //
+ // Call the dispatcher to dispatch any drivers from the produced firmware volume
+ //
+ gDS->Dispatch ();
+ //
+ // On to the next FV in the capsule
+ //
+ Length -= (UINT32) FvImage->FvLength;
+ FvImage = (EFI_FIRMWARE_VOLUME_HEADER *) ((UINT8 *) FvImage + FvImage->FvLength);
+ }
+
+ return Status;
+}
+
+
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf
new file mode 100644
index 0000000000..28b4693c1f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.inf
@@ -0,0 +1,55 @@
+## @file
+# Capsule library instance for DXE_DRIVER, DXE_RUNTIME_DRIVER.
+#
+# Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeCapsuleLib
+ MODULE_UNI_FILE = DxeCapsuleLib.uni
+ FILE_GUID = 654950df-1ede-4b04-b144-6b77845736ad
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = CapsuleLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DxeCapsuleLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseMemoryLib
+ DebugLib
+ MemoryAllocationLib
+ DxeServicesTableLib
+ GenericBdsLib
+ UefiBootServicesTableLib
+ DevicePathLib
+
+[Protocols]
+ gEfiFirmwareManagementProtocolGuid ## SOMETIMES_CONSUMES
+
+[Guids]
+ gEfiCapsuleGuid ## SOMETIMES_CONSUMES ## GUID # Capsule Image Header Guid
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.uni b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.uni
new file mode 100644
index 0000000000..8191bfa72d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeCapsuleLib/DxeCapsuleLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
new file mode 100644
index 0000000000..a97d4e8aac
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.inf
@@ -0,0 +1,58 @@
+## @file
+# Framework DXE report status code library to support EFI1.1 and UEFI2.0 system.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DxeReportStatusCodeLib
+ MODULE_UNI_FILE = DxeReportStatusCodeLib.uni
+ FILE_GUID = 3ddc3b12-99ea-4364-b315-6310a2050be5
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER UEFI_APPLICATION UEFI_DRIVER SMM_CORE
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ DevicePathLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## SOMETIMES_CONSUMES # Used if revision of the EFI Specification is not less than 0x20000
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.uni b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.uni
new file mode 100644
index 0000000000..befd970aa5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/DxeReportStatusCodeLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/ReportStatusCodeLib.c b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..a3603f862f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/DxeReportStatusCodeLibFramework/ReportStatusCodeLib.c
@@ -0,0 +1,634 @@
+/** @file
+ Report Status Code Library for DXE Phase.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <FrameworkDxe.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Protocol/StatusCode.h>
+
+//
+// Define the maximum extended data size that is supported when a status code is
+// reported at TPL_HIGH_LEVEL.
+//
+#define MAX_EXTENDED_DATA_SIZE 0x200
+
+EFI_REPORT_STATUS_CODE mReportStatusCode = NULL;
+
+/**
+ Locate the report status code service.
+
+ @return Function pointer to the report status code service.
+ NULL is returned if no status code service is available.
+
+**/
+EFI_REPORT_STATUS_CODE
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS_CODE_PROTOCOL *StatusCodeProtocol;
+ EFI_STATUS Status;
+
+ if (gRT != NULL && gRT->Hdr.Revision < 0x20000) {
+ return ((FRAMEWORK_EFI_RUNTIME_SERVICES*)gRT)->ReportStatusCode;
+ } else if (gBS != NULL && gBS->LocateProtocol != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**)&StatusCodeProtocol);
+ if (!EFI_ERROR (Status) && StatusCodeProtocol != NULL) {
+ return StatusCodeProtocol->ReportStatusCode;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Internal worker function that reports a status code through the status code service.
+
+ If status code service is not cached, then this function checks if status code service is
+ available in system. If status code service is not available, then EFI_UNSUPPORTED is
+ returned. If status code service is present, then it is cached in mReportStatusCode.
+ Finally this function reports status code through the status code service.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Status code service is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ //
+ // If mReportStatusCode is NULL, then check if status code service is available in system.
+ //
+ if (mReportStatusCode == NULL) {
+ mReportStatusCode = InternalGetReportStatusCode ();
+ if (mReportStatusCode == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // A status code service is present in system, so pass in all the parameters to the service.
+ //
+ return (*mReportStatusCode) (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with a Device Path Protocol as the extended data.
+
+ Allocates and fills in the extended data section of a status code with the
+ Device Path Protocol specified by DevicePath. This function is responsible
+ for allocating a buffer large enough for the standard header and the device
+ path. The standard header is filled in with a GUID of
+ gEfiStatusCodeSpecificDataGuid. The status code is reported with a zero
+ instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithDevicePath()must actively prevent recursion. If
+ ReportStatusCodeWithDevicePath() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithDevicePath()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If DevicePath is NULL, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param DevicePath Pointer to the Device Path Protocol to be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by DevicePath.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithDevicePath (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT (DevicePath != NULL);
+ return ReportStatusCodeWithExtendedData (
+ Type,
+ Value,
+ (VOID *)DevicePath,
+ GetDevicePathSize (DevicePath)
+ );
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDataGuid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If
+ ReportStatusCodeEx() is called while processing another any
+ other Report Status Code Library function, then
+ ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS_CODE_DATA *StatusCodeData;
+ EFI_TPL Tpl;
+ UINT64 Buffer[(MAX_EXTENDED_DATA_SIZE / sizeof (UINT64)) + 1];
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (gBS == NULL || gBS->AllocatePool == NULL || gBS->FreePool == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Retrieve the current TPL
+ //
+ Tpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ gBS->RestoreTPL (Tpl);
+
+ StatusCodeData = NULL;
+ if (Tpl <= TPL_NOTIFY) {
+ //
+ // Allocate space for the Status Code Header and its buffer
+ //
+ gBS->AllocatePool (EfiBootServicesData, sizeof (EFI_STATUS_CODE_DATA) + ExtendedDataSize, (VOID **)&StatusCodeData);
+ }
+
+ if (StatusCodeData == NULL) {
+ //
+ // If a buffer could not be allocated, then see if the local variable Buffer can be used
+ //
+ if (ExtendedDataSize > (MAX_EXTENDED_DATA_SIZE - sizeof (EFI_STATUS_CODE_DATA))) {
+ //
+ // The local variable Buffer not large enough to hold the extended data associated
+ // with the status code being reported.
+ //
+ DEBUG ((EFI_D_ERROR, "Status code extended data is too large to be reported!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+ StatusCodeData = (EFI_STATUS_CODE_DATA *)Buffer;
+ }
+
+ //
+ // Fill in the extended data header
+ //
+ StatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ StatusCodeData->Size = (UINT16)ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&StatusCodeData->Type, ExtendedDataGuid);
+
+ //
+ // Fill in the extended data buffer
+ //
+ if (ExtendedData != NULL) {
+ CopyMem (StatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+
+ //
+ // Report the status code
+ //
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ Status = InternalReportStatusCode (Type, Value, Instance, CallerId, StatusCodeData);
+
+ //
+ // Free the allocated buffer
+ //
+ if (StatusCodeData != (EFI_STATUS_CODE_DATA *)Buffer) {
+ gBS->FreePool (StatusCodeData);
+ }
+
+ return Status;
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
new file mode 100644
index 0000000000..bba62a801a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsBoot.c
@@ -0,0 +1,4356 @@
+/** @file
+ BDS Lib functions which relate with create or process the boot option.
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+#include "String.h"
+
+BOOLEAN mEnumBootDevice = FALSE;
+EFI_HII_HANDLE gBdsLibStringPackHandle = NULL;
+
+/**
+ The constructor function register UNI strings into imageHandle.
+
+ It will ASSERT() if that operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor successfully added string package.
+ @retval Other value The constructor can't add string package.
+
+**/
+EFI_STATUS
+EFIAPI
+GenericBdsLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+
+ gBdsLibStringPackHandle = HiiAddPackages (
+ &gBdsLibStringPackageGuid,
+ ImageHandle,
+ GenericBdsLibStrings,
+ NULL
+ );
+
+ ASSERT (gBdsLibStringPackHandle != NULL);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deletete the Boot Option from EFI Variable. The Boot Order Arrray
+ is also updated.
+
+ @param OptionNumber The number of Boot option want to be deleted.
+ @param BootOrder The Boot Order array.
+ @param BootOrderSize The size of the Boot Order Array.
+
+ @retval EFI_SUCCESS The Boot Option Variable was found and removed
+ @retval EFI_UNSUPPORTED The Boot Option Variable store was inaccessible
+ @retval EFI_NOT_FOUND The Boot Option Variable was not found
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteBootOption (
+ IN UINTN OptionNumber,
+ IN OUT UINT16 *BootOrder,
+ IN OUT UINTN *BootOrderSize
+ )
+{
+ CHAR16 BootOption[9];
+ UINTN Index;
+ EFI_STATUS Status;
+
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", OptionNumber);
+ Status = gRT->SetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // adjust boot order array
+ //
+ for (Index = 0; Index < *BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] == OptionNumber) {
+ CopyMem (&BootOrder[Index], &BootOrder[Index+1], *BootOrderSize - (Index+1) * sizeof (UINT16));
+ *BootOrderSize -= sizeof (UINT16);
+ break;
+ }
+ }
+
+ return Status;
+}
+/**
+
+ Translate the first n characters of an Ascii string to
+ Unicode characters. The count n is indicated by parameter
+ Size. If Size is greater than the length of string, then
+ the entire string is translated.
+
+
+ @param AStr Pointer to input Ascii string.
+ @param Size The number of characters to translate.
+ @param UStr Pointer to output Unicode string buffer.
+
+**/
+VOID
+AsciiToUnicodeSize (
+ IN UINT8 *AStr,
+ IN UINTN Size,
+ OUT UINT16 *UStr
+ )
+{
+ UINTN Idx;
+
+ Idx = 0;
+ while (AStr[Idx] != 0) {
+ UStr[Idx] = (CHAR16) AStr[Idx];
+ if (Idx == Size) {
+ break;
+ }
+
+ Idx++;
+ }
+ UStr[Idx] = 0;
+}
+
+/**
+ Build Legacy Device Name String according.
+
+ @param CurBBSEntry BBS Table.
+ @param Index Index.
+ @param BufSize The buffer size.
+ @param BootString The output string.
+
+**/
+VOID
+BdsBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ )
+{
+ CHAR16 *Fmt;
+ CHAR16 *Type;
+ UINT8 *StringDesc;
+ CHAR16 Temp[80];
+
+ switch (Index) {
+ //
+ // Primary Master
+ //
+ case 1:
+ Fmt = L"Primary Master %s";
+ break;
+
+ //
+ // Primary Slave
+ //
+ case 2:
+ Fmt = L"Primary Slave %s";
+ break;
+
+ //
+ // Secondary Master
+ //
+ case 3:
+ Fmt = L"Secondary Master %s";
+ break;
+
+ //
+ // Secondary Slave
+ //
+ case 4:
+ Fmt = L"Secondary Slave %s";
+ break;
+
+ default:
+ Fmt = L"%s";
+ break;
+ }
+
+ switch (CurBBSEntry->DeviceType) {
+ case BBS_FLOPPY:
+ Type = L"Floppy";
+ break;
+
+ case BBS_HARDDISK:
+ Type = L"Harddisk";
+ break;
+
+ case BBS_CDROM:
+ Type = L"CDROM";
+ break;
+
+ case BBS_PCMCIA:
+ Type = L"PCMCIAe";
+ break;
+
+ case BBS_USB:
+ Type = L"USB";
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Type = L"Network";
+ break;
+
+ case BBS_BEV_DEVICE:
+ Type = L"BEVe";
+ break;
+
+ case BBS_UNKNOWN:
+ default:
+ Type = L"Unknown";
+ break;
+ }
+ //
+ // If current BBS entry has its description then use it.
+ //
+ StringDesc = (UINT8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+ if (NULL != StringDesc) {
+ //
+ // Only get fisrt 32 characters, this is suggested by BBS spec
+ //
+ AsciiToUnicodeSize (StringDesc, 32, Temp);
+ Fmt = L"%s";
+ Type = Temp;
+ }
+
+ //
+ // BbsTable 16 entries are for onboard IDE.
+ // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+ //
+ if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
+ Fmt = L"%s %d";
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+ } else {
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);
+ }
+}
+
+/**
+
+ Create a legacy boot option for the specified entry of
+ BBS table, save it as variable, and append it to the boot
+ order list.
+
+
+ @param CurrentBbsEntry Pointer to current BBS table.
+ @param CurrentBbsDevPath Pointer to the Device Path Protocol instance of BBS
+ @param Index Index of the specified entry in BBS table.
+ @param BootOrderList On input, the original boot order list.
+ On output, the new boot order list attached with the
+ created node.
+ @param BootOrderListSize On input, the original size of boot order list.
+ On output, the size of new boot order list.
+
+ @retval EFI_SUCCESS Boot Option successfully created.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval Other Error occurs while setting variable.
+
+**/
+EFI_STATUS
+BdsCreateLegacyBootOption (
+ IN BBS_TABLE *CurrentBbsEntry,
+ IN EFI_DEVICE_PATH_PROTOCOL *CurrentBbsDevPath,
+ IN UINTN Index,
+ IN OUT UINT16 **BootOrderList,
+ IN OUT UINTN *BootOrderListSize
+ )
+{
+ EFI_STATUS Status;
+ UINT16 CurrentBootOptionNo;
+ UINT16 BootString[10];
+ CHAR16 BootDesc[100];
+ CHAR8 HelpString[100];
+ UINT16 *NewBootOrderList;
+ UINTN BufferSize;
+ UINTN StringLen;
+ VOID *Buffer;
+ UINT8 *Ptr;
+ UINT16 CurrentBbsDevPathSize;
+ UINTN BootOrderIndex;
+ UINTN BootOrderLastIndex;
+ UINTN ArrayIndex;
+ BOOLEAN IndexNotFound;
+ BBS_BBS_DEVICE_PATH *NewBbsDevPathNode;
+
+ if ((*BootOrderList) == NULL) {
+ CurrentBootOptionNo = 0;
+ } else {
+ for (ArrayIndex = 0; ArrayIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); ArrayIndex++) {
+ IndexNotFound = TRUE;
+ for (BootOrderIndex = 0; BootOrderIndex < (UINTN) (*BootOrderListSize / sizeof (UINT16)); BootOrderIndex++) {
+ if ((*BootOrderList)[BootOrderIndex] == ArrayIndex) {
+ IndexNotFound = FALSE;
+ break;
+ }
+ }
+
+ if (!IndexNotFound) {
+ continue;
+ } else {
+ break;
+ }
+ }
+
+ CurrentBootOptionNo = (UINT16) ArrayIndex;
+ }
+
+ UnicodeSPrint (
+ BootString,
+ sizeof (BootString),
+ L"Boot%04x",
+ CurrentBootOptionNo
+ );
+
+ BdsBuildLegacyDevNameString (CurrentBbsEntry, Index, sizeof (BootDesc), BootDesc);
+
+ //
+ // Create new BBS device path node with description string
+ //
+ UnicodeStrToAsciiStrS (BootDesc, HelpString, sizeof (HelpString));
+
+ StringLen = AsciiStrLen (HelpString);
+ NewBbsDevPathNode = AllocateZeroPool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+ if (NewBbsDevPathNode == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (NewBbsDevPathNode, CurrentBbsDevPath, sizeof (BBS_BBS_DEVICE_PATH));
+ CopyMem (NewBbsDevPathNode->String, HelpString, StringLen + 1);
+ SetDevicePathNodeLength (&(NewBbsDevPathNode->Header), sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+
+ //
+ // Create entire new CurrentBbsDevPath with end node
+ //
+ CurrentBbsDevPath = AppendDevicePathNode (
+ NULL,
+ (EFI_DEVICE_PATH_PROTOCOL *) NewBbsDevPathNode
+ );
+ if (CurrentBbsDevPath == NULL) {
+ FreePool (NewBbsDevPathNode);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CurrentBbsDevPathSize = (UINT16) (GetDevicePathSize (CurrentBbsDevPath));
+
+ BufferSize = sizeof (UINT32) +
+ sizeof (UINT16) +
+ StrSize (BootDesc) +
+ CurrentBbsDevPathSize +
+ sizeof (BBS_TABLE) +
+ sizeof (UINT16);
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Ptr = (UINT8 *) Buffer;
+
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+ Ptr += sizeof (UINT32);
+
+ *((UINT16 *) Ptr) = CurrentBbsDevPathSize;
+ Ptr += sizeof (UINT16);
+
+ CopyMem (
+ Ptr,
+ BootDesc,
+ StrSize (BootDesc)
+ );
+ Ptr += StrSize (BootDesc);
+
+ CopyMem (
+ Ptr,
+ CurrentBbsDevPath,
+ CurrentBbsDevPathSize
+ );
+ Ptr += CurrentBbsDevPathSize;
+
+ CopyMem (
+ Ptr,
+ CurrentBbsEntry,
+ sizeof (BBS_TABLE)
+ );
+
+ Ptr += sizeof (BBS_TABLE);
+ *((UINT16 *) Ptr) = (UINT16) Index;
+
+ Status = gRT->SetVariable (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BufferSize,
+ Buffer
+ );
+
+ FreePool (Buffer);
+
+ Buffer = NULL;
+
+ NewBootOrderList = AllocateZeroPool (*BootOrderListSize + sizeof (UINT16));
+ if (NULL == NewBootOrderList) {
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (*BootOrderList != NULL) {
+ CopyMem (NewBootOrderList, *BootOrderList, *BootOrderListSize);
+ FreePool (*BootOrderList);
+ }
+
+ BootOrderLastIndex = (UINTN) (*BootOrderListSize / sizeof (UINT16));
+ NewBootOrderList[BootOrderLastIndex] = CurrentBootOptionNo;
+ *BootOrderListSize += sizeof (UINT16);
+ *BootOrderList = NewBootOrderList;
+
+ FreePool (NewBbsDevPathNode);
+ FreePool (CurrentBbsDevPath);
+ return Status;
+}
+
+/**
+ Check if the boot option is a legacy one.
+
+ @param BootOptionVar The boot option data payload.
+ @param BbsEntry The BBS Table.
+ @param BbsIndex The table index.
+
+ @retval TRUE It is a legacy boot option.
+ @retval FALSE It is not a legacy boot option.
+
+**/
+BOOLEAN
+BdsIsLegacyBootOption (
+ IN UINT8 *BootOptionVar,
+ OUT BBS_TABLE **BbsEntry,
+ OUT UINT16 *BbsIndex
+ )
+{
+ UINT8 *Ptr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN Ret;
+ UINT16 DevPathLen;
+
+ Ptr = BootOptionVar;
+ Ptr += sizeof (UINT32);
+ DevPathLen = *(UINT16 *) Ptr;
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((UINT16 *) Ptr);
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+ Ptr += DevPathLen;
+ *BbsEntry = (BBS_TABLE *) Ptr;
+ Ptr += sizeof (BBS_TABLE);
+ *BbsIndex = *(UINT16 *) Ptr;
+ Ret = TRUE;
+ } else {
+ *BbsEntry = NULL;
+ Ret = FALSE;
+ }
+
+ return Ret;
+}
+
+/**
+ Delete all the invalid legacy boot options.
+
+ @retval EFI_SUCCESS All invalide legacy boot options are deleted.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+EFIAPI
+BdsDeleteAllInvalidLegacyBootOptions (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ BBS_TABLE *BbsEntry;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 BootOption[10];
+ UINT16 BootDesc[100];
+ BOOLEAN DescStringMatch;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ BootOrderSize = 0;
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ BbsEntry = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ BootOptionSize = 0;
+ Status = gRT->GetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &BootOptionSize,
+ BootOptionVar
+ );
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Update BootOrder
+ //
+ BdsDeleteBootOption (
+ BootOrder[Index],
+ BootOrder,
+ &BootOrderSize
+ );
+ continue;
+ } else {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+ //
+ // Skip Non-Legacy boot option
+ //
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, &BbsIndex)) {
+ if (BootOptionVar!= NULL) {
+ FreePool (BootOptionVar);
+ }
+ Index++;
+ continue;
+ }
+
+ if (BbsIndex < BbsCount) {
+ //
+ // Check if BBS Description String is changed
+ //
+ DescStringMatch = FALSE;
+ BdsBuildLegacyDevNameString (
+ &LocalBbsTable[BbsIndex],
+ BbsIndex,
+ sizeof (BootDesc),
+ BootDesc
+ );
+
+ if (StrCmp (BootDesc, (UINT16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) == 0) {
+ DescStringMatch = TRUE;
+ }
+
+ if (!((LocalBbsTable[BbsIndex].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[BbsIndex].BootPriority == BBS_DO_NOT_BOOT_FROM)) &&
+ (LocalBbsTable[BbsIndex].DeviceType == BbsEntry->DeviceType) &&
+ DescStringMatch) {
+ Index++;
+ continue;
+ }
+ }
+
+ if (BootOptionVar != NULL) {
+ FreePool (BootOptionVar);
+ }
+ //
+ // should delete
+ //
+ BdsDeleteBootOption (
+ BootOrder[Index],
+ BootOrder,
+ &BootOrderSize
+ );
+ }
+
+ //
+ // Adjust the number of boot options.
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Shrinking variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+/**
+ Find all legacy boot option by device type.
+
+ @param BootOrder The boot order array.
+ @param BootOptionNum The number of boot option.
+ @param DevType Device type.
+ @param DevName Device name.
+ @param Attribute The boot option attribute.
+ @param BbsIndex The BBS table index.
+ @param OptionNumber The boot option index.
+
+ @retval TRUE The Legacy boot option is found.
+ @retval FALSE The legacy boot option is not found.
+
+**/
+BOOLEAN
+BdsFindLegacyBootOptionByDevTypeAndName (
+ IN UINT16 *BootOrder,
+ IN UINTN BootOptionNum,
+ IN UINT16 DevType,
+ IN CHAR16 *DevName,
+ OUT UINT32 *Attribute,
+ OUT UINT16 *BbsIndex,
+ OUT UINT16 *OptionNumber
+ )
+{
+ UINTN Index;
+ CHAR16 BootOption[9];
+ UINTN BootOptionSize;
+ UINT8 *BootOptionVar;
+ BBS_TABLE *BbsEntry;
+ BOOLEAN Found;
+
+ BbsEntry = NULL;
+ Found = FALSE;
+
+ if (NULL == BootOrder) {
+ return Found;
+ }
+
+ //
+ // Loop all boot option from variable
+ //
+ for (Index = 0; Index < BootOptionNum; Index++) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", (UINTN) BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ continue;
+ }
+
+ //
+ // Skip Non-legacy boot option
+ //
+ if (!BdsIsLegacyBootOption (BootOptionVar, &BbsEntry, BbsIndex)) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ if (
+ (BbsEntry->DeviceType != DevType) ||
+ (StrCmp (DevName, (CHAR16*)(BootOptionVar + sizeof (UINT32) + sizeof (UINT16))) != 0)
+ ) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ *Attribute = *(UINT32 *) BootOptionVar;
+ *OptionNumber = BootOrder[Index];
+ Found = TRUE;
+ FreePool (BootOptionVar);
+ break;
+ }
+
+ return Found;
+}
+
+/**
+ Create a legacy boot option.
+
+ @param BbsItem The BBS Table entry.
+ @param Index Index of the specified entry in BBS table.
+ @param BootOrderList The boot order list.
+ @param BootOrderListSize The size of boot order list.
+
+ @retval EFI_OUT_OF_RESOURCE No enough memory.
+ @retval EFI_SUCCESS The function complete successfully.
+ @return Other value if the legacy boot option is not created.
+
+**/
+EFI_STATUS
+BdsCreateOneLegacyBootOption (
+ IN BBS_TABLE *BbsItem,
+ IN UINTN Index,
+ IN OUT UINT16 **BootOrderList,
+ IN OUT UINTN *BootOrderListSize
+ )
+{
+ BBS_BBS_DEVICE_PATH BbsDevPathNode;
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+
+ DevPath = NULL;
+
+ //
+ // Create device path node.
+ //
+ BbsDevPathNode.Header.Type = BBS_DEVICE_PATH;
+ BbsDevPathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (&BbsDevPathNode.Header, sizeof (BBS_BBS_DEVICE_PATH));
+ BbsDevPathNode.DeviceType = BbsItem->DeviceType;
+ CopyMem (&BbsDevPathNode.StatusFlag, &BbsItem->StatusFlags, sizeof (UINT16));
+
+ DevPath = AppendDevicePathNode (
+ NULL,
+ (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevPathNode
+ );
+ if (NULL == DevPath) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = BdsCreateLegacyBootOption (
+ BbsItem,
+ DevPath,
+ Index,
+ BootOrderList,
+ BootOrderListSize
+ );
+ BbsItem->BootPriority = 0x00;
+
+ FreePool (DevPath);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot options from BBS table if they do not exist.
+
+ @retval EFI_SUCCESS The boot options are added successfully
+ or they are already in boot options.
+ @retval EFI_NOT_FOUND No legacy boot options is found.
+ @retval EFI_OUT_OF_RESOURCE No enough memory.
+ @return Other value LegacyBoot options are not added.
+**/
+EFI_STATUS
+EFIAPI
+BdsAddNonExistingLegacyBootOptions (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ EFI_STATUS Status;
+ CHAR16 Desc[100];
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 Index;
+ UINT32 Attribute;
+ UINT16 OptionNumber;
+ BOOLEAN Exist;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ BootOrderSize = 0;
+ }
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ BdsBuildLegacyDevNameString (&LocalBbsTable[Index], Index, sizeof (Desc), Desc);
+
+ Exist = BdsFindLegacyBootOptionByDevTypeAndName (
+ BootOrder,
+ BootOrderSize / sizeof (UINT16),
+ LocalBbsTable[Index].DeviceType,
+ Desc,
+ &Attribute,
+ &BbsIndex,
+ &OptionNumber
+ );
+ if (!Exist) {
+ //
+ // Not found such type of legacy device in boot options or we found but it's disabled
+ // so we have to create one and put it to the tail of boot order list
+ //
+ Status = BdsCreateOneLegacyBootOption (
+ &LocalBbsTable[Index],
+ Index,
+ &BootOrder,
+ &BootOrderSize
+ );
+ if (!EFI_ERROR (Status)) {
+ ASSERT (BootOrder != NULL);
+ BbsIndex = Index;
+ OptionNumber = BootOrder[BootOrderSize / sizeof (UINT16) - 1];
+ }
+ }
+
+ ASSERT (BbsIndex == Index);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ if (BootOrder != NULL) {
+ FreePool (BootOrder);
+ }
+
+ return Status;
+}
+
+/**
+ Fill the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsType The BBS Type.
+ @param BbsCount The BBS Count.
+ @param Buf device order buffer.
+
+ @return The device order buffer.
+
+**/
+UINT16 *
+BdsFillDevOrderBuf (
+ IN BBS_TABLE *BbsTable,
+ IN BBS_TYPE BbsType,
+ IN UINTN BbsCount,
+ OUT UINT16 *Buf
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ if (BbsTable[Index].DeviceType != BbsType) {
+ continue;
+ }
+
+ *Buf = (UINT16) (Index & 0xFF);
+ Buf++;
+ }
+
+ return Buf;
+}
+
+/**
+ Create the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsCount The BBS Count.
+
+ @retval EFI_SUCCES The buffer is created and the EFI variable named
+ VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid is
+ set correctly.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
+ because of hardware error.
+**/
+EFI_STATUS
+BdsCreateDevOrder (
+ IN BBS_TABLE *BbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINTN Index;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ EFI_STATUS Status;
+
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ DevOrder = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Count all boot devices
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (BbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) {
+ continue;
+ }
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
+
+ //
+ // Create buffer to hold all boot device order
+ //
+ DevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevOrderPtr = DevOrder;
+
+ DevOrderPtr->BbsType = BBS_FLOPPY;
+ DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_HARDDISK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_CDROM;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_BEV_DEVICE;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) BdsFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
+
+ ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
+
+ //
+ // Save device order for legacy boot device to variable.
+ //
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ DevOrder
+ );
+ FreePool (DevOrder);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot devices from BBS table into
+ the legacy device boot order.
+
+ @retval EFI_SUCCESS The boot devices are added successfully.
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
+ because of hardware error.
+**/
+EFI_STATUS
+EFIAPI
+BdsUpdateLegacyDevOrder (
+ VOID
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
+ LEGACY_DEV_ORDER_ENTRY *Ptr;
+ LEGACY_DEV_ORDER_ENTRY *NewPtr;
+ UINTN DevOrderSize;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINTN Index;
+ UINTN Index2;
+ UINTN *Idx;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ UINT16 *NewFDPtr;
+ UINT16 *NewHDPtr;
+ UINT16 *NewCDPtr;
+ UINT16 *NewNETPtr;
+ UINT16 *NewBEVPtr;
+ UINT16 *NewDevPtr;
+ UINTN FDIndex;
+ UINTN HDIndex;
+ UINTN CDIndex;
+ UINTN NETIndex;
+ UINTN BEVIndex;
+
+ Idx = NULL;
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ FDIndex = 0;
+ HDIndex = 0;
+ CDIndex = 0;
+ NETIndex = 0;
+ BEVIndex = 0;
+ NewDevPtr = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DevOrder = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &DevOrderSize
+ );
+ if (NULL == DevOrder) {
+ return BdsCreateDevOrder (LocalBbsTable, BbsCount);
+ }
+ //
+ // First we figure out how many boot devices with same device type respectively
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
+
+ NewDevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == NewDevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+
+
+ //
+ // copy FD
+ //
+ Ptr = DevOrder;
+ NewPtr = NewDevOrder;
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[FDIndex] = Ptr->Data[Index];
+ FDIndex++;
+ }
+ NewFDPtr = NewPtr->Data;
+
+ //
+ // copy HD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[HDIndex] = Ptr->Data[Index];
+ HDIndex++;
+ }
+ NewHDPtr = NewPtr->Data;
+
+ //
+ // copy CD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[CDIndex] = Ptr->Data[Index];
+ CDIndex++;
+ }
+ NewCDPtr = NewPtr->Data;
+
+ //
+ // copy NET
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[NETIndex] = Ptr->Data[Index];
+ NETIndex++;
+ }
+ NewNETPtr = NewPtr->Data;
+
+ //
+ // copy BEV
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_IGNORE_ENTRY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_DO_NOT_BOOT_FROM ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].BootPriority == BBS_LOWEST_PRIORITY ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[BEVIndex] = Ptr->Data[Index];
+ BEVIndex++;
+ }
+ NewBEVPtr = NewPtr->Data;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((LocalBbsTable[Index].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Index].BootPriority == BBS_DO_NOT_BOOT_FROM)
+ ) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ Idx = &FDIndex;
+ NewDevPtr = NewFDPtr;
+ break;
+
+ case BBS_HARDDISK:
+ Idx = &HDIndex;
+ NewDevPtr = NewHDPtr;
+ break;
+
+ case BBS_CDROM:
+ Idx = &CDIndex;
+ NewDevPtr = NewCDPtr;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Idx = &NETIndex;
+ NewDevPtr = NewNETPtr;
+ break;
+
+ case BBS_BEV_DEVICE:
+ Idx = &BEVIndex;
+ NewDevPtr = NewBEVPtr;
+ break;
+
+ default:
+ Idx = NULL;
+ break;
+ }
+ //
+ // at this point we have copied those valid indexes to new buffer
+ // and we should check if there is any new appeared boot device
+ //
+ if (Idx != NULL) {
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
+ break;
+ }
+ }
+
+ if (Index2 == *Idx) {
+ //
+ // Index2 == *Idx means we didn't find Index
+ // so Index is a new appeared device's index in BBS table
+ // insert it before disabled indexes.
+ //
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
+ break;
+ }
+ }
+ CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
+ NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
+ (*Idx)++;
+ }
+ }
+ }
+
+ FreePool (DevOrder);
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ NewDevOrder
+ );
+ FreePool (NewDevOrder);
+
+ return Status;
+}
+
+/**
+ Set Boot Priority for specified device type.
+
+ @param DeviceType The device type.
+ @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
+ @param LocalBbsTable The BBS table.
+ @param Priority The prority table.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND Failed to find device.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
+
+**/
+EFI_STATUS
+BdsSetBootPriority4SameTypeDev (
+ IN UINT16 DeviceType,
+ IN UINTN BbsIndex,
+ IN OUT BBS_TABLE *LocalBbsTable,
+ IN OUT UINT16 *Priority
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ UINTN DevOrderSize;
+ UINTN Index;
+
+ DevOrder = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &DevOrderSize
+ );
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevOrderPtr = DevOrder;
+ while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
+ if (DevOrderPtr->BbsType == DeviceType) {
+ break;
+ }
+
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
+ }
+
+ if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+
+ if (BbsIndex != (UINTN) -1) {
+ LocalBbsTable[BbsIndex].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ //
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
+ //
+ for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
+ if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
+ //
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
+ //
+ } else if (DevOrderPtr->Data[Index] != BbsIndex) {
+ LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ }
+
+ FreePool (DevOrder);
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the BBS Table.
+
+ @param LocalBbsTable The BBS table.
+ @param BbsCount The count of entry in BBS table.
+**/
+VOID
+PrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINT16 Idx;
+
+ DEBUG ((DEBUG_ERROR, "\n"));
+ DEBUG ((DEBUG_ERROR, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+ DEBUG ((DEBUG_ERROR, "=============================================\n"));
+ for (Idx = 0; Idx < BbsCount; Idx++) {
+ if ((LocalBbsTable[Idx].BootPriority == BBS_IGNORE_ENTRY) ||
+ (LocalBbsTable[Idx].BootPriority == BBS_DO_NOT_BOOT_FROM) ||
+ (LocalBbsTable[Idx].BootPriority == BBS_LOWEST_PRIORITY)
+ ) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_ERROR,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN) Idx,
+ (UINTN) LocalBbsTable[Idx].BootPriority,
+ (UINTN) LocalBbsTable[Idx].Bus,
+ (UINTN) LocalBbsTable[Idx].Device,
+ (UINTN) LocalBbsTable[Idx].Function,
+ (UINTN) LocalBbsTable[Idx].Class,
+ (UINTN) LocalBbsTable[Idx].SubClass,
+ (UINTN) LocalBbsTable[Idx].DeviceType,
+ (UINTN) * (UINT16 *) &LocalBbsTable[Idx].StatusFlags,
+ (UINTN) LocalBbsTable[Idx].BootHandlerSegment,
+ (UINTN) LocalBbsTable[Idx].BootHandlerOffset,
+ (UINTN) ((LocalBbsTable[Idx].MfgStringSegment << 4) + LocalBbsTable[Idx].MfgStringOffset),
+ (UINTN) ((LocalBbsTable[Idx].DescStringSegment << 4) + LocalBbsTable[Idx].DescStringOffset))
+ );
+ }
+
+ DEBUG ((DEBUG_ERROR, "\n"));
+}
+
+/**
+ Set the boot priority for BBS entries based on boot option entry and boot order.
+
+ @param Entry The boot option is to be checked for refresh BBS table.
+
+ @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
+ @retval EFI_NOT_FOUND BBS entries can't be found.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+EFIAPI
+BdsRefreshBbsTableForBoot (
+ IN BDS_COMMON_OPTION *Entry
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BbsIndex;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 DevType;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 Priority;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ UINT8 *BootOptionVar;
+ UINTN BootOptionSize;
+ CHAR16 BootOption[9];
+ UINT8 *Ptr;
+ UINT16 DevPathLen;
+ EFI_DEVICE_PATH_PROTOCOL *DevPath;
+ UINT16 *DeviceType;
+ UINTN DeviceTypeCount;
+ UINTN DeviceTypeIndex;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ DevType = BBS_UNKNOWN;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ //
+ // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
+ // We will set them according to the settings setup by user
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!((BBS_IGNORE_ENTRY == LocalBbsTable[Index].BootPriority) ||
+ (BBS_DO_NOT_BOOT_FROM == LocalBbsTable[Index].BootPriority) ||
+ (BBS_LOWEST_PRIORITY == LocalBbsTable[Index].BootPriority))) {
+ LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+ //
+ // boot priority always starts at 0
+ //
+ Priority = 0;
+ if (Entry->LoadOptionsSize == sizeof (BBS_TABLE) + sizeof (UINT16)) {
+ //
+ // If Entry stands for a legacy boot option, we prioritize the devices with the same type first.
+ //
+ DevType = ((BBS_TABLE *) Entry->LoadOptions)->DeviceType;
+ BbsIndex = *(UINT16 *) ((BBS_TABLE *) Entry->LoadOptions + 1);
+ Status = BdsSetBootPriority4SameTypeDev (
+ DevType,
+ BbsIndex,
+ LocalBbsTable,
+ &Priority
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // we have to set the boot priority for other BBS entries with different device types
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ DeviceType = AllocatePool (BootOrderSize + sizeof (UINT16));
+ ASSERT (DeviceType != NULL);
+
+ DeviceType[0] = DevType;
+ DeviceTypeCount = 1;
+ for (Index = 0; ((BootOrder != NULL) && (Index < BootOrderSize / sizeof (UINT16))); Index++) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ continue;
+ }
+
+ Ptr = BootOptionVar;
+
+ Ptr += sizeof (UINT32);
+ DevPathLen = *(UINT16 *) Ptr;
+ Ptr += sizeof (UINT16);
+ Ptr += StrSize ((UINT16 *) Ptr);
+ DevPath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if (BBS_DEVICE_PATH != DevPath->Type || BBS_BBS_DP != DevPath->SubType) {
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ Ptr += DevPathLen;
+ DevType = ((BBS_TABLE *) Ptr)->DeviceType;
+ for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
+ if (DeviceType[DeviceTypeIndex] == DevType) {
+ break;
+ }
+ }
+ if (DeviceTypeIndex < DeviceTypeCount) {
+ //
+ // We don't want to process twice for a device type
+ //
+ FreePool (BootOptionVar);
+ continue;
+ }
+
+ DeviceType[DeviceTypeCount] = DevType;
+ DeviceTypeCount++;
+
+ Status = BdsSetBootPriority4SameTypeDev (
+ DevType,
+ (UINTN) -1,
+ LocalBbsTable,
+ &Priority
+ );
+ FreePool (BootOptionVar);
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ FreePool (DeviceType);
+
+ if (BootOrder != NULL) {
+ FreePool (BootOrder);
+ }
+
+ DEBUG_CODE_BEGIN();
+ PrintBbsTable (LocalBbsTable, BbsCount);
+ DEBUG_CODE_END();
+
+ return Status;
+}
+
+/**
+ Boot the legacy system with the boot option
+
+ @param Option The legacy boot option which have BBS device path
+
+ @retval EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ @retval EFI_STATUS Return the status of LegacyBios->LegacyBoot ().
+
+**/
+EFI_STATUS
+BdsLibDoLegacyBoot (
+ IN BDS_COMMON_OPTION *Option
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_EVENT LegacyBootEvent;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ //
+ // If no LegacyBios protocol we do not support legacy boot
+ //
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Notes: if we separate the int 19, then we don't need to refresh BBS
+ //
+ BdsRefreshBbsTableForBoot (Option);
+
+ //
+ // Write boot to OS performance data for legacy boot.
+ //
+ PERF_CODE (
+ //
+ // Create an event to be signalled when Legacy Boot occurs to write performance data.
+ //
+ Status = EfiCreateEventLegacyBootEx(
+ TPL_NOTIFY,
+ WriteBootToOsPerformanceData,
+ NULL,
+ &LegacyBootEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ );
+
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Legacy Boot: %S\n", Option->Description));
+ return LegacyBios->LegacyBoot (
+ LegacyBios,
+ (BBS_BBS_DEVICE_PATH *) Option->DevicePath,
+ Option->LoadOptionsSize,
+ Option->LoadOptions
+ );
+}
+
+/**
+ Internal function to check if the input boot option is a valid EFI NV Boot####.
+
+ @param OptionToCheck Boot option to be checked.
+
+ @retval TRUE This boot option matches a valid EFI NV Boot####.
+ @retval FALSE If not.
+
+**/
+BOOLEAN
+IsBootOptionValidNVVarialbe (
+ IN BDS_COMMON_OPTION *OptionToCheck
+ )
+{
+ LIST_ENTRY TempList;
+ BDS_COMMON_OPTION *BootOption;
+ BOOLEAN Valid;
+ CHAR16 OptionName[20];
+
+ Valid = FALSE;
+
+ InitializeListHead (&TempList);
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionToCheck->BootCurrent);
+
+ BootOption = BdsLibVariableToOption (&TempList, OptionName);
+ if (BootOption == NULL) {
+ return FALSE;
+ }
+
+ //
+ // If the Boot Option Number and Device Path matches, OptionToCheck matches a
+ // valid EFI NV Boot####.
+ //
+ if ((OptionToCheck->BootCurrent == BootOption->BootCurrent) &&
+ (CompareMem (OptionToCheck->DevicePath, BootOption->DevicePath, GetDevicePathSize (OptionToCheck->DevicePath)) == 0))
+ {
+ Valid = TRUE;
+ }
+
+ FreePool (BootOption);
+
+ return Valid;
+}
+
+/**
+ Check whether a USB device match the specified USB Class device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbClass The USB Class device path to match.
+
+ @retval TRUE The USB device match the USB Class device path.
+ @retval FALSE The USB device does not match the USB Class device path.
+
+**/
+BOOLEAN
+BdsMatchUsbClass (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_CLASS_DEVICE_PATH *UsbClass
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT8 DeviceClass;
+ UINT8 DeviceSubClass;
+ UINT8 DeviceProtocol;
+
+ if ((DevicePathType (UsbClass) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbClass) != MSG_USB_CLASS_DP)){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->VendorId != 0xffff) &&
+ (UsbClass->VendorId != DevDesc.IdVendor)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->ProductId != 0xffff) &&
+ (UsbClass->ProductId != DevDesc.IdProduct)) {
+ return FALSE;
+ }
+
+ DeviceClass = DevDesc.DeviceClass;
+ DeviceSubClass = DevDesc.DeviceSubClass;
+ DeviceProtocol = DevDesc.DeviceProtocol;
+ if (DeviceClass == 0) {
+ //
+ // If Class in Device Descriptor is set to 0, use the Class, SubClass and
+ // Protocol in Interface Descriptor instead.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ DeviceClass = IfDesc.InterfaceClass;
+ DeviceSubClass = IfDesc.InterfaceSubClass;
+ DeviceProtocol = IfDesc.InterfaceProtocol;
+ }
+
+ //
+ // Check Class, SubClass and Protocol.
+ //
+ if ((UsbClass->DeviceClass != 0xff) &&
+ (UsbClass->DeviceClass != DeviceClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceSubClass != 0xff) &&
+ (UsbClass->DeviceSubClass != DeviceSubClass)) {
+ return FALSE;
+ }
+
+ if ((UsbClass->DeviceProtocol != 0xff) &&
+ (UsbClass->DeviceProtocol != DeviceProtocol)) {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Check whether a USB device match the specified USB WWID device path. This
+ function follows "Load Option Processing" behavior in UEFI specification.
+
+ @param UsbIo USB I/O protocol associated with the USB device.
+ @param UsbWwid The USB WWID device path to match.
+
+ @retval TRUE The USB device match the USB WWID device path.
+ @retval FALSE The USB device does not match the USB WWID device path.
+
+**/
+BOOLEAN
+BdsMatchUsbWwid (
+ IN EFI_USB_IO_PROTOCOL *UsbIo,
+ IN USB_WWID_DEVICE_PATH *UsbWwid
+ )
+{
+ EFI_STATUS Status;
+ EFI_USB_DEVICE_DESCRIPTOR DevDesc;
+ EFI_USB_INTERFACE_DESCRIPTOR IfDesc;
+ UINT16 *LangIdTable;
+ UINT16 TableSize;
+ UINT16 Index;
+ CHAR16 *CompareStr;
+ UINTN CompareLen;
+ CHAR16 *SerialNumberStr;
+ UINTN Length;
+
+ if ((DevicePathType (UsbWwid) != MESSAGING_DEVICE_PATH) ||
+ (DevicePathSubType (UsbWwid) != MSG_USB_WWID_DP )){
+ return FALSE;
+ }
+
+ //
+ // Check Vendor Id and Product Id.
+ //
+ Status = UsbIo->UsbGetDeviceDescriptor (UsbIo, &DevDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if ((DevDesc.IdVendor != UsbWwid->VendorId) ||
+ (DevDesc.IdProduct != UsbWwid->ProductId)) {
+ return FALSE;
+ }
+
+ //
+ // Check Interface Number.
+ //
+ Status = UsbIo->UsbGetInterfaceDescriptor (UsbIo, &IfDesc);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ if (IfDesc.InterfaceNumber != UsbWwid->InterfaceNumber) {
+ return FALSE;
+ }
+
+ //
+ // Check Serial Number.
+ //
+ if (DevDesc.StrSerialNumber == 0) {
+ return FALSE;
+ }
+
+ //
+ // Get all supported languages.
+ //
+ TableSize = 0;
+ LangIdTable = NULL;
+ Status = UsbIo->UsbGetSupportedLanguages (UsbIo, &LangIdTable, &TableSize);
+ if (EFI_ERROR (Status) || (TableSize == 0) || (LangIdTable == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Serial number in USB WWID device path is the last 64-or-less UTF-16 characters.
+ //
+ CompareStr = (CHAR16 *) (UINTN) (UsbWwid + 1);
+ CompareLen = (DevicePathNodeLength (UsbWwid) - sizeof (USB_WWID_DEVICE_PATH)) / sizeof (CHAR16);
+ if (CompareStr[CompareLen - 1] == L'\0') {
+ CompareLen--;
+ }
+
+ //
+ // Compare serial number in each supported language.
+ //
+ for (Index = 0; Index < TableSize / sizeof (UINT16); Index++) {
+ SerialNumberStr = NULL;
+ Status = UsbIo->UsbGetStringDescriptor (
+ UsbIo,
+ LangIdTable[Index],
+ DevDesc.StrSerialNumber,
+ &SerialNumberStr
+ );
+ if (EFI_ERROR (Status) || (SerialNumberStr == NULL)) {
+ continue;
+ }
+
+ Length = StrLen (SerialNumberStr);
+ if ((Length >= CompareLen) &&
+ (CompareMem (SerialNumberStr + Length - CompareLen, CompareStr, CompareLen * sizeof (CHAR16)) == 0)) {
+ FreePool (SerialNumberStr);
+ return TRUE;
+ }
+
+ FreePool (SerialNumberStr);
+ }
+
+ return FALSE;
+}
+
+/**
+ Find a USB device path which match the specified short-form device path start
+ with USB Class or USB WWID device path and load the boot file then return the
+ image handle. If ParentDevicePath is NULL, this function will search in all USB
+ devices of the platform. If ParentDevicePath is not NULL,this function will only
+ search in its child devices.
+
+ @param ParentDevicePath The device path of the parent.
+ @param ShortFormDevicePath The USB Class or USB WWID device path to match.
+
+ @return The image Handle if find load file from specified short-form device path
+ or NULL if not found.
+
+**/
+EFI_HANDLE *
+BdsFindUsbDevice (
+ IN EFI_DEVICE_PATH_PROTOCOL *ParentDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN UsbIoHandleCount;
+ EFI_HANDLE *UsbIoHandleBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *UsbIoDevicePath;
+ EFI_USB_IO_PROTOCOL *UsbIo;
+ UINTN Index;
+ UINTN ParentSize;
+ UINTN Size;
+ EFI_HANDLE ImageHandle;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *NextDevicePath;
+
+ FullDevicePath = NULL;
+ ImageHandle = NULL;
+
+ //
+ // Get all UsbIo Handles.
+ //
+ UsbIoHandleCount = 0;
+ UsbIoHandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiUsbIoProtocolGuid,
+ NULL,
+ &UsbIoHandleCount,
+ &UsbIoHandleBuffer
+ );
+ if (EFI_ERROR (Status) || (UsbIoHandleCount == 0) || (UsbIoHandleBuffer == NULL)) {
+ return NULL;
+ }
+
+ ParentSize = (ParentDevicePath == NULL) ? 0 : GetDevicePathSize (ParentDevicePath);
+ for (Index = 0; Index < UsbIoHandleCount; Index++) {
+ //
+ // Get the Usb IO interface.
+ //
+ Status = gBS->HandleProtocol(
+ UsbIoHandleBuffer[Index],
+ &gEfiUsbIoProtocolGuid,
+ (VOID **) &UsbIo
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ UsbIoDevicePath = DevicePathFromHandle (UsbIoHandleBuffer[Index]);
+ if (UsbIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (ParentDevicePath != NULL) {
+ //
+ // Compare starting part of UsbIoHandle's device path with ParentDevicePath.
+ //
+ Size = GetDevicePathSize (UsbIoDevicePath);
+ if ((Size < ParentSize) ||
+ (CompareMem (UsbIoDevicePath, ParentDevicePath, ParentSize - END_DEVICE_PATH_LENGTH) != 0)) {
+ continue;
+ }
+ }
+
+ if (BdsMatchUsbClass (UsbIo, (USB_CLASS_DEVICE_PATH *) ShortFormDevicePath) ||
+ BdsMatchUsbWwid (UsbIo, (USB_WWID_DEVICE_PATH *) ShortFormDevicePath)) {
+ //
+ // Try to find if there is the boot file in this DevicePath
+ //
+ NextDevicePath = NextDevicePathNode (ShortFormDevicePath);
+ if (!IsDevicePathEnd (NextDevicePath)) {
+ FullDevicePath = AppendDevicePath (UsbIoDevicePath, NextDevicePath);
+ //
+ // Connect the full device path, so that Simple File System protocol
+ // could be installed for this USB device.
+ //
+ BdsLibConnectDevicePath (FullDevicePath);
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FullDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ FreePool (FullDevicePath);
+ } else {
+ FullDevicePath = UsbIoDevicePath;
+ Status = EFI_NOT_FOUND;
+ }
+
+ //
+ // If we didn't find an image directly, we need to try as if it is a removable device boot option
+ // and load the image according to the default boot behavior for removable device.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // check if there is a bootable removable media could be found in this device path ,
+ // and get the bootable media handle
+ //
+ Handle = BdsLibGetBootableHandle(UsbIoDevicePath);
+ if (Handle == NULL) {
+ continue;
+ }
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ FullDevicePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (FullDevicePath != NULL) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FullDevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // The DevicePath failed, and it's not a valid
+ // removable media device.
+ //
+ continue;
+ }
+ } else {
+ continue;
+ }
+ }
+ break;
+ }
+ }
+
+ FreePool (UsbIoHandleBuffer);
+ return ImageHandle;
+}
+
+/**
+ Expand USB Class or USB WWID device path node to be full device path of a USB
+ device in platform then load the boot file on this full device path and return the
+ image handle.
+
+ This function support following 4 cases:
+ 1) Boot Option device path starts with a USB Class or USB WWID device path,
+ and there is no Media FilePath device path in the end.
+ In this case, it will follow Removable Media Boot Behavior.
+ 2) Boot Option device path starts with a USB Class or USB WWID device path,
+ and ended with Media FilePath device path.
+ 3) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, while not ended with Media
+ FilePath device path. In this case, it will follow Removable Media Boot Behavior.
+ 4) Boot Option device path starts with a full device path to a USB Host Controller,
+ contains a USB Class or USB WWID device path node, and ended with Media
+ FilePath device path.
+
+ @param DevicePath The Boot Option device path.
+
+ @return The image handle of boot file, or NULL if there is no boot file found in
+ the specified USB Class or USB WWID device path.
+
+**/
+EFI_HANDLE *
+BdsExpandUsbShortFormDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_HANDLE *ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ShortFormDevicePath;
+
+ //
+ // Search for USB Class or USB WWID device path node.
+ //
+ ShortFormDevicePath = NULL;
+ ImageHandle = NULL;
+ TempDevicePath = DevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
+ ShortFormDevicePath = TempDevicePath;
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ if (ShortFormDevicePath == NULL) {
+ //
+ // No USB Class or USB WWID device path node found, do nothing.
+ //
+ return NULL;
+ }
+
+ if (ShortFormDevicePath == DevicePath) {
+ //
+ // Boot Option device path starts with USB Class or USB WWID device path.
+ //
+ ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
+ if (ImageHandle == NULL) {
+ //
+ // Failed to find a match in existing devices, connect the short form USB
+ // device path and try again.
+ //
+ BdsLibConnectUsbDevByShortFormDP (0xff, ShortFormDevicePath);
+ ImageHandle = BdsFindUsbDevice (NULL, ShortFormDevicePath);
+ }
+ } else {
+ //
+ // Boot Option device path contains USB Class or USB WWID device path node.
+ //
+
+ //
+ // Prepare the parent device path for search.
+ //
+ TempDevicePath = DuplicateDevicePath (DevicePath);
+ ASSERT (TempDevicePath != NULL);
+ SetDevicePathEndNode (((UINT8 *) TempDevicePath) + ((UINTN) ShortFormDevicePath - (UINTN) DevicePath));
+
+ //
+ // The USB Host Controller device path is already in Boot Option device path
+ // and USB Bus driver already support RemainingDevicePath starts with USB
+ // Class or USB WWID device path, so just search in existing USB devices and
+ // doesn't perform ConnectController here.
+ //
+ ImageHandle = BdsFindUsbDevice (TempDevicePath, ShortFormDevicePath);
+ FreePool (TempDevicePath);
+ }
+
+ return ImageHandle;
+}
+
+/**
+ Process the boot option follow the UEFI specification and
+ special treat the legacy boot option with BBS_DEVICE_PATH.
+
+ @param Option The boot option need to be processed
+ @param DevicePath The device path which describe where to load the
+ boot image or the legacy BBS device path to boot
+ the legacy OS
+ @param ExitDataSize The size of exit data.
+ @param ExitData Data returned when Boot image failed.
+
+ @retval EFI_SUCCESS Boot from the input boot option successfully.
+ @retval EFI_NOT_FOUND If the Device Path is not found in the system
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBootViaBootOption (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT UINTN *ExitDataSize,
+ OUT CHAR16 **ExitData OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS StatusLogo;
+ EFI_HANDLE Handle;
+ EFI_HANDLE ImageHandle;
+ EFI_DEVICE_PATH_PROTOCOL *FilePath;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ EFI_DEVICE_PATH_PROTOCOL *WorkingDevicePath;
+ LIST_ENTRY TempBootLists;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+
+ Status = EFI_SUCCESS;
+ *ExitDataSize = 0;
+ *ExitData = NULL;
+
+ //
+ // If it's Device Path that starts with a hard drive path, append it with the front part to compose a
+ // full device path
+ //
+ WorkingDevicePath = NULL;
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)) {
+ WorkingDevicePath = BdsExpandPartitionPartialDevicePathToFull (
+ (HARDDRIVE_DEVICE_PATH *)DevicePath
+ );
+ if (WorkingDevicePath != NULL) {
+ DevicePath = WorkingDevicePath;
+ }
+ }
+
+ //
+ // Set Boot Current
+ //
+ if (IsBootOptionValidNVVarialbe (Option)) {
+ //
+ // For a temporary boot (i.e. a boot by selected a EFI Shell using "Boot From File"), Boot Current is actually not valid.
+ // In this case, "BootCurrent" is not created.
+ // Only create the BootCurrent variable when it points to a valid Boot#### variable.
+ //
+ SetVariableAndReportStatusCodeOnError (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT16),
+ &Option->BootCurrent
+ );
+ }
+
+ //
+ // Signal the EVT_SIGNAL_READY_TO_BOOT event
+ //
+ EfiSignalEventReadyToBoot();
+
+ //
+ // Report Status Code to indicate ReadyToBoot event was signalled
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_READY_TO_BOOT_EVENT));
+
+ //
+ // Expand USB Class or USB WWID device path node to be full device path of a USB
+ // device in platform then load the boot file on this full device path and get the
+ // image handle.
+ //
+ ImageHandle = BdsExpandUsbShortFormDevicePath (DevicePath);
+
+ //
+ // Adjust the different type memory page number just before booting
+ // and save the updated info into the variable for next boot to use
+ //
+ BdsSetMemoryTypeInformationVariable ();
+
+ //
+ // By expanding the USB Class or WWID device path, the ImageHandle has returnned.
+ // Here get the ImageHandle for the non USB class or WWID device path.
+ //
+ if (ImageHandle == NULL) {
+ ASSERT (Option->DevicePath != NULL);
+ if ((DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
+ ) {
+ //
+ // Check to see if we should legacy BOOT. If yes then do the legacy boot
+ //
+ return BdsLibDoLegacyBoot (Option);
+ }
+
+ //
+ // If the boot option point to Internal FV shell, make sure it is valid
+ //
+ Status = BdsLibUpdateFvFileDevicePath (&DevicePath, PcdGetPtr(PcdShellFile));
+ if (!EFI_ERROR(Status)) {
+ if (Option->DevicePath != NULL) {
+ FreePool(Option->DevicePath);
+ }
+ Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
+ ASSERT(Option->DevicePath != NULL);
+ CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+ //
+ // Update the shell boot option
+ //
+ InitializeListHead (&TempBootLists);
+ BdsLibRegisterNewOption (&TempBootLists, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+ //
+ // free the temporary device path created by BdsLibUpdateFvFileDevicePath()
+ //
+ FreePool (DevicePath);
+ DevicePath = Option->DevicePath;
+ }
+
+ DEBUG_CODE_BEGIN();
+
+ if (Option->Description == NULL) {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting from unknown device path\n"));
+ } else {
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Booting %S\n", Option->Description));
+ }
+
+ DEBUG_CODE_END();
+
+ //
+ // Report status code for OS Loader LoadImage.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ DevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+
+ //
+ // If we didn't find an image directly, we need to try as if it is a removable device boot option
+ // and load the image according to the default boot behavior for removable device.
+ //
+ if (EFI_ERROR (Status)) {
+ //
+ // check if there is a bootable removable media could be found in this device path ,
+ // and get the bootable media handle
+ //
+ Handle = BdsLibGetBootableHandle(DevicePath);
+ if (Handle != NULL) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ FilePath = FileDevicePath (Handle, EFI_REMOVABLE_MEDIA_FILE_NAME);
+ if (FilePath != NULL) {
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderLoad));
+ Status = gBS->LoadImage (
+ TRUE,
+ gImageHandle,
+ FilePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+ }
+ }
+ }
+ }
+ //
+ // Provide the image with it's load options
+ //
+ if ((ImageHandle == NULL) || (EFI_ERROR(Status))) {
+ //
+ // Report Status Code to indicate that the failure to load boot option
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_LOAD_ERROR)
+ );
+ goto Done;
+ }
+
+ Status = gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+ ASSERT_EFI_ERROR (Status);
+
+ if (Option->LoadOptionsSize != 0) {
+ ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
+ ImageInfo->LoadOptions = Option->LoadOptions;
+ }
+
+ //
+ // Clean to NULL because the image is loaded directly from the firmwares boot manager.
+ //
+ ImageInfo->ParentHandle = NULL;
+
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // the 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ //
+ // Write boot to OS performance data for UEFI boot
+ //
+ PERF_CODE (
+ WriteBootToOsPerformanceData (NULL, NULL);
+ );
+
+ //
+ // Report status code for OS Loader StartImage.
+ //
+ REPORT_STATUS_CODE (EFI_PROGRESS_CODE, PcdGet32 (PcdProgressCodeOsLoaderStart));
+
+ Status = gBS->StartImage (ImageHandle, ExitDataSize, ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Image Return Status = %r\n", Status));
+ if (EFI_ERROR (Status)) {
+ //
+ // Report Status Code to indicate that boot failure
+ //
+ REPORT_STATUS_CODE (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_EC_BOOT_OPTION_FAILED)
+ );
+ }
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+
+Done:
+ //
+ // Set Logo status invalid after trying one boot option
+ //
+ BootLogo = NULL;
+ StatusLogo = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (StatusLogo) && (BootLogo != NULL)) {
+ BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ }
+
+ //
+ // Clear Boot Current
+ // Deleting variable with current implementation shouldn't fail.
+ //
+ gRT->SetVariable (
+ L"BootCurrent",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ 0,
+ NULL
+ );
+
+ return Status;
+}
+
+
+/**
+ Expand a device path that starts with a hard drive media device path node to be a
+ full device path that includes the full hardware path to the device. We need
+ to do this so it can be booted. As an optimization the front match (the part point
+ to the partition node. E.g. ACPI() /PCI()/ATA()/Partition() ) is saved in a variable
+ so a connect all is not required on every boot. All successful history device path
+ which point to partition node (the front part) will be saved.
+
+ @param HardDriveDevicePath EFI Device Path to boot, if it starts with a hard
+ drive media device path.
+ @return A Pointer to the full device path or NULL if a valid Hard Drive devic path
+ cannot be found.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsExpandPartitionPartialDevicePathToFull (
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ UINTN BlockIoHandleCount;
+ EFI_HANDLE *BlockIoBuffer;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN Index;
+ UINTN InstanceNum;
+ EFI_DEVICE_PATH_PROTOCOL *CachedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN CachedDevicePathSize;
+ BOOLEAN DeviceExist;
+ BOOLEAN NeedAdjust;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ UINTN Size;
+
+ FullDevicePath = NULL;
+ //
+ // Check if there is prestore HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
+ // If exist, search the front path which point to partition node in the variable instants.
+ // If fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, reconnect all and search in all system
+ //
+ GetVariable2 (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ (VOID **) &CachedDevicePath,
+ &CachedDevicePathSize
+ );
+
+ //
+ // Delete the invalid HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable.
+ //
+ if ((CachedDevicePath != NULL) && !IsDevicePathValid (CachedDevicePath, CachedDevicePathSize)) {
+ FreePool (CachedDevicePath);
+ CachedDevicePath = NULL;
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ 0,
+ 0,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ DeviceExist = FALSE;
+ NeedAdjust = FALSE;
+ do {
+ //
+ // Check every instance of the variable
+ // First, check whether the instance contain the partition node, which is needed for distinguishing multi
+ // partial partition boot option. Second, check whether the instance could be connected.
+ //
+ Instance = GetNextDevicePathInstance (&TempNewDevicePath, &Size);
+ if (MatchPartitionDevicePathNode (Instance, HardDriveDevicePath)) {
+ //
+ // Connect the device path instance, the device path point to hard drive media device path node
+ // e.g. ACPI() /PCI()/ATA()/Partition()
+ //
+ Status = BdsLibConnectDevicePath (Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ break;
+ }
+ }
+ //
+ // Come here means the first instance is not matched
+ //
+ NeedAdjust = TRUE;
+ FreePool(Instance);
+ } while (TempNewDevicePath != NULL);
+
+ if (DeviceExist) {
+ //
+ // Find the matched device path.
+ // Append the file path information from the boot option and return the fully expanded device path.
+ //
+ DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+ FullDevicePath = AppendDevicePath (Instance, DevicePath);
+
+ //
+ // Adjust the HD_BOOT_DEVICE_PATH_VARIABLE_NAME instances sequence if the matched one is not first one.
+ //
+ if (NeedAdjust) {
+ //
+ // First delete the matched instance.
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, Instance );
+ FreePool (TempNewDevicePath);
+
+ //
+ // Second, append the remaining path after the matched instance
+ //
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (Instance, CachedDevicePath );
+ FreePool (TempNewDevicePath);
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
+ //
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+ }
+
+ FreePool (Instance);
+ FreePool (CachedDevicePath);
+ return FullDevicePath;
+ }
+ }
+
+ //
+ // If we get here we fail to find or HD_BOOT_DEVICE_PATH_VARIABLE_NAME not exist, and now we need
+ // to search all devices in the system for a matched partition
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+ Status = gBS->LocateHandleBuffer (ByProtocol, &gEfiBlockIoProtocolGuid, NULL, &BlockIoHandleCount, &BlockIoBuffer);
+ if (EFI_ERROR (Status) || BlockIoHandleCount == 0 || BlockIoBuffer == NULL) {
+ //
+ // If there was an error or there are no device handles that support
+ // the BLOCK_IO Protocol, then return.
+ //
+ return NULL;
+ }
+ //
+ // Loop through all the device handles that support the BLOCK_IO Protocol
+ //
+ for (Index = 0; Index < BlockIoHandleCount; Index++) {
+
+ Status = gBS->HandleProtocol (BlockIoBuffer[Index], &gEfiDevicePathProtocolGuid, (VOID *) &BlockIoDevicePath);
+ if (EFI_ERROR (Status) || BlockIoDevicePath == NULL) {
+ continue;
+ }
+
+ if (MatchPartitionDevicePathNode (BlockIoDevicePath, HardDriveDevicePath)) {
+ //
+ // Find the matched partition device path
+ //
+ DevicePath = NextDevicePathNode ((EFI_DEVICE_PATH_PROTOCOL *) HardDriveDevicePath);
+ FullDevicePath = AppendDevicePath (BlockIoDevicePath, DevicePath);
+
+ //
+ // Save the matched partition device path in HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
+ //
+ if (CachedDevicePath != NULL) {
+ //
+ // Save the matched partition device path as first instance of HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable
+ //
+ if (BdsLibMatchDevicePaths (CachedDevicePath, BlockIoDevicePath)) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = BdsLibDelPartMatchInstance (CachedDevicePath, BlockIoDevicePath);
+ FreePool(TempNewDevicePath);
+ }
+
+ if (CachedDevicePath != NULL) {
+ TempNewDevicePath = CachedDevicePath;
+ CachedDevicePath = AppendDevicePathInstance (BlockIoDevicePath, CachedDevicePath);
+ FreePool(TempNewDevicePath);
+ } else {
+ CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+ }
+
+ //
+ // Here limit the device path instance number to 12, which is max number for a system support 3 IDE controller
+ // If the user try to boot many OS in different HDs or partitions, in theory,
+ // the HD_BOOT_DEVICE_PATH_VARIABLE_NAME variable maybe become larger and larger.
+ //
+ InstanceNum = 0;
+ ASSERT (CachedDevicePath != NULL);
+ TempNewDevicePath = CachedDevicePath;
+ while (!IsDevicePathEnd (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ //
+ // Parse one instance
+ //
+ while (!IsDevicePathEndType (TempNewDevicePath)) {
+ TempNewDevicePath = NextDevicePathNode (TempNewDevicePath);
+ }
+ InstanceNum++;
+ //
+ // If the CachedDevicePath variable contain too much instance, only remain 12 instances.
+ //
+ if (InstanceNum >= 12) {
+ SetDevicePathEndNode (TempNewDevicePath);
+ break;
+ }
+ }
+ } else {
+ CachedDevicePath = DuplicateDevicePath (BlockIoDevicePath);
+ }
+
+ //
+ // Save the matching Device Path so we don't need to do a connect all next time
+ // Failure to set the variable only impacts the performance when next time expanding the short-form device path.
+ //
+ Status = gRT->SetVariable (
+ HD_BOOT_DEVICE_PATH_VARIABLE_NAME,
+ &gHdBootDevicePathVariablGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (CachedDevicePath),
+ CachedDevicePath
+ );
+
+ break;
+ }
+ }
+
+ if (CachedDevicePath != NULL) {
+ FreePool (CachedDevicePath);
+ }
+ if (BlockIoBuffer != NULL) {
+ FreePool (BlockIoBuffer);
+ }
+ return FullDevicePath;
+}
+
+/**
+ Check whether there is a instance in BlockIoDevicePath, which contain multi device path
+ instances, has the same partition node with HardDriveDevicePath device path
+
+ @param BlockIoDevicePath Multi device path instances which need to check
+ @param HardDriveDevicePath A device path which starts with a hard drive media
+ device path.
+
+ @retval TRUE There is a matched device path instance.
+ @retval FALSE There is no matched device path instance.
+
+**/
+BOOLEAN
+EFIAPI
+MatchPartitionDevicePathNode (
+ IN EFI_DEVICE_PATH_PROTOCOL *BlockIoDevicePath,
+ IN HARDDRIVE_DEVICE_PATH *HardDriveDevicePath
+ )
+{
+ HARDDRIVE_DEVICE_PATH *TmpHdPath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN Match;
+ EFI_DEVICE_PATH_PROTOCOL *BlockIoHdDevicePathNode;
+
+ if ((BlockIoDevicePath == NULL) || (HardDriveDevicePath == NULL)) {
+ return FALSE;
+ }
+
+ //
+ // Make PreviousDevicePath == the device path node before the end node
+ //
+ DevicePath = BlockIoDevicePath;
+ BlockIoHdDevicePathNode = NULL;
+
+ //
+ // find the partition device path node
+ //
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePathType (DevicePath) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MEDIA_HARDDRIVE_DP)
+ ) {
+ BlockIoHdDevicePathNode = DevicePath;
+ break;
+ }
+
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (BlockIoHdDevicePathNode == NULL) {
+ return FALSE;
+ }
+ //
+ // See if the harddrive device path in blockio matches the orig Hard Drive Node
+ //
+ TmpHdPath = (HARDDRIVE_DEVICE_PATH *) BlockIoHdDevicePathNode;
+ Match = FALSE;
+
+ //
+ // Check for the match
+ //
+ if ((TmpHdPath->MBRType == HardDriveDevicePath->MBRType) &&
+ (TmpHdPath->SignatureType == HardDriveDevicePath->SignatureType)) {
+ switch (TmpHdPath->SignatureType) {
+ case SIGNATURE_TYPE_GUID:
+ Match = CompareGuid ((EFI_GUID *)TmpHdPath->Signature, (EFI_GUID *)HardDriveDevicePath->Signature);
+ break;
+ case SIGNATURE_TYPE_MBR:
+ Match = (BOOLEAN)(*((UINT32 *)(&(TmpHdPath->Signature[0]))) == ReadUnaligned32((UINT32 *)(&(HardDriveDevicePath->Signature[0]))));
+ break;
+ default:
+ Match = FALSE;
+ break;
+ }
+ }
+
+ return Match;
+}
+
+/**
+ Delete the boot option associated with the handle passed in.
+
+ @param Handle The handle which present the device path to create
+ boot option
+
+ @retval EFI_SUCCESS Delete the boot option success
+ @retval EFI_NOT_FOUND If the Device Path is not found in the system
+ @retval EFI_OUT_OF_RESOURCES Lack of memory resource
+ @retval Other Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsLibDeleteOptionFromHandle (
+ IN EFI_HANDLE Handle
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
+ UINTN DevicePathSize;
+ UINTN OptionDevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ UINT8 *TempPtr;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ BootOrderSize = 0;
+
+ //
+ // Check "BootOrder" variable, if no, means there is no any boot order.
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (BootOrder == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Convert device handle to device path protocol instance
+ //
+ DevicePath = DevicePathFromHandle (Handle);
+ if (DevicePath == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ DevicePathSize = GetDevicePathSize (DevicePath);
+
+ //
+ // Loop all boot order variable and find the matching device path
+ //
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+
+ if (BootOptionVar == NULL) {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!ValidateOption(BootOptionVar, BootOptionSize)) {
+ BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
+ FreePool (BootOptionVar);
+ Index++;
+ continue;
+ }
+
+ TempPtr = BootOptionVar;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ OptionDevicePathSize = GetDevicePathSize (OptionDevicePath);
+
+ //
+ // Check whether the device path match
+ //
+ if ((OptionDevicePathSize == DevicePathSize) &&
+ (CompareMem (DevicePath, OptionDevicePath, DevicePathSize) == 0)) {
+ BdsDeleteBootOption (BootOrder[Index], BootOrder, &BootOrderSize);
+ FreePool (BootOptionVar);
+ break;
+ }
+
+ FreePool (BootOptionVar);
+ Index++;
+ }
+
+ //
+ // Adjust number of boot option for "BootOrder" variable.
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Shrinking variable with existing variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+
+/**
+ Delete all invalid EFI boot options.
+
+ @retval EFI_SUCCESS Delete all invalid boot option success
+ @retval EFI_NOT_FOUND Variable "BootOrder" is not found
+ @retval EFI_OUT_OF_RESOURCES Lack of memory resource
+ @retval Other Error return value from SetVariable()
+
+**/
+EFI_STATUS
+BdsDeleteAllInvalidEfiBootOption (
+ VOID
+ )
+{
+ UINT16 *BootOrder;
+ UINT8 *BootOptionVar;
+ UINTN BootOrderSize;
+ UINTN BootOptionSize;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+ UINT16 BootOption[BOOT_OPTION_MAX_CHAR];
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ UINT8 *TempPtr;
+ CHAR16 *Description;
+ BOOLEAN Corrupted;
+
+ Status = EFI_SUCCESS;
+ BootOrder = NULL;
+ Description = NULL;
+ OptionDevicePath = NULL;
+ BootOrderSize = 0;
+ Corrupted = FALSE;
+
+ //
+ // Check "BootOrder" variable firstly, this variable hold the number of boot options
+ //
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ if (NULL == BootOrder) {
+ return EFI_NOT_FOUND;
+ }
+
+ Index = 0;
+ while (Index < BootOrderSize / sizeof (UINT16)) {
+ UnicodeSPrint (BootOption, sizeof (BootOption), L"Boot%04x", BootOrder[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (NULL == BootOptionVar) {
+ FreePool (BootOrder);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (!ValidateOption(BootOptionVar, BootOptionSize)) {
+ Corrupted = TRUE;
+ } else {
+ TempPtr = BootOptionVar;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ Description = (CHAR16 *) TempPtr;
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+ //
+ // Skip legacy boot option (BBS boot device)
+ //
+ if ((DevicePathType (OptionDevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (OptionDevicePath) == BBS_BBS_DP)) {
+ FreePool (BootOptionVar);
+ Index++;
+ continue;
+ }
+ }
+
+ if (Corrupted || !BdsLibIsValidEFIBootOptDevicePathExt (OptionDevicePath, FALSE, Description)) {
+ //
+ // Delete this invalid boot option "Boot####"
+ //
+ Status = gRT->SetVariable (
+ BootOption,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Mark this boot option in boot order as deleted
+ //
+ BootOrder[Index] = 0xffff;
+ Corrupted = FALSE;
+ }
+
+ FreePool (BootOptionVar);
+ Index++;
+ }
+
+ //
+ // Adjust boot order array
+ //
+ Index2 = 0;
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BootOrder[Index] != 0xffff) {
+ BootOrder[Index2] = BootOrder[Index];
+ Index2 ++;
+ }
+ }
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ Index2 * sizeof (UINT16),
+ BootOrder
+ );
+ //
+ // Shrinking variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOrder);
+
+ return Status;
+}
+
+
+/**
+ For EFI boot option, BDS separate them as six types:
+ 1. Network - The boot option points to the SimpleNetworkProtocol device.
+ Bds will try to automatically create this type boot option when enumerate.
+ 2. Shell - The boot option points to internal flash shell.
+ Bds will try to automatically create this type boot option when enumerate.
+ 3. Removable BlockIo - The boot option only points to the removable media
+ device, like USB flash disk, DVD, Floppy etc.
+ These device should contain a *removable* blockIo
+ protocol in their device handle.
+ Bds will try to automatically create this type boot option
+ when enumerate.
+ 4. Fixed BlockIo - The boot option only points to a Fixed blockIo device,
+ like HardDisk.
+ These device should contain a *fixed* blockIo
+ protocol in their device handle.
+ BDS will skip fixed blockIo devices, and NOT
+ automatically create boot option for them. But BDS
+ will help to delete those fixed blockIo boot option,
+ whose description rule conflict with other auto-created
+ boot options.
+ 5. Non-BlockIo Simplefile - The boot option points to a device whose handle
+ has SimpleFileSystem Protocol, but has no blockio
+ protocol. These devices do not offer blockIo
+ protocol, but BDS still can get the
+ \EFI\BOOT\boot{machinename}.EFI by SimpleFileSystem
+ Protocol.
+ 6. File - The boot option points to a file. These boot options are usually
+ created by user manually or OS loader. BDS will not delete or modify
+ these boot options.
+
+ This function will enumerate all possible boot device in the system, and
+ automatically create boot options for Network, Shell, Removable BlockIo,
+ and Non-BlockIo Simplefile devices.
+ It will only execute once of every boot.
+
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+
+ @retval EFI_SUCCESS Finished all the boot device enumerate and create
+ the boot option base on that boot device
+
+ @retval EFI_OUT_OF_RESOURCES Failed to enumerate the boot device and create the boot option list
+**/
+EFI_STATUS
+EFIAPI
+BdsLibEnumerateAllBootOption (
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ )
+{
+ EFI_STATUS Status;
+ UINT16 FloppyNumber;
+ UINT16 HarddriveNumber;
+ UINT16 CdromNumber;
+ UINT16 UsbNumber;
+ UINT16 MiscNumber;
+ UINT16 ScsiNumber;
+ UINT16 NonBlockNumber;
+ UINTN NumberBlockIoHandles;
+ EFI_HANDLE *BlockIoHandles;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ BOOLEAN Removable[2];
+ UINTN RemovableIndex;
+ UINTN Index;
+ UINTN NumOfLoadFileHandles;
+ EFI_HANDLE *LoadFileHandles;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN DevicePathType;
+ CHAR16 Buffer[40];
+ EFI_HANDLE *FileSystemHandles;
+ UINTN NumberFileSystemHandles;
+ BOOLEAN NeedDelete;
+ EFI_IMAGE_DOS_HEADER DosHeader;
+ CHAR8 *PlatLang;
+ CHAR8 *LastLang;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ FloppyNumber = 0;
+ HarddriveNumber = 0;
+ CdromNumber = 0;
+ UsbNumber = 0;
+ MiscNumber = 0;
+ ScsiNumber = 0;
+ PlatLang = NULL;
+ LastLang = NULL;
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ //
+ // If the boot device enumerate happened, just get the boot
+ // device from the boot order variable
+ //
+ if (mEnumBootDevice) {
+ GetVariable2 (LAST_ENUM_LANGUAGE_VARIABLE_NAME, &gLastEnumLangGuid, (VOID**)&LastLang, NULL);
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&PlatLang, NULL);
+ ASSERT (PlatLang != NULL);
+ if ((LastLang != NULL) && (AsciiStrCmp (LastLang, PlatLang) == 0)) {
+ Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+ FreePool (LastLang);
+ FreePool (PlatLang);
+ return Status;
+ } else {
+ Status = gRT->SetVariable (
+ LAST_ENUM_LANGUAGE_VARIABLE_NAME,
+ &gLastEnumLangGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ AsciiStrSize (PlatLang),
+ PlatLang
+ );
+ //
+ // Failure to set the variable only impacts the performance next time enumerating the boot options.
+ //
+
+ if (LastLang != NULL) {
+ FreePool (LastLang);
+ }
+ FreePool (PlatLang);
+ }
+ }
+
+ //
+ // Notes: this dirty code is to get the legacy boot option from the
+ // BBS table and create to variable as the EFI boot option, it should
+ // be removed after the CSM can provide legacy boot option directly
+ //
+ REFRESH_LEGACY_BOOT_OPTIONS;
+
+ //
+ // Delete invalid boot option
+ //
+ BdsDeleteAllInvalidEfiBootOption ();
+
+ //
+ // Parse removable media followed by fixed media.
+ // The Removable[] array is used by the for-loop below to create removable media boot options
+ // at first, and then to create fixed media boot options.
+ //
+ Removable[0] = FALSE;
+ Removable[1] = TRUE;
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NumberBlockIoHandles,
+ &BlockIoHandles
+ );
+
+ for (RemovableIndex = 0; RemovableIndex < 2; RemovableIndex++) {
+ for (Index = 0; Index < NumberBlockIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlockIoHandles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ //
+ // skip the logical partition
+ //
+ if (EFI_ERROR (Status) || BlkIo->Media->LogicalPartition) {
+ continue;
+ }
+
+ //
+ // firstly fixed block io then the removable block io
+ //
+ if (BlkIo->Media->RemovableMedia == Removable[RemovableIndex]) {
+ continue;
+ }
+ DevicePath = DevicePathFromHandle (BlockIoHandles[Index]);
+ DevicePathType = BdsGetBootTypeFromDevicePath (DevicePath);
+
+ switch (DevicePathType) {
+ case BDS_EFI_ACPI_FLOPPY_BOOT:
+ if (FloppyNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)), FloppyNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_FLOPPY)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ FloppyNumber++;
+ break;
+
+ //
+ // Assume a removable SATA device should be the DVD/CD device, a fixed SATA device should be the Hard Drive device.
+ //
+ case BDS_EFI_MESSAGE_ATAPI_BOOT:
+ case BDS_EFI_MESSAGE_SATA_BOOT:
+ if (BlkIo->Media->RemovableMedia) {
+ if (CdromNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)), CdromNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_CD_DVD)));
+ }
+ CdromNumber++;
+ } else {
+ if (HarddriveNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)), HarddriveNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_HARDDRIVE)));
+ }
+ HarddriveNumber++;
+ }
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Buffer: %S\n", Buffer));
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ break;
+
+ case BDS_EFI_MESSAGE_USB_DEVICE_BOOT:
+ if (UsbNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)), UsbNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_USB)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ UsbNumber++;
+ break;
+
+ case BDS_EFI_MESSAGE_SCSI_BOOT:
+ if (ScsiNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)), ScsiNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_SCSI)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ ScsiNumber++;
+ break;
+
+ case BDS_EFI_MESSAGE_MISC_BOOT:
+ default:
+ if (MiscNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)), MiscNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_MISC)));
+ }
+ BdsLibBuildOptionFromHandle (BlockIoHandles[Index], BdsBootOptionList, Buffer);
+ MiscNumber++;
+ break;
+ }
+ }
+ }
+
+ if (NumberBlockIoHandles != 0) {
+ FreePool (BlockIoHandles);
+ }
+
+ //
+ // If there is simple file protocol which does not consume block Io protocol, create a boot option for it here.
+ //
+ NonBlockNumber = 0;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberFileSystemHandles,
+ &FileSystemHandles
+ );
+ for (Index = 0; Index < NumberFileSystemHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ FileSystemHandles[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Skip if the file system handle supports a BlkIo protocol,
+ //
+ continue;
+ }
+
+ //
+ // Do the removable Media thing. \EFI\BOOT\boot{machinename}.EFI
+ // machinename is ia32, ia64, x64, ...
+ //
+ Hdr.Union = &HdrData;
+ NeedDelete = TRUE;
+ Status = BdsLibGetImageHeader (
+ FileSystemHandles[Index],
+ EFI_REMOVABLE_MEDIA_FILE_NAME,
+ &DosHeader,
+ Hdr
+ );
+ if (!EFI_ERROR (Status) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+ Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ NeedDelete = FALSE;
+ }
+
+ if (NeedDelete) {
+ //
+ // No such file or the file is not a EFI application, delete this boot option
+ //
+ BdsLibDeleteOptionFromHandle (FileSystemHandles[Index]);
+ } else {
+ if (NonBlockNumber != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)), NonBlockNumber);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NON_BLOCK)));
+ }
+ BdsLibBuildOptionFromHandle (FileSystemHandles[Index], BdsBootOptionList, Buffer);
+ NonBlockNumber++;
+ }
+ }
+
+ if (NumberFileSystemHandles != 0) {
+ FreePool (FileSystemHandles);
+ }
+
+ //
+ // Parse Network Boot Device
+ //
+ NumOfLoadFileHandles = 0;
+ //
+ // Search Load File protocol for PXE boot option.
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &NumOfLoadFileHandles,
+ &LoadFileHandles
+ );
+
+ for (Index = 0; Index < NumOfLoadFileHandles; Index++) {
+ if (Index != 0) {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s %d", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)), Index);
+ } else {
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"%s", BdsLibGetStringById (STRING_TOKEN (STR_DESCRIPTION_NETWORK)));
+ }
+ BdsLibBuildOptionFromHandle (LoadFileHandles[Index], BdsBootOptionList, Buffer);
+ }
+
+ if (NumOfLoadFileHandles != 0) {
+ FreePool (LoadFileHandles);
+ }
+
+ //
+ // Check if we have on flash shell
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ PcdGetPtr(PcdShellFile),
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if no shell file in the FV
+ //
+ continue;
+ }
+ //
+ // Build the shell boot option
+ //
+ BdsLibBuildOptionFromShell (FvHandleBuffer[Index], BdsBootOptionList);
+ }
+
+ if (FvHandleCount != 0) {
+ FreePool (FvHandleBuffer);
+ }
+ //
+ // Make sure every boot only have one time
+ // boot device enumerate
+ //
+ Status = BdsLibBuildOptionFromVar (BdsBootOptionList, L"BootOrder");
+ mEnumBootDevice = TRUE;
+
+ return Status;
+}
+
+/**
+ Build the boot option with the handle parsed in
+
+ @param Handle The handle which present the device path to create
+ boot option
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+ @param String The description of the boot option.
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromHandle (
+ IN EFI_HANDLE Handle,
+ IN LIST_ENTRY *BdsBootOptionList,
+ IN CHAR16 *String
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ DevicePath = DevicePathFromHandle (Handle);
+
+ //
+ // Create and register new boot option
+ //
+ BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, String, L"BootOrder");
+}
+
+
+/**
+ Build the on flash shell boot option with the handle parsed in.
+
+ @param Handle The handle which present the device path to create
+ on flash shell boot option
+ @param BdsBootOptionList The header of the link list which indexed all
+ current boot options
+
+**/
+VOID
+EFIAPI
+BdsLibBuildOptionFromShell (
+ IN EFI_HANDLE Handle,
+ IN OUT LIST_ENTRY *BdsBootOptionList
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH ShellNode;
+
+ DevicePath = DevicePathFromHandle (Handle);
+
+ //
+ // Build the shell device path
+ //
+ EfiInitializeFwVolDevicepathNode (&ShellNode, PcdGetPtr(PcdShellFile));
+
+ DevicePath = AppendDevicePathNode (DevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &ShellNode);
+
+ //
+ // Create and register the shell boot option
+ //
+ BdsLibRegisterNewOption (BdsBootOptionList, DevicePath, L"EFI Internal Shell", L"BootOrder");
+
+}
+
+/**
+ Boot from the UEFI spec defined "BootNext" variable.
+
+**/
+VOID
+EFIAPI
+BdsLibBootNext (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *BootNext;
+ UINTN BootNextSize;
+ CHAR16 Buffer[20];
+ BDS_COMMON_OPTION *BootOption;
+ LIST_ENTRY TempList;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+
+ //
+ // Init the boot option name buffer and temp link list
+ //
+ InitializeListHead (&TempList);
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ BootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ //
+ // Clear the boot next variable first
+ //
+ if (BootNext != NULL) {
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Start to build the boot option and try to boot
+ //
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *BootNext);
+ BootOption = BdsLibVariableToOption (&TempList, Buffer);
+ ASSERT (BootOption != NULL);
+ BdsLibConnectDevicePath (BootOption->DevicePath);
+ BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+ FreePool(BootOption);
+ FreePool(BootNext);
+ }
+
+}
+
+/**
+ Return the bootable media handle.
+ First, check the device is connected
+ Second, check whether the device path point to a device which support SimpleFileSystemProtocol,
+ Third, detect the the default boot file in the Media, and return the removable Media handle.
+
+ @param DevicePath Device Path to a bootable device
+
+ @return The bootable media handle. If the media on the DevicePath is not bootable, NULL will return.
+
+**/
+EFI_HANDLE
+EFIAPI
+BdsLibGetBootableHandle (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_TPL OldTpl;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DupDevicePath;
+ EFI_HANDLE Handle;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+ VOID *Buffer;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ UINTN Size;
+ UINTN TempSize;
+ EFI_HANDLE ReturnHandle;
+ EFI_HANDLE *SimpleFileSystemHandles;
+
+ UINTN NumberSimpleFileSystemHandles;
+ UINTN Index;
+ EFI_IMAGE_DOS_HEADER DosHeader;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION HdrData;
+ EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr;
+
+ UpdatedDevicePath = DevicePath;
+
+ //
+ // Enter to critical section to protect the acquired BlockIo instance
+ // from getting released due to the USB mass storage hotplug event
+ //
+ OldTpl = gBS->RaiseTPL (TPL_CALLBACK);
+
+ //
+ // Check whether the device is connected
+ //
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip the case that the boot option point to a simple file protocol which does not consume block Io protocol,
+ //
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to find the proper BlockIo and simple file protocol, maybe because device not present, we need to connect it firstly
+ //
+ UpdatedDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ }
+ } else {
+ //
+ // For removable device boot option, its contained device path only point to the removable device handle,
+ // should make sure all its children handles (its child partion or media handles) are created and connected.
+ //
+ gBS->ConnectController (Handle, NULL, NULL, TRUE);
+ //
+ // Get BlockIo protocol and check removable attribute
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Issue a dummy read to the device to check for media change.
+ // When the removable media is changed, any Block IO read/write will
+ // cause the BlockIo protocol be reinstalled and EFI_MEDIA_CHANGED is
+ // returned. After the Block IO protocol is reinstalled, subsequent
+ // Block IO read/write will success.
+ //
+ Buffer = AllocatePool (BlockIo->Media->BlockSize);
+ if (Buffer != NULL) {
+ BlockIo->ReadBlocks (
+ BlockIo,
+ BlockIo->Media->MediaId,
+ 0,
+ BlockIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool(Buffer);
+ }
+ }
+
+ //
+ // Detect the the default boot file from removable Media
+ //
+
+ //
+ // If fail to get bootable handle specified by a USB boot option, the BDS should try to find other bootable device in the same USB bus
+ // Try to locate the USB node device path first, if fail then use its previous PCI node to search
+ //
+ DupDevicePath = DuplicateDevicePath (DevicePath);
+ ASSERT (DupDevicePath != NULL);
+
+ UpdatedDevicePath = DupDevicePath;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &UpdatedDevicePath, &Handle);
+ //
+ // if the resulting device path point to a usb node, and the usb node is a dummy node, should only let device path only point to the previous Pci node
+ // Acpi()/Pci()/Usb() --> Acpi()/Pci()
+ //
+ if ((DevicePathType (UpdatedDevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (UpdatedDevicePath) == MSG_USB_DP)) {
+ //
+ // Remove the usb node, let the device path only point to PCI node
+ //
+ SetDevicePathEndNode (UpdatedDevicePath);
+ UpdatedDevicePath = DupDevicePath;
+ } else {
+ UpdatedDevicePath = DevicePath;
+ }
+
+ //
+ // Get the device path size of boot option
+ //
+ Size = GetDevicePathSize(UpdatedDevicePath) - sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+ ReturnHandle = NULL;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NumberSimpleFileSystemHandles,
+ &SimpleFileSystemHandles
+ );
+ for (Index = 0; Index < NumberSimpleFileSystemHandles; Index++) {
+ //
+ // Get the device path size of SimpleFileSystem handle
+ //
+ TempDevicePath = DevicePathFromHandle (SimpleFileSystemHandles[Index]);
+ TempSize = GetDevicePathSize (TempDevicePath)- sizeof (EFI_DEVICE_PATH_PROTOCOL); // minus the end node
+ //
+ // Check whether the device path of boot option is part of the SimpleFileSystem handle's device path
+ //
+ if (Size <= TempSize && CompareMem (TempDevicePath, UpdatedDevicePath, Size)==0) {
+ //
+ // Load the default boot file \EFI\BOOT\boot{machinename}.EFI from removable Media
+ // machinename is ia32, ia64, x64, ...
+ //
+ Hdr.Union = &HdrData;
+ Status = BdsLibGetImageHeader (
+ SimpleFileSystemHandles[Index],
+ EFI_REMOVABLE_MEDIA_FILE_NAME,
+ &DosHeader,
+ Hdr
+ );
+ if (!EFI_ERROR (Status) &&
+ EFI_IMAGE_MACHINE_TYPE_SUPPORTED (Hdr.Pe32->FileHeader.Machine) &&
+ Hdr.Pe32->OptionalHeader.Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ ReturnHandle = SimpleFileSystemHandles[Index];
+ break;
+ }
+ }
+ }
+
+ FreePool(DupDevicePath);
+
+ if (SimpleFileSystemHandles != NULL) {
+ FreePool(SimpleFileSystemHandles);
+ }
+
+ gBS->RestoreTPL (OldTpl);
+
+ return ReturnHandle;
+}
+
+/**
+ Check to see if the network cable is plugged in. If the DevicePath is not
+ connected it will be connected.
+
+ @param DevicePath Device Path to check
+
+ @retval TRUE DevicePath points to an Network that is connected
+ @retval FALSE DevicePath does not point to a bootable network
+
+**/
+BOOLEAN
+BdsLibNetworkBootWithMediaPresent (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *UpdatedDevicePath;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_NETWORK_PROTOCOL *Snp;
+ BOOLEAN MediaPresent;
+ UINT32 InterruptStatus;
+
+ MediaPresent = FALSE;
+
+ UpdatedDevicePath = DevicePath;
+ //
+ // Locate Load File Protocol for PXE boot option first
+ //
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ Status = BdsLibConnectDevicePath (DevicePath);
+ if (!EFI_ERROR (Status)) {
+ //
+ // This one should work after we did the connect
+ //
+ Status = gBS->LocateDevicePath (&gEfiLoadFileProtocolGuid, &UpdatedDevicePath, &Handle);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **)&Snp);
+ if (EFI_ERROR (Status)) {
+ //
+ // Failed to open SNP from this handle, try to get SNP from parent handle
+ //
+ UpdatedDevicePath = DevicePathFromHandle (Handle);
+ if (UpdatedDevicePath != NULL) {
+ Status = gBS->LocateDevicePath (&gEfiSimpleNetworkProtocolGuid, &UpdatedDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ //
+ // SNP handle found, get SNP from it
+ //
+ Status = gBS->HandleProtocol (Handle, &gEfiSimpleNetworkProtocolGuid, (VOID **) &Snp);
+ }
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (Snp->Mode->MediaPresentSupported) {
+ if (Snp->Mode->State == EfiSimpleNetworkInitialized) {
+ //
+ // Invoke Snp->GetStatus() to refresh the media status
+ //
+ Snp->GetStatus (Snp, &InterruptStatus, NULL);
+
+ //
+ // In case some one else is using the SNP check to see if it's connected
+ //
+ MediaPresent = Snp->Mode->MediaPresent;
+ } else {
+ //
+ // No one is using SNP so we need to Start and Initialize so
+ // MediaPresent will be valid.
+ //
+ Status = Snp->Start (Snp);
+ if (!EFI_ERROR (Status)) {
+ Status = Snp->Initialize (Snp, 0, 0);
+ if (!EFI_ERROR (Status)) {
+ MediaPresent = Snp->Mode->MediaPresent;
+ Snp->Shutdown (Snp);
+ }
+ Snp->Stop (Snp);
+ }
+ }
+ } else {
+ MediaPresent = TRUE;
+ }
+ }
+ }
+
+ return MediaPresent;
+}
+
+/**
+ For a bootable Device path, return its boot type.
+
+ @param DevicePath The bootable device Path to check
+
+ @retval BDS_EFI_MEDIA_HD_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
+ which subtype is MEDIA_HARDDRIVE_DP
+ @retval BDS_EFI_MEDIA_CDROM_BOOT If given device path contains MEDIA_DEVICE_PATH type device path node
+ which subtype is MEDIA_CDROM_DP
+ @retval BDS_EFI_ACPI_FLOPPY_BOOT If given device path contains ACPI_DEVICE_PATH type device path node
+ which HID is floppy device.
+ @retval BDS_EFI_MESSAGE_ATAPI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_ATAPI_DP.
+ @retval BDS_EFI_MESSAGE_SCSI_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_SCSI_DP.
+ @retval BDS_EFI_MESSAGE_USB_DEVICE_BOOT If given device path contains MESSAGING_DEVICE_PATH type device path node
+ and its last device path node's subtype is MSG_USB_DP.
+ @retval BDS_EFI_MESSAGE_MISC_BOOT If the device path not contains any media device path node, and
+ its last device path node point to a message device path node.
+ @retval BDS_LEGACY_BBS_BOOT If given device path contains BBS_DEVICE_PATH type device path node.
+ @retval BDS_EFI_UNSUPPORT An EFI Removable BlockIO device path not point to a media and message device,
+
+**/
+UINT32
+EFIAPI
+BdsGetBootTypeFromDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ UINT32 BootType;
+
+ if (NULL == DevicePath) {
+ return BDS_EFI_UNSUPPORT;
+ }
+
+ TempDevicePath = DevicePath;
+
+ while (!IsDevicePathEndType (TempDevicePath)) {
+ switch (DevicePathType (TempDevicePath)) {
+ case BBS_DEVICE_PATH:
+ return BDS_LEGACY_BBS_BOOT;
+ case MEDIA_DEVICE_PATH:
+ if (DevicePathSubType (TempDevicePath) == MEDIA_HARDDRIVE_DP) {
+ return BDS_EFI_MEDIA_HD_BOOT;
+ } else if (DevicePathSubType (TempDevicePath) == MEDIA_CDROM_DP) {
+ return BDS_EFI_MEDIA_CDROM_BOOT;
+ }
+ break;
+ case ACPI_DEVICE_PATH:
+ Acpi = (ACPI_HID_DEVICE_PATH *) TempDevicePath;
+ if (EISA_ID_TO_NUM (Acpi->HID) == 0x0604) {
+ return BDS_EFI_ACPI_FLOPPY_BOOT;
+ }
+ break;
+ case MESSAGING_DEVICE_PATH:
+ //
+ // Get the last device path node
+ //
+ LastDeviceNode = NextDevicePathNode (TempDevicePath);
+ if (DevicePathSubType(LastDeviceNode) == MSG_DEVICE_LOGICAL_UNIT_DP) {
+ //
+ // if the next node type is Device Logical Unit, which specify the Logical Unit Number (LUN),
+ // skip it
+ //
+ LastDeviceNode = NextDevicePathNode (LastDeviceNode);
+ }
+ //
+ // if the device path not only point to driver device, it is not a messaging device path,
+ //
+ if (!IsDevicePathEndType (LastDeviceNode)) {
+ break;
+ }
+
+ switch (DevicePathSubType (TempDevicePath)) {
+ case MSG_ATAPI_DP:
+ BootType = BDS_EFI_MESSAGE_ATAPI_BOOT;
+ break;
+
+ case MSG_USB_DP:
+ BootType = BDS_EFI_MESSAGE_USB_DEVICE_BOOT;
+ break;
+
+ case MSG_SCSI_DP:
+ BootType = BDS_EFI_MESSAGE_SCSI_BOOT;
+ break;
+
+ case MSG_SATA_DP:
+ BootType = BDS_EFI_MESSAGE_SATA_BOOT;
+ break;
+
+ case MSG_MAC_ADDR_DP:
+ case MSG_VLAN_DP:
+ case MSG_IPv4_DP:
+ case MSG_IPv6_DP:
+ BootType = BDS_EFI_MESSAGE_MAC_BOOT;
+ break;
+
+ default:
+ BootType = BDS_EFI_MESSAGE_MISC_BOOT;
+ break;
+ }
+ return BootType;
+
+ default:
+ break;
+ }
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+
+ return BDS_EFI_UNSUPPORT;
+}
+
+/**
+ Check whether the Device path in a boot option point to a valid bootable device,
+ And if CheckMedia is true, check the device is ready to boot now.
+
+ @param DevPath the Device path in a boot option
+ @param CheckMedia if true, check the device is ready to boot now.
+
+ @retval TRUE the Device path is valid
+ @retval FALSE the Device path is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia
+ )
+{
+ return BdsLibIsValidEFIBootOptDevicePathExt (DevPath, CheckMedia, NULL);
+}
+
+/**
+ Check whether the Device path in a boot option point to a valid bootable device,
+ And if CheckMedia is true, check the device is ready to boot now.
+ If Description is not NULL and the device path point to a fixed BlockIo
+ device, check the description whether conflict with other auto-created
+ boot options.
+
+ @param DevPath the Device path in a boot option
+ @param CheckMedia if true, check the device is ready to boot now.
+ @param Description the description in a boot option
+
+ @retval TRUE the Device path is valid
+ @retval FALSE the Device path is invalid .
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibIsValidEFIBootOptDevicePathExt (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath,
+ IN BOOLEAN CheckMedia,
+ IN CHAR16 *Description
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_BLOCK_IO_PROTOCOL *BlockIo;
+
+ TempDevicePath = DevPath;
+ LastDeviceNode = DevPath;
+
+ //
+ // Check if it's a valid boot option for network boot device.
+ // Check if there is EfiLoadFileProtocol installed.
+ // If yes, that means there is a boot option for network.
+ //
+ Status = gBS->LocateDevicePath (
+ &gEfiLoadFileProtocolGuid,
+ &TempDevicePath,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ TempDevicePath = DevPath;
+ BdsLibConnectDevicePath (TempDevicePath);
+ Status = gBS->LocateDevicePath (
+ &gEfiLoadFileProtocolGuid,
+ &TempDevicePath,
+ &Handle
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ if (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // LoadFile protocol is not installed on handle with exactly the same DevPath
+ //
+ return FALSE;
+ }
+
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibNetworkBootWithMediaPresent(DevPath)) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+
+ //
+ // If the boot option point to a file, it is a valid EFI boot option,
+ // and assume it is ready to boot now
+ //
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ //
+ // If there is USB Class or USB WWID device path node, treat it as valid EFI
+ // Boot Option. BdsExpandUsbShortFormDevicePath () will be used to expand it
+ // to full device path.
+ //
+ if ((DevicePathType (TempDevicePath) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (TempDevicePath) == MSG_USB_CLASS_DP) ||
+ (DevicePathSubType (TempDevicePath) == MSG_USB_WWID_DP))) {
+ return TRUE;
+ }
+
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ if ((DevicePathType (LastDeviceNode) == MEDIA_DEVICE_PATH) &&
+ (DevicePathSubType (LastDeviceNode) == MEDIA_FILEPATH_DP)) {
+ return TRUE;
+ }
+
+ //
+ // Check if it's a valid boot option for internal FV application
+ //
+ if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode) != NULL) {
+ //
+ // If the boot option point to internal FV application, make sure it is valid
+ //
+ TempDevicePath = DevPath;
+ Status = BdsLibUpdateFvFileDevicePath (
+ &TempDevicePath,
+ EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode)
+ );
+ if (Status == EFI_ALREADY_STARTED) {
+ return TRUE;
+ } else {
+ if (Status == EFI_SUCCESS) {
+ FreePool (TempDevicePath);
+ }
+ return FALSE;
+ }
+ }
+
+ //
+ // If the boot option point to a blockIO device:
+ // if it is a removable blockIo device, it is valid.
+ // if it is a fixed blockIo device, check its description confliction.
+ //
+ TempDevicePath = DevPath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Device not present so see if we need to connect it
+ //
+ Status = BdsLibConnectDevicePath (DevPath);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Try again to get the Block Io protocol after we did the connect
+ //
+ TempDevicePath = DevPath;
+ Status = gBS->LocateDevicePath (&gEfiBlockIoProtocolGuid, &TempDevicePath, &Handle);
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (Handle, &gEfiBlockIoProtocolGuid, (VOID **)&BlockIo);
+ if (!EFI_ERROR (Status)) {
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibGetBootableHandle (DevPath) != NULL) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+ } else {
+ //
+ // if the boot option point to a simple file protocol which does not consume block Io protocol, it is also a valid EFI boot option,
+ //
+ Status = gBS->LocateDevicePath (&gEfiSimpleFileSystemProtocolGuid, &TempDevicePath, &Handle);
+ if (!EFI_ERROR (Status)) {
+ if (CheckMedia) {
+ //
+ // Test if it is ready to boot now
+ //
+ if (BdsLibGetBootableHandle (DevPath) != NULL) {
+ return TRUE;
+ }
+ } else {
+ return TRUE;
+ }
+ }
+ }
+
+ return FALSE;
+}
+
+
+/**
+ According to a file guild, check a Fv file device path is valid. If it is invalid,
+ try to return the valid device path.
+ FV address maybe changes for memory layout adjust from time to time, use this function
+ could promise the Fv file device path is right.
+
+ @param DevicePath on input, the Fv file device path need to check on
+ output, the updated valid Fv file device path
+ @param FileGuid the Fv file guild
+
+ @retval EFI_INVALID_PARAMETER the input DevicePath or FileGuid is invalid
+ parameter
+ @retval EFI_UNSUPPORTED the input DevicePath does not contain Fv file
+ guild at all
+ @retval EFI_ALREADY_STARTED the input DevicePath has pointed to Fv file, it is
+ valid
+ @retval EFI_SUCCESS has successfully updated the invalid DevicePath,
+ and return the updated device path in DevicePath
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateFvFileDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL ** DevicePath,
+ IN EFI_GUID *FileGuid
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *TempDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *LastDeviceNode;
+ EFI_STATUS Status;
+ EFI_GUID *GuidPoint;
+ UINTN Index;
+ UINTN FvHandleCount;
+ EFI_HANDLE *FvHandleBuffer;
+ EFI_FV_FILETYPE Type;
+ UINTN Size;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+ UINT32 AuthenticationStatus;
+ BOOLEAN FindFvFile;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImage;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH FvFileNode;
+ EFI_HANDLE FoundFvHandle;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+
+ if ((DevicePath == NULL) || (*DevicePath == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if (FileGuid == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check whether the device path point to the default the input Fv file
+ //
+ TempDevicePath = *DevicePath;
+ LastDeviceNode = TempDevicePath;
+ while (!IsDevicePathEnd (TempDevicePath)) {
+ LastDeviceNode = TempDevicePath;
+ TempDevicePath = NextDevicePathNode (TempDevicePath);
+ }
+ GuidPoint = EfiGetNameGuidFromFwVolDevicePathNode (
+ (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) LastDeviceNode
+ );
+ if (GuidPoint == NULL) {
+ //
+ // if this option does not points to a Fv file, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+ if (!CompareGuid (GuidPoint, FileGuid)) {
+ //
+ // If the Fv file is not the input file guid, just return EFI_UNSUPPORTED
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check whether the input Fv file device path is valid
+ //
+ TempDevicePath = *DevicePath;
+ FoundFvHandle = NULL;
+ Status = gBS->LocateDevicePath (
+ &gEfiFirmwareVolume2ProtocolGuid,
+ &TempDevicePath,
+ &FoundFvHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ FoundFvHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set FV ReadFile Buffer as NULL, only need to check whether input Fv file exist there
+ //
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ return EFI_ALREADY_STARTED;
+ }
+ }
+ }
+
+ //
+ // Look for the input wanted FV file in current FV
+ // First, try to look for in Bds own FV. Bds and input wanted FV file usually are in the same FV
+ //
+ FindFvFile = FALSE;
+ FoundFvHandle = NULL;
+ Status = gBS->HandleProtocol (
+ gImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &LoadedImage
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = gBS->HandleProtocol (
+ LoadedImage->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ FindFvFile = TRUE;
+ FoundFvHandle = LoadedImage->DeviceHandle;
+ }
+ }
+ }
+ //
+ // Second, if fail to find, try to enumerate all FV
+ //
+ if (!FindFvFile) {
+ FvHandleBuffer = NULL;
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ NULL,
+ &FvHandleCount,
+ &FvHandleBuffer
+ );
+ for (Index = 0; Index < FvHandleCount; Index++) {
+ gBS->HandleProtocol (
+ FvHandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+
+ Status = Fv->ReadFile (
+ Fv,
+ FileGuid,
+ NULL,
+ &Size,
+ &Type,
+ &Attributes,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Skip if input Fv file not in the FV
+ //
+ continue;
+ }
+ FindFvFile = TRUE;
+ FoundFvHandle = FvHandleBuffer[Index];
+ break;
+ }
+
+ if (FvHandleBuffer != NULL) {
+ FreePool (FvHandleBuffer);
+ }
+ }
+
+ if (FindFvFile) {
+ //
+ // Build the shell device path
+ //
+ NewDevicePath = DevicePathFromHandle (FoundFvHandle);
+ EfiInitializeFwVolDevicepathNode (&FvFileNode, FileGuid);
+ NewDevicePath = AppendDevicePathNode (NewDevicePath, (EFI_DEVICE_PATH_PROTOCOL *) &FvFileNode);
+ ASSERT (NewDevicePath != NULL);
+ *DevicePath = NewDevicePath;
+ return EFI_SUCCESS;
+ }
+ return EFI_NOT_FOUND;
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c
new file mode 100644
index 0000000000..f487aa611a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConnect.c
@@ -0,0 +1,435 @@
+/** @file
+ BDS Lib functions which relate with connect the device
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+
+/**
+ This function will connect all the system driver to controller
+ first, and then special connect the default console, this make
+ sure all the system controller available and the platform default
+ console connected.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAll (
+ VOID
+ )
+{
+ //
+ // Connect the platform console first
+ //
+ BdsLibConnectAllDefaultConsoles ();
+
+ //
+ // Generic way to connect all the drivers
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+
+ //
+ // Here we have the assumption that we have already had
+ // platform default console
+ //
+ BdsLibConnectAllDefaultConsoles ();
+}
+
+
+/**
+ This function will connect all the system drivers to all controllers
+ first, and then connect all the console devices the system current
+ have. After this we should get all the device work and console available
+ if the system have console device.
+
+**/
+VOID
+BdsLibGenericConnectAll (
+ VOID
+ )
+{
+ //
+ // Most generic way to connect all the drivers
+ //
+ BdsLibConnectAllDriversToAllControllers ();
+ BdsLibConnectAllConsoles ();
+}
+
+/**
+ This function will create all handles associate with every device
+ path node. If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible.
+
+ @param DevicePathToConnect The device path which will be connected, it can be
+ a multi-instance device path
+
+ @retval EFI_SUCCESS All handles associate with every device path node
+ have been created
+ @retval EFI_OUT_OF_RESOURCES There is no resource to create new handles
+ @retval EFI_NOT_FOUND Create the handle associate with one device path
+ node failed
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePathToConnect
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_HANDLE Handle;
+ EFI_HANDLE PreviousHandle;
+ UINTN Size;
+ EFI_TPL CurrentTpl;
+
+ if (DevicePathToConnect == NULL) {
+ return EFI_SUCCESS;
+ }
+
+ CurrentTpl = EfiGetCurrentTpl ();
+
+ DevicePath = DuplicateDevicePath (DevicePathToConnect);
+ if (DevicePath == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyOfDevicePath = DevicePath;
+
+ do {
+ //
+ // The outer loop handles multi instance device paths.
+ // Only console variables contain multiple instance device paths.
+ //
+ // After this call DevicePath points to the next Instance
+ //
+ Instance = GetNextDevicePathInstance (&DevicePath, &Size);
+ if (Instance == NULL) {
+ FreePool (CopyOfDevicePath);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+
+ //
+ // Start the real work of connect with RemainingDevicePath
+ //
+ PreviousHandle = NULL;
+ do {
+ //
+ // Find the handle that best matches the Device Path. If it is only a
+ // partial match the remaining part of the device path is returned in
+ // RemainingDevicePath.
+ //
+ RemainingDevicePath = Instance;
+ Status = gBS->LocateDevicePath (&gEfiDevicePathProtocolGuid, &RemainingDevicePath, &Handle);
+
+ if (!EFI_ERROR (Status)) {
+ if (Handle == PreviousHandle) {
+ //
+ // If no forward progress is made try invoking the Dispatcher.
+ // A new FV may have been added to the system an new drivers
+ // may now be found.
+ // Status == EFI_SUCCESS means a driver was dispatched
+ // Status == EFI_NOT_FOUND means no new drivers were dispatched
+ //
+ if (CurrentTpl == TPL_APPLICATION) {
+ //
+ // Dispatch calls LoadImage/StartImage which cannot run at TPL > TPL_APPLICATION
+ //
+ Status = gDS->Dispatch ();
+ } else {
+ //
+ // Always return EFI_NOT_FOUND here
+ // to prevent dead loop when control handle is found but connection failded case
+ //
+ Status = EFI_NOT_FOUND;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ PreviousHandle = Handle;
+ //
+ // Connect all drivers that apply to Handle and RemainingDevicePath,
+ // the Recursive flag is FALSE so only one level will be expanded.
+ //
+ // Do not check the connect status here, if the connect controller fail,
+ // then still give the chance to do dispatch, because partial
+ // RemainingDevicepath may be in the new FV
+ //
+ // 1. If the connect fail, RemainingDevicepath and handle will not
+ // change, so next time will do the dispatch, then dispatch's status
+ // will take effect
+ // 2. If the connect success, the RemainingDevicepath and handle will
+ // change, then avoid the dispatch, we have chance to continue the
+ // next connection
+ //
+ gBS->ConnectController (Handle, NULL, RemainingDevicePath, FALSE);
+ }
+ }
+ //
+ // Loop until RemainingDevicePath is an empty device path
+ //
+ } while (!EFI_ERROR (Status) && !IsDevicePathEnd (RemainingDevicePath));
+
+ } while (DevicePath != NULL);
+
+ if (CopyOfDevicePath != NULL) {
+ FreePool (CopyOfDevicePath);
+ }
+ //
+ // All handle with DevicePath exists in the handle database
+ //
+ return Status;
+}
+
+/**
+ This function will connect all current system handles recursively.
+
+ gBS->ConnectController() service is invoked for each handle exist in system handler buffer.
+ If the handle is bus type handler, all childrens also will be connected recursively
+ by gBS->ConnectController().
+
+ @retval EFI_SUCCESS All handles and it's child handle have been connected
+ @retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllEfi (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will disconnect all current system handles.
+
+ gBS->DisconnectController() is invoked for each handle exists in system handle buffer.
+ If handle is a bus type handle, all childrens also are disconnected recursively by
+ gBS->DisconnectController().
+
+ @retval EFI_SUCCESS All handles have been disconnected
+ @retval EFI_STATUS Error status returned by of gBS->LocateHandleBuffer().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibDisconnectAllEfi (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN Index;
+
+ //
+ // Disconnect all
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ Status = gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Connects all drivers to all controllers.
+ This function make sure all the current system driver will manage
+ the correspoinding controllers if have. And at the same time, make
+ sure all the system controllers have driver to manage it if have.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllDriversToAllControllers (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ do {
+ //
+ // Connect All EFI 1.10 drivers following EFI 1.10 algorithm
+ //
+ BdsLibConnectAllEfi ();
+
+ //
+ // Check to see if it's possible to dispatch an more DXE drivers.
+ // The BdsLibConnectAllEfi () may have made new DXE drivers show up.
+ // If anything is Dispatched Status == EFI_SUCCESS and we will try
+ // the connect again.
+ //
+ Status = gDS->Dispatch ();
+
+ } while (!EFI_ERROR (Status));
+
+}
+
+
+/**
+ Connect the specific Usb device which match the short form device path,
+ and whose bus is determined by Host Controller (Uhci or Ehci).
+
+ @param HostControllerPI Uhci (0x00) or Ehci (0x20) or Both uhci and ehci
+ (0xFF)
+ @param RemainingDevicePath a short-form device path that starts with the first
+ element being a USB WWID or a USB Class device
+ path
+
+ @return EFI_INVALID_PARAMETER RemainingDevicePath is NULL pointer.
+ RemainingDevicePath is not a USB device path.
+ Invalid HostControllerPI type.
+ @return EFI_SUCCESS Success to connect USB device
+ @return EFI_NOT_FOUND Fail to find handle for USB controller to connect.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectUsbDevByShortFormDP(
+ IN UINT8 HostControllerPI,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleArray;
+ UINTN HandleArrayCount;
+ UINTN Index;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ UINT8 Class[3];
+ BOOLEAN AtLeastOneConnected;
+
+ //
+ // Check the passed in parameters
+ //
+ if (RemainingDevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((DevicePathType (RemainingDevicePath) != MESSAGING_DEVICE_PATH) ||
+ ((DevicePathSubType (RemainingDevicePath) != MSG_USB_CLASS_DP)
+ && (DevicePathSubType (RemainingDevicePath) != MSG_USB_WWID_DP)
+ )) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (HostControllerPI != 0xFF &&
+ HostControllerPI != 0x00 &&
+ HostControllerPI != 0x20) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Find the usb host controller firstly, then connect with the remaining device path
+ //
+ AtLeastOneConnected = FALSE;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleArrayCount,
+ &HandleArray
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleArrayCount; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleArray[Index],
+ &gEfiPciIoProtocolGuid,
+ (VOID **)&PciIo
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Check whether the Pci device is the wanted usb host controller
+ //
+ Status = PciIo->Pci.Read (PciIo, EfiPciIoWidthUint8, 0x09, 3, &Class);
+ if (!EFI_ERROR (Status)) {
+ if ((PCI_CLASS_SERIAL == Class[2]) &&
+ (PCI_CLASS_SERIAL_USB == Class[1])) {
+ if (HostControllerPI == Class[0] || HostControllerPI == 0xFF) {
+ Status = gBS->ConnectController (
+ HandleArray[Index],
+ NULL,
+ RemainingDevicePath,
+ FALSE
+ );
+ if (!EFI_ERROR(Status)) {
+ AtLeastOneConnected = TRUE;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ if (HandleArray != NULL) {
+ FreePool (HandleArray);
+ }
+
+ if (AtLeastOneConnected) {
+ return EFI_SUCCESS;
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
new file mode 100644
index 0000000000..eefec0642a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsConsole.c
@@ -0,0 +1,1301 @@
+/** @file
+ BDS Lib functions which contain all the code to connect console device
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+#include <IndustryStandard/Bmp.h>
+
+
+/**
+ Check if we need to save the EFI variable with "ConVarName" as name
+ as NV type
+ If ConVarName is NULL, then ASSERT().
+
+ @param ConVarName The name of the EFI variable.
+
+ @retval TRUE Set the EFI variable as NV type.
+ @retval FALSE EFI variable as NV type can be set NonNV.
+**/
+BOOLEAN
+IsNvNeed (
+ IN CHAR16 *ConVarName
+ )
+{
+ CHAR16 *Ptr;
+
+ ASSERT (ConVarName != NULL);
+
+ Ptr = ConVarName;
+
+ //
+ // If the variable includes "Dev" at last, we consider
+ // it does not support NV attribute.
+ //
+ while (*Ptr != L'\0') {
+ Ptr++;
+ }
+
+ if (((INTN)((UINTN)Ptr - (UINTN)ConVarName) / sizeof (CHAR16)) <= 3) {
+ return TRUE;
+ }
+
+ if ((*(Ptr - 3) == 'D') && (*(Ptr - 2) == 'e') && (*(Ptr - 1) == 'v')) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+}
+
+/**
+ Fill console handle in System Table if there are no valid console handle in.
+
+ Firstly, check the validation of console handle in System Table. If it is invalid,
+ update it by the first console device handle from EFI console variable.
+
+ @param VarName The name of the EFI console variable.
+ @param ConsoleGuid Specified Console protocol GUID.
+ @param ConsoleHandle On IN, console handle in System Table to be checked.
+ On OUT, new console handle in system table.
+ @param ProtocolInterface On IN, console protocol on console handle in System Table to be checked.
+ On OUT, new console protocol on new console handle in system table.
+
+ @retval TRUE System Table has been updated.
+ @retval FALSE System Table hasn't been updated.
+
+**/
+BOOLEAN
+UpdateSystemTableConsole (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *ConsoleGuid,
+ IN OUT EFI_HANDLE *ConsoleHandle,
+ IN OUT VOID **ProtocolInterface
+ )
+{
+ EFI_STATUS Status;
+ UINTN DevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *FullDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ VOID *Interface;
+ EFI_HANDLE NewHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *TextOut;
+
+ ASSERT (VarName != NULL);
+ ASSERT (ConsoleHandle != NULL);
+ ASSERT (ConsoleGuid != NULL);
+ ASSERT (ProtocolInterface != NULL);
+
+ if (*ConsoleHandle != NULL) {
+ Status = gBS->HandleProtocol (
+ *ConsoleHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (Status == EFI_SUCCESS && Interface == *ProtocolInterface) {
+ //
+ // If ConsoleHandle is valid and console protocol on this handle also
+ // also matched, just return.
+ //
+ return FALSE;
+ }
+ }
+
+ //
+ // Get all possible consoles device path from EFI variable
+ //
+ VarConsole = BdsLibGetVariableAndSize (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ &DevicePathSize
+ );
+ if (VarConsole == NULL) {
+ //
+ // If there is no any console device, just return.
+ //
+ return FALSE;
+ }
+
+ FullDevicePath = VarConsole;
+
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&VarConsole, &DevicePathSize);
+ if (Instance == NULL) {
+ FreePool (FullDevicePath);
+ ASSERT (FALSE);
+ }
+
+ //
+ // Find console device handle by device path instance
+ //
+ Status = gBS->LocateDevicePath (
+ ConsoleGuid,
+ &Instance,
+ &NewHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Get the console protocol on this console device handle
+ //
+ Status = gBS->HandleProtocol (
+ NewHandle,
+ ConsoleGuid,
+ &Interface
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Update new console handle in System Table.
+ //
+ *ConsoleHandle = NewHandle;
+ *ProtocolInterface = Interface;
+ if (CompareGuid (ConsoleGuid, &gEfiSimpleTextOutProtocolGuid)) {
+ //
+ // If it is console out device, set console mode 80x25 if current mode is invalid.
+ //
+ TextOut = (EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *) Interface;
+ if (TextOut->Mode->Mode == -1) {
+ TextOut->SetMode (TextOut, 0);
+ }
+ }
+ return TRUE;
+ }
+ }
+
+ } while (Instance != NULL);
+
+ //
+ // No any available console devcie found.
+ //
+ return FALSE;
+}
+
+/**
+ This function update console variable based on ConVarName, it can
+ add or remove one specific console device path from the variable
+
+ @param ConVarName Console related variable name, ConIn, ConOut,
+ ErrOut.
+ @param CustomizedConDevicePath The console device path which will be added to
+ the console variable ConVarName, this parameter
+ can not be multi-instance.
+ @param ExclusiveDevicePath The console device path which will be removed
+ from the console variable ConVarName, this
+ parameter can not be multi-instance.
+
+ @retval EFI_UNSUPPORTED The added device path is same to the removed one.
+ @retval EFI_SUCCESS Success add or remove the device path from the
+ console variable.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUpdateConsoleVariable (
+ IN CHAR16 *ConVarName,
+ IN EFI_DEVICE_PATH_PROTOCOL *CustomizedConDevicePath,
+ IN EFI_DEVICE_PATH_PROTOCOL *ExclusiveDevicePath
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *VarConsole;
+ UINTN DevicePathSize;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINT32 Attributes;
+
+ VarConsole = NULL;
+ DevicePathSize = 0;
+
+ //
+ // Notes: check the device path point, here should check
+ // with compare memory
+ //
+ if (CustomizedConDevicePath == ExclusiveDevicePath) {
+ return EFI_UNSUPPORTED;
+ }
+ //
+ // Delete the ExclusiveDevicePath from current default console
+ //
+ VarConsole = BdsLibGetVariableAndSize (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ &DevicePathSize
+ );
+
+ //
+ // Initialize NewDevicePath
+ //
+ NewDevicePath = VarConsole;
+
+ //
+ // If ExclusiveDevicePath is even the part of the instance in VarConsole, delete it.
+ // In the end, NewDevicePath is the final device path.
+ //
+ if (ExclusiveDevicePath != NULL && VarConsole != NULL) {
+ NewDevicePath = BdsLibDelPartMatchInstance (VarConsole, ExclusiveDevicePath);
+ }
+ //
+ // Try to append customized device path to NewDevicePath.
+ //
+ if (CustomizedConDevicePath != NULL) {
+ if (!BdsLibMatchDevicePaths (NewDevicePath, CustomizedConDevicePath)) {
+ //
+ // Check if there is part of CustomizedConDevicePath in NewDevicePath, delete it.
+ //
+ NewDevicePath = BdsLibDelPartMatchInstance (NewDevicePath, CustomizedConDevicePath);
+ //
+ // In the first check, the default console variable will be _ModuleEntryPoint,
+ // just append current customized device path
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, CustomizedConDevicePath);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ }
+
+ //
+ // The attribute for ConInDev, ConOutDev and ErrOutDev does not include NV.
+ //
+ if (IsNvNeed(ConVarName)) {
+ //
+ // ConVarName has NV attribute.
+ //
+ Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE;
+ } else {
+ //
+ // ConVarName does not have NV attribute.
+ //
+ Attributes = EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS;
+ }
+
+ //
+ // Finally, Update the variable of the default console by NewDevicePath
+ //
+ DevicePathSize = GetDevicePathSize (NewDevicePath);
+ Status = SetVariableAndReportStatusCodeOnError (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ Attributes,
+ DevicePathSize,
+ NewDevicePath
+ );
+ if ((DevicePathSize == 0) && (Status == EFI_NOT_FOUND)) {
+ Status = EFI_SUCCESS;
+ }
+
+ if (VarConsole == NewDevicePath) {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ } else {
+ if (VarConsole != NULL) {
+ FreePool(VarConsole);
+ }
+ if (NewDevicePath != NULL) {
+ FreePool(NewDevicePath);
+ }
+ }
+
+ return Status;
+
+}
+
+
+/**
+ Connect the console device base on the variable ConVarName, if
+ device path of the ConVarName is multi-instance device path and
+ anyone of the instances is connected success, then this function
+ will return success.
+ If the handle associate with one device path node can not
+ be created successfully, then still give chance to do the dispatch,
+ which load the missing drivers if possible..
+
+ @param ConVarName Console related variable name, ConIn, ConOut,
+ ErrOut.
+
+ @retval EFI_NOT_FOUND There is not any console devices connected
+ success
+ @retval EFI_SUCCESS Success connect any one instance of the console
+ device path base on the variable ConVarName.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectConsoleVariable (
+ IN CHAR16 *ConVarName
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *StartDevicePath;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *Next;
+ EFI_DEVICE_PATH_PROTOCOL *CopyOfDevicePath;
+ UINTN Size;
+ BOOLEAN DeviceExist;
+
+ Status = EFI_SUCCESS;
+ DeviceExist = FALSE;
+
+ //
+ // Check if the console variable exist
+ //
+ StartDevicePath = BdsLibGetVariableAndSize (
+ ConVarName,
+ &gEfiGlobalVariableGuid,
+ &VariableSize
+ );
+ if (StartDevicePath == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CopyOfDevicePath = StartDevicePath;
+ do {
+ //
+ // Check every instance of the console variable
+ //
+ Instance = GetNextDevicePathInstance (&CopyOfDevicePath, &Size);
+ if (Instance == NULL) {
+ FreePool (StartDevicePath);
+ return EFI_UNSUPPORTED;
+ }
+
+ Next = Instance;
+ while (!IsDevicePathEndType (Next)) {
+ Next = NextDevicePathNode (Next);
+ }
+
+ SetDevicePathEndNode (Next);
+ //
+ // Connect the USB console
+ // USB console device path is a short-form device path that
+ // starts with the first element being a USB WWID
+ // or a USB Class device path
+ //
+ if ((DevicePathType (Instance) == MESSAGING_DEVICE_PATH) &&
+ ((DevicePathSubType (Instance) == MSG_USB_CLASS_DP)
+ || (DevicePathSubType (Instance) == MSG_USB_WWID_DP)
+ )) {
+ Status = BdsLibConnectUsbDevByShortFormDP (0xFF, Instance);
+ if (!EFI_ERROR (Status)) {
+ DeviceExist = TRUE;
+ }
+ } else {
+ //
+ // Connect the instance device path
+ //
+ Status = BdsLibConnectDevicePath (Instance);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Delete the instance from the console varialbe
+ //
+ BdsLibUpdateConsoleVariable (ConVarName, NULL, Instance);
+ } else {
+ DeviceExist = TRUE;
+ }
+ }
+ FreePool(Instance);
+ } while (CopyOfDevicePath != NULL);
+
+ FreePool (StartDevicePath);
+
+ if (!DeviceExist) {
+ return EFI_NOT_FOUND;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function will search every simpletext device in current system,
+ and make every simpletext device as pertantial console device.
+
+**/
+VOID
+EFIAPI
+BdsLibConnectAllConsoles (
+ VOID
+ )
+{
+ UINTN Index;
+ EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+
+ Index = 0;
+ HandleCount = 0;
+ HandleBuffer = NULL;
+ ConDevicePath = NULL;
+
+ //
+ // Update all the console variables
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextInProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ BdsLibUpdateConsoleVariable (L"ConIn", ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ConDevicePath
+ );
+ BdsLibUpdateConsoleVariable (L"ConOut", ConDevicePath, NULL);
+ BdsLibUpdateConsoleVariable (L"ErrOut", ConDevicePath, NULL);
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool(HandleBuffer);
+ }
+
+ //
+ // Connect all console variables
+ //
+ BdsLibConnectAllDefaultConsoles ();
+
+}
+
+/**
+ This function will connect console device base on the console
+ device variable ConIn, ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConIn and ConOut device have
+ been connected success.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsoles (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SystemTableUpdated;
+
+ //
+ // Connect all default console variables
+ //
+
+ //
+ // It seems impossible not to have any ConOut device on platform,
+ // so we check the status here.
+ //
+ Status = BdsLibConnectConsoleVariable (L"ConOut");
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert the performance probe for Console Out
+ //
+ PERF_START (NULL, "ConOut", "BDS", 1);
+ PERF_END (NULL, "ConOut", "BDS", 0);
+
+ //
+ // Because possibly the platform is legacy free, in such case,
+ // ConIn devices (Serial Port and PS2 Keyboard ) does not exist,
+ // so we need not check the status.
+ //
+ BdsLibConnectConsoleVariable (L"ConIn");
+
+ //
+ // The _ModuleEntryPoint err out var is legal.
+ //
+ BdsLibConnectConsoleVariable (L"ErrOut");
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (UpdateSystemTableConsole (L"ConIn", &gEfiSimpleTextInProtocolGuid, &gST->ConsoleInHandle, (VOID **) &gST->ConIn)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+ SystemTableUpdated = TRUE;
+ }
+
+ if (SystemTableUpdated) {
+ //
+ // Update the CRC32 in the EFI System Table header
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 (
+ (UINT8 *) &gST->Hdr,
+ gST->Hdr.HeaderSize,
+ &gST->Hdr.CRC32
+ );
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This function will connect console device except ConIn base on the console
+ device variable ConOut and ErrOut.
+
+ @retval EFI_SUCCESS At least one of the ConOut device have
+ been connected success.
+ @retval EFI_STATUS Return the status of BdsLibConnectConsoleVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibConnectAllDefaultConsolesWithOutConIn (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN SystemTableUpdated;
+
+ //
+ // Connect all default console variables except ConIn
+ //
+
+ //
+ // It seems impossible not to have any ConOut device on platform,
+ // so we check the status here.
+ //
+ Status = BdsLibConnectConsoleVariable (L"ConOut");
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Insert the performance probe for Console Out
+ //
+ PERF_START (NULL, "ConOut", "BDS", 1);
+ PERF_END (NULL, "ConOut", "BDS", 0);
+
+ //
+ // The _ModuleEntryPoint err out var is legal.
+ //
+ BdsLibConnectConsoleVariable (L"ErrOut");
+
+ SystemTableUpdated = FALSE;
+ //
+ // Fill console handles in System Table if no console device assignd.
+ //
+ if (UpdateSystemTableConsole (L"ConOut", &gEfiSimpleTextOutProtocolGuid, &gST->ConsoleOutHandle, (VOID **) &gST->ConOut)) {
+ SystemTableUpdated = TRUE;
+ }
+ if (UpdateSystemTableConsole (L"ErrOut", &gEfiSimpleTextOutProtocolGuid, &gST->StandardErrorHandle, (VOID **) &gST->StdErr)) {
+ SystemTableUpdated = TRUE;
+ }
+
+ if (SystemTableUpdated) {
+ //
+ // Update the CRC32 in the EFI System Table header
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 (
+ (UINT8 *) &gST->Hdr,
+ gST->Hdr.HeaderSize,
+ &gST->Hdr.CRC32
+ );
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Convert a *.BMP graphics image to a GOP blt buffer. If a NULL Blt buffer
+ is passed in a GopBlt buffer will be allocated by this routine. If a GopBlt
+ buffer is passed in it will be used if it is big enough.
+
+ @param BmpImage Pointer to BMP file
+ @param BmpImageSize Number of bytes in BmpImage
+ @param GopBlt Buffer containing GOP version of BmpImage.
+ @param GopBltSize Size of GopBlt in bytes.
+ @param PixelHeight Height of GopBlt/BmpImage in pixels
+ @param PixelWidth Width of GopBlt/BmpImage in pixels
+
+ @retval EFI_SUCCESS GopBlt and GopBltSize are returned.
+ @retval EFI_UNSUPPORTED BmpImage is not a valid *.BMP image
+ @retval EFI_BUFFER_TOO_SMALL The passed in GopBlt buffer is not big enough.
+ GopBltSize will contain the required size.
+ @retval EFI_OUT_OF_RESOURCES No enough buffer to allocate.
+
+**/
+EFI_STATUS
+ConvertBmpToGopBlt (
+ IN VOID *BmpImage,
+ IN UINTN BmpImageSize,
+ IN OUT VOID **GopBlt,
+ IN OUT UINTN *GopBltSize,
+ OUT UINTN *PixelHeight,
+ OUT UINTN *PixelWidth
+ )
+{
+ UINT8 *Image;
+ UINT8 *ImageHeader;
+ BMP_IMAGE_HEADER *BmpHeader;
+ BMP_COLOR_MAP *BmpColorMap;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *BltBuffer;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ UINT64 BltBufferSize;
+ UINTN Index;
+ UINTN Height;
+ UINTN Width;
+ UINTN ImageIndex;
+ UINT32 DataSizePerLine;
+ BOOLEAN IsAllocated;
+ UINT32 ColorMapNum;
+
+ if (sizeof (BMP_IMAGE_HEADER) > BmpImageSize) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ BmpHeader = (BMP_IMAGE_HEADER *) BmpImage;
+
+ if (BmpHeader->CharB != 'B' || BmpHeader->CharM != 'M') {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Doesn't support compress.
+ //
+ if (BmpHeader->CompressionType != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Only support BITMAPINFOHEADER format.
+ // BITMAPFILEHEADER + BITMAPINFOHEADER = BMP_IMAGE_HEADER
+ //
+ if (BmpHeader->HeaderSize != sizeof (BMP_IMAGE_HEADER) - OFFSET_OF(BMP_IMAGE_HEADER, HeaderSize)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // The data size in each line must be 4 byte alignment.
+ //
+ DataSizePerLine = ((BmpHeader->PixelWidth * BmpHeader->BitPerPixel + 31) >> 3) & (~0x3);
+ BltBufferSize = MultU64x32 (DataSizePerLine, BmpHeader->PixelHeight);
+ if (BltBufferSize > (UINT32) ~0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((BmpHeader->Size != BmpImageSize) ||
+ (BmpHeader->Size < BmpHeader->ImageOffset) ||
+ (BmpHeader->Size - BmpHeader->ImageOffset != BmpHeader->PixelHeight * DataSizePerLine)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Calculate Color Map offset in the image.
+ //
+ Image = BmpImage;
+ BmpColorMap = (BMP_COLOR_MAP *) (Image + sizeof (BMP_IMAGE_HEADER));
+ if (BmpHeader->ImageOffset < sizeof (BMP_IMAGE_HEADER)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (BmpHeader->ImageOffset > sizeof (BMP_IMAGE_HEADER)) {
+ switch (BmpHeader->BitPerPixel) {
+ case 1:
+ ColorMapNum = 2;
+ break;
+ case 4:
+ ColorMapNum = 16;
+ break;
+ case 8:
+ ColorMapNum = 256;
+ break;
+ default:
+ ColorMapNum = 0;
+ break;
+ }
+ //
+ // BMP file may has padding data between the bmp header section and the bmp data section.
+ //
+ if (BmpHeader->ImageOffset - sizeof (BMP_IMAGE_HEADER) < sizeof (BMP_COLOR_MAP) * ColorMapNum) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ //
+ // Calculate graphics image data address in the image
+ //
+ Image = ((UINT8 *) BmpImage) + BmpHeader->ImageOffset;
+ ImageHeader = Image;
+
+ //
+ // Calculate the BltBuffer needed size.
+ //
+ BltBufferSize = MultU64x32 ((UINT64) BmpHeader->PixelWidth, BmpHeader->PixelHeight);
+ //
+ // Ensure the BltBufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (BltBufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+ return EFI_UNSUPPORTED;
+ }
+ BltBufferSize = MultU64x32 (BltBufferSize, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+
+ IsAllocated = FALSE;
+ if (*GopBlt == NULL) {
+ //
+ // GopBlt is not allocated by caller.
+ //
+ *GopBltSize = (UINTN) BltBufferSize;
+ *GopBlt = AllocatePool (*GopBltSize);
+ IsAllocated = TRUE;
+ if (*GopBlt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ } else {
+ //
+ // GopBlt has been allocated by caller.
+ //
+ if (*GopBltSize < (UINTN) BltBufferSize) {
+ *GopBltSize = (UINTN) BltBufferSize;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+ }
+
+ *PixelWidth = BmpHeader->PixelWidth;
+ *PixelHeight = BmpHeader->PixelHeight;
+
+ //
+ // Convert image from BMP to Blt buffer format
+ //
+ BltBuffer = *GopBlt;
+ for (Height = 0; Height < BmpHeader->PixelHeight; Height++) {
+ Blt = &BltBuffer[(BmpHeader->PixelHeight - Height - 1) * BmpHeader->PixelWidth];
+ for (Width = 0; Width < BmpHeader->PixelWidth; Width++, Image++, Blt++) {
+ switch (BmpHeader->BitPerPixel) {
+ case 1:
+ //
+ // Convert 1-bit (2 colors) BMP to 24-bit color
+ //
+ for (Index = 0; Index < 8 && Width < BmpHeader->PixelWidth; Index++) {
+ Blt->Red = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Red;
+ Blt->Green = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Green;
+ Blt->Blue = BmpColorMap[((*Image) >> (7 - Index)) & 0x1].Blue;
+ Blt++;
+ Width++;
+ }
+
+ Blt--;
+ Width--;
+ break;
+
+ case 4:
+ //
+ // Convert 4-bit (16 colors) BMP Palette to 24-bit color
+ //
+ Index = (*Image) >> 4;
+ Blt->Red = BmpColorMap[Index].Red;
+ Blt->Green = BmpColorMap[Index].Green;
+ Blt->Blue = BmpColorMap[Index].Blue;
+ if (Width < (BmpHeader->PixelWidth - 1)) {
+ Blt++;
+ Width++;
+ Index = (*Image) & 0x0f;
+ Blt->Red = BmpColorMap[Index].Red;
+ Blt->Green = BmpColorMap[Index].Green;
+ Blt->Blue = BmpColorMap[Index].Blue;
+ }
+ break;
+
+ case 8:
+ //
+ // Convert 8-bit (256 colors) BMP Palette to 24-bit color
+ //
+ Blt->Red = BmpColorMap[*Image].Red;
+ Blt->Green = BmpColorMap[*Image].Green;
+ Blt->Blue = BmpColorMap[*Image].Blue;
+ break;
+
+ case 24:
+ //
+ // It is 24-bit BMP.
+ //
+ Blt->Blue = *Image++;
+ Blt->Green = *Image++;
+ Blt->Red = *Image;
+ break;
+
+ default:
+ //
+ // Other bit format BMP is not supported.
+ //
+ if (IsAllocated) {
+ FreePool (*GopBlt);
+ *GopBlt = NULL;
+ }
+ return EFI_UNSUPPORTED;
+ break;
+ };
+
+ }
+
+ ImageIndex = (UINTN) (Image - ImageHeader);
+ if ((ImageIndex % 4) != 0) {
+ //
+ // Bmp Image starts each row on a 32-bit boundary!
+ //
+ Image = Image + (4 - (ImageIndex % 4));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Use SystemTable Conout to stop video based Simple Text Out consoles from going
+ to the video device. Put up LogoFile on every video device that is a console.
+
+ @param[in] LogoFile File name of logo to display on the center of the screen.
+
+ @retval EFI_SUCCESS ConsoleControl has been flipped to graphics and logo displayed.
+ @retval EFI_UNSUPPORTED Logo not found
+
+**/
+EFI_STATUS
+EFIAPI
+EnableQuietBoot (
+ IN EFI_GUID *LogoFile
+ )
+{
+ EFI_STATUS Status;
+ EFI_OEM_BADGING_PROTOCOL *Badging;
+ UINT32 SizeOfX;
+ UINT32 SizeOfY;
+ INTN DestX;
+ INTN DestY;
+ UINT8 *ImageData;
+ UINTN ImageSize;
+ UINTN BltSize;
+ UINT32 Instance;
+ EFI_BADGING_FORMAT Format;
+ EFI_BADGING_DISPLAY_ATTRIBUTE Attribute;
+ UINTN CoordinateX;
+ UINTN CoordinateY;
+ UINTN Height;
+ UINTN Width;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *Blt;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ UINTN NumberOfLogos;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL *LogoBlt;
+ UINTN LogoDestX;
+ UINTN LogoDestY;
+ UINTN LogoHeight;
+ UINTN LogoWidth;
+ UINTN NewDestX;
+ UINTN NewDestY;
+ UINTN NewHeight;
+ UINTN NewWidth;
+ UINT64 BufferSize;
+
+ UgaDraw = NULL;
+ //
+ // Try to open GOP first
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiGraphicsOutputProtocolGuid, (VOID **) &GraphicsOutput);
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ GraphicsOutput = NULL;
+ //
+ // Open GOP failed, try to open UGA
+ //
+ Status = gBS->HandleProtocol (gST->ConsoleOutHandle, &gEfiUgaDrawProtocolGuid, (VOID **) &UgaDraw);
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Try to open Boot Logo Protocol.
+ //
+ BootLogo = NULL;
+ gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+
+ //
+ // Erase Cursor from screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+
+ Badging = NULL;
+ Status = gBS->LocateProtocol (&gEfiOEMBadgingProtocolGuid, NULL, (VOID **) &Badging);
+
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->GetMode (UgaDraw, &SizeOfX, &SizeOfY, &ColorDepth, &RefreshRate);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ Blt = NULL;
+ NumberOfLogos = 0;
+ LogoDestX = 0;
+ LogoDestY = 0;
+ LogoHeight = 0;
+ LogoWidth = 0;
+ NewDestX = 0;
+ NewDestY = 0;
+ NewHeight = 0;
+ NewWidth = 0;
+ Instance = 0;
+ while (1) {
+ ImageData = NULL;
+ ImageSize = 0;
+
+ if (Badging != NULL) {
+ //
+ // Get image from OEMBadging protocol.
+ //
+ Status = Badging->GetImage (
+ Badging,
+ &Instance,
+ &Format,
+ &ImageData,
+ &ImageSize,
+ &Attribute,
+ &CoordinateX,
+ &CoordinateY
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ //
+ // Currently only support BMP format.
+ //
+ if (Format != EfiBadgingFormatBMP) {
+ if (ImageData != NULL) {
+ FreePool (ImageData);
+ }
+ continue;
+ }
+ } else {
+ //
+ // Get the specified image from FV.
+ //
+ Status = GetSectionFromAnyFv (LogoFile, EFI_SECTION_RAW, 0, (VOID **) &ImageData, &ImageSize);
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ CoordinateX = 0;
+ CoordinateY = 0;
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ Attribute = EfiBadgingDisplayAttributeCenter;
+ } else {
+ Attribute = EfiBadgingDisplayAttributeCustomized;
+ }
+ }
+
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+ Blt = NULL;
+ Status = ConvertBmpToGopBlt (
+ ImageData,
+ ImageSize,
+ (VOID **) &Blt,
+ &BltSize,
+ &Height,
+ &Width
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (ImageData);
+
+ if (Badging == NULL) {
+ return Status;
+ } else {
+ continue;
+ }
+ }
+
+ //
+ // Calculate the display position according to Attribute.
+ //
+ switch (Attribute) {
+ case EfiBadgingDisplayAttributeLeftTop:
+ DestX = CoordinateX;
+ DestY = CoordinateY;
+ break;
+
+ case EfiBadgingDisplayAttributeCenterTop:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = CoordinateY;
+ break;
+
+ case EfiBadgingDisplayAttributeRightTop:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = CoordinateY;;
+ break;
+
+ case EfiBadgingDisplayAttributeCenterRight:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeRightBottom:
+ DestX = (SizeOfX - Width - CoordinateX);
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeCenterBottom:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeLeftBottom:
+ DestX = CoordinateX;
+ DestY = (SizeOfY - Height - CoordinateY);
+ break;
+
+ case EfiBadgingDisplayAttributeCenterLeft:
+ DestX = CoordinateX;
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeCenter:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = (SizeOfY - Height) / 2;
+ break;
+
+ case EfiBadgingDisplayAttributeCustomized:
+ DestX = (SizeOfX - Width) / 2;
+ DestY = ((SizeOfY * 382) / 1000) - Height / 2;
+ break;
+
+ default:
+ DestX = CoordinateX;
+ DestY = CoordinateY;
+ break;
+ }
+
+ if ((DestX >= 0) && (DestY >= 0)) {
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ Blt,
+ EfiBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Width,
+ Height,
+ Width * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) Blt,
+ EfiUgaBltBufferToVideo,
+ 0,
+ 0,
+ (UINTN) DestX,
+ (UINTN) DestY,
+ Width,
+ Height,
+ Width * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ //
+ // Report displayed Logo information.
+ //
+ if (!EFI_ERROR (Status)) {
+ NumberOfLogos++;
+
+ if (LogoWidth == 0) {
+ //
+ // The first Logo.
+ //
+ LogoDestX = (UINTN) DestX;
+ LogoDestY = (UINTN) DestY;
+ LogoWidth = Width;
+ LogoHeight = Height;
+ } else {
+ //
+ // Merge new logo with old one.
+ //
+ NewDestX = MIN ((UINTN) DestX, LogoDestX);
+ NewDestY = MIN ((UINTN) DestY, LogoDestY);
+ NewWidth = MAX ((UINTN) DestX + Width, LogoDestX + LogoWidth) - NewDestX;
+ NewHeight = MAX ((UINTN) DestY + Height, LogoDestY + LogoHeight) - NewDestY;
+
+ LogoDestX = NewDestX;
+ LogoDestY = NewDestY;
+ LogoWidth = NewWidth;
+ LogoHeight = NewHeight;
+ }
+ }
+ }
+
+ FreePool (ImageData);
+
+ if (Badging == NULL) {
+ break;
+ }
+ }
+
+Done:
+ if (BootLogo == NULL || NumberOfLogos == 0) {
+ //
+ // No logo displayed.
+ //
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+
+ return Status;
+ }
+
+ //
+ // Advertise displayed Logo information.
+ //
+ if (NumberOfLogos == 1) {
+ //
+ // Only one logo displayed, use its Blt buffer directly for BootLogo protocol.
+ //
+ LogoBlt = Blt;
+ Status = EFI_SUCCESS;
+ } else {
+ //
+ // More than one Logo displayed, get merged BltBuffer using VideoToBuffer operation.
+ //
+ if (Blt != NULL) {
+ FreePool (Blt);
+ }
+
+ //
+ // Ensure the LogoHeight * LogoWidth doesn't overflow
+ //
+ if (LogoHeight > DivU64x64Remainder ((UINTN) ~0, LogoWidth, NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+ BufferSize = MultU64x64 (LogoWidth, LogoHeight);
+
+ //
+ // Ensure the BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL) doesn't overflow
+ //
+ if (BufferSize > DivU64x32 ((UINTN) ~0, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ LogoBlt = AllocateZeroPool ((UINTN)BufferSize * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL));
+ if (LogoBlt == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ LogoBlt,
+ EfiBltVideoToBltBuffer,
+ LogoDestX,
+ LogoDestY,
+ 0,
+ 0,
+ LogoWidth,
+ LogoHeight,
+ LogoWidth * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (UgaDraw != NULL && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) LogoBlt,
+ EfiUgaVideoToBltBuffer,
+ LogoDestX,
+ LogoDestY,
+ 0,
+ 0,
+ LogoWidth,
+ LogoHeight,
+ LogoWidth * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ Status = EFI_UNSUPPORTED;
+ }
+ }
+
+ if (!EFI_ERROR (Status)) {
+ BootLogo->SetBootLogo (BootLogo, LogoBlt, LogoDestX, LogoDestY, LogoWidth, LogoHeight);
+ }
+ FreePool (LogoBlt);
+
+ return Status;
+}
+
+/**
+ Use SystemTable Conout to turn on video based Simple Text Out consoles. The
+ Simple Text Out screens will now be synced up with all non video output devices
+
+ @retval EFI_SUCCESS UGA devices are back in text mode and synced up.
+
+**/
+EFI_STATUS
+EFIAPI
+DisableQuietBoot (
+ VOID
+ )
+{
+
+ //
+ // Enable Cursor on Screen
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
new file mode 100644
index 0000000000..24c1998a14
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/BdsMisc.c
@@ -0,0 +1,1589 @@
+/** @file
+ Misc BDS library function
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+
+#define MAX_STRING_LEN 200
+
+BOOLEAN mFeaturerSwitch = TRUE;
+BOOLEAN mResetRequired = FALSE;
+
+extern UINT16 gPlatformBootTimeOutDefault;
+
+/**
+ The function will go through the driver option link list, load and start
+ every driver the driver option device path point to.
+
+ @param BdsDriverLists The header of the current driver option link list
+
+**/
+VOID
+EFIAPI
+BdsLibLoadDrivers (
+ IN LIST_ENTRY *BdsDriverLists
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_COMMON_OPTION *Option;
+ EFI_HANDLE ImageHandle;
+ EFI_LOADED_IMAGE_PROTOCOL *ImageInfo;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ BOOLEAN ReconnectAll;
+
+ ReconnectAll = FALSE;
+
+ //
+ // Process the driver option
+ //
+ for (Link = BdsDriverLists->ForwardLink; Link != BdsDriverLists; Link = Link->ForwardLink) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // If a load option is not marked as LOAD_OPTION_ACTIVE,
+ // the boot manager will not automatically load the option.
+ //
+ if (!IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_ACTIVE)) {
+ continue;
+ }
+
+ //
+ // If a driver load option is marked as LOAD_OPTION_FORCE_RECONNECT,
+ // then all of the EFI drivers in the system will be disconnected and
+ // reconnected after the last driver load option is processed.
+ //
+ if (IS_LOAD_OPTION_TYPE (Option->Attribute, LOAD_OPTION_FORCE_RECONNECT)) {
+ ReconnectAll = TRUE;
+ }
+
+ //
+ // Make sure the driver path is connected.
+ //
+ BdsLibConnectDevicePath (Option->DevicePath);
+
+ //
+ // Load and start the image that Driver#### describes
+ //
+ Status = gBS->LoadImage (
+ FALSE,
+ gImageHandle,
+ Option->DevicePath,
+ NULL,
+ 0,
+ &ImageHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ gBS->HandleProtocol (ImageHandle, &gEfiLoadedImageProtocolGuid, (VOID **) &ImageInfo);
+
+ //
+ // Verify whether this image is a driver, if not,
+ // exit it and continue to parse next load option
+ //
+ if (ImageInfo->ImageCodeType != EfiBootServicesCode && ImageInfo->ImageCodeType != EfiRuntimeServicesCode) {
+ gBS->Exit (ImageHandle, EFI_INVALID_PARAMETER, 0, NULL);
+ continue;
+ }
+
+ if (Option->LoadOptionsSize != 0) {
+ ImageInfo->LoadOptionsSize = Option->LoadOptionsSize;
+ ImageInfo->LoadOptions = Option->LoadOptions;
+ }
+ //
+ // Before calling the image, enable the Watchdog Timer for
+ // the 5 Minute period
+ //
+ gBS->SetWatchdogTimer (5 * 60, 0x0000, 0x00, NULL);
+
+ Status = gBS->StartImage (ImageHandle, &ExitDataSize, &ExitData);
+ DEBUG ((DEBUG_INFO | DEBUG_LOAD, "Driver Return Status = %r\n", Status));
+
+ //
+ // Clear the Watchdog Timer after the image returns
+ //
+ gBS->SetWatchdogTimer (0x0000, 0x0000, 0x0000, NULL);
+ }
+ }
+
+ //
+ // Process the LOAD_OPTION_FORCE_RECONNECT driver option
+ //
+ if (ReconnectAll) {
+ BdsLibDisconnectAllEfi ();
+ BdsLibConnectAll ();
+ }
+
+}
+
+/**
+ Get the Option Number that does not used.
+ Try to locate the specific option variable one by one utile find a free number.
+
+ @param VariableName Indicate if the boot#### or driver#### option
+
+ @return The Minimal Free Option Number
+
+**/
+UINT16
+BdsLibGetFreeOptionNumber (
+ IN CHAR16 *VariableName
+ )
+{
+ UINTN Index;
+ CHAR16 StrTemp[10];
+ UINT16 *OptionBuffer;
+ UINTN OptionSize;
+
+ //
+ // Try to find the minimum free number from 0, 1, 2, 3....
+ //
+ Index = 0;
+ do {
+ if (*VariableName == 'B') {
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Boot%04x", Index);
+ } else {
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"Driver%04x", Index);
+ }
+ //
+ // try if the option number is used
+ //
+ OptionBuffer = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (OptionBuffer == NULL) {
+ break;
+ }
+ FreePool(OptionBuffer);
+ Index++;
+ } while (TRUE);
+
+ return ((UINT16) Index);
+}
+
+
+/**
+ This function will register the new boot#### or driver#### option base on
+ the VariableName. The new registered boot#### or driver#### will be linked
+ to BdsOptionList and also update to the VariableName. After the boot#### or
+ driver#### updated, the BootOrder or DriverOrder will also be updated.
+
+ @param BdsOptionList The header of the boot#### or driver#### link list
+ @param DevicePath The device path which the boot#### or driver####
+ option present
+ @param String The description of the boot#### or driver####
+ @param VariableName Indicate if the boot#### or driver#### option
+
+ @retval EFI_SUCCESS The boot#### or driver#### have been success
+ registered
+ @retval EFI_STATUS Return the status of gRT->SetVariable ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibRegisterNewOption (
+ IN LIST_ENTRY *BdsOptionList,
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN CHAR16 *String,
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINT16 RegisterOptionNumber;
+ UINT16 *TempOptionPtr;
+ UINTN TempOptionSize;
+ UINT16 *OptionOrderPtr;
+ VOID *OptionPtr;
+ UINTN OptionSize;
+ UINT8 *TempPtr;
+ EFI_DEVICE_PATH_PROTOCOL *OptionDevicePath;
+ CHAR16 *Description;
+ CHAR16 OptionName[10];
+ BOOLEAN UpdateDescription;
+ UINT16 BootOrderEntry;
+ UINTN OrderItemNum;
+
+ if (DevicePath == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ OptionPtr = NULL;
+ OptionSize = 0;
+ TempPtr = NULL;
+ OptionDevicePath = NULL;
+ Description = NULL;
+ OptionOrderPtr = NULL;
+ UpdateDescription = FALSE;
+ Status = EFI_SUCCESS;
+ ZeroMem (OptionName, sizeof (OptionName));
+
+ TempOptionSize = 0;
+ TempOptionPtr = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &TempOptionSize
+ );
+ //
+ // Compare with current option variable if the previous option is set in global variable.
+ //
+ for (Index = 0; Index < TempOptionSize / sizeof (UINT16); Index++) {
+ //
+ // TempOptionPtr must not be NULL if we have non-zero TempOptionSize.
+ //
+ ASSERT (TempOptionPtr != NULL);
+
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", TempOptionPtr[Index]);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", TempOptionPtr[Index]);
+ }
+
+ OptionPtr = BdsLibGetVariableAndSize (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (OptionPtr == NULL) {
+ continue;
+ }
+
+ //
+ // Validate the variable.
+ //
+ if (!ValidateOption(OptionPtr, OptionSize)) {
+ FreePool(OptionPtr);
+ continue;
+ }
+
+ TempPtr = OptionPtr;
+ TempPtr += sizeof (UINT32) + sizeof (UINT16);
+ Description = (CHAR16 *) TempPtr;
+ TempPtr += StrSize ((CHAR16 *) TempPtr);
+ OptionDevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+
+ //
+ // Notes: the description may will change base on the GetStringToken
+ //
+ if (CompareMem (OptionDevicePath, DevicePath, GetDevicePathSize (OptionDevicePath)) == 0) {
+ if (CompareMem (Description, String, StrSize (Description)) == 0) {
+ //
+ // Got the option, so just return
+ //
+ FreePool (OptionPtr);
+ FreePool (TempOptionPtr);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // Option description changed, need update.
+ //
+ UpdateDescription = TRUE;
+ FreePool (OptionPtr);
+ break;
+ }
+ }
+
+ FreePool (OptionPtr);
+ }
+
+ OptionSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (String);
+ OptionSize += GetDevicePathSize (DevicePath);
+ OptionPtr = AllocateZeroPool (OptionSize);
+ ASSERT (OptionPtr != NULL);
+
+ TempPtr = OptionPtr;
+ *(UINT32 *) TempPtr = LOAD_OPTION_ACTIVE;
+ TempPtr += sizeof (UINT32);
+ *(UINT16 *) TempPtr = (UINT16) GetDevicePathSize (DevicePath);
+ TempPtr += sizeof (UINT16);
+ CopyMem (TempPtr, String, StrSize (String));
+ TempPtr += StrSize (String);
+ CopyMem (TempPtr, DevicePath, GetDevicePathSize (DevicePath));
+
+ if (UpdateDescription) {
+ //
+ // The number in option#### to be updated.
+ // In this case, we must have non-NULL TempOptionPtr.
+ //
+ ASSERT (TempOptionPtr != NULL);
+ RegisterOptionNumber = TempOptionPtr[Index];
+ } else {
+ //
+ // The new option#### number
+ //
+ RegisterOptionNumber = BdsLibGetFreeOptionNumber(VariableName);
+ }
+
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", RegisterOptionNumber);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", RegisterOptionNumber);
+ }
+
+ Status = gRT->SetVariable (
+ OptionName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionSize,
+ OptionPtr
+ );
+ //
+ // Return if only need to update a changed description or fail to set option.
+ //
+ if (EFI_ERROR (Status) || UpdateDescription) {
+ FreePool (OptionPtr);
+ if (TempOptionPtr != NULL) {
+ FreePool (TempOptionPtr);
+ }
+ return Status;
+ }
+
+ FreePool (OptionPtr);
+
+ //
+ // Update the option order variable
+ //
+
+ //
+ // If no option order
+ //
+ if (TempOptionSize == 0) {
+ BootOrderEntry = 0;
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &BootOrderEntry
+ );
+ if (TempOptionPtr != NULL) {
+ FreePool (TempOptionPtr);
+ }
+ return Status;
+ }
+
+ //
+ // TempOptionPtr must not be NULL if TempOptionSize is not zero.
+ //
+ ASSERT (TempOptionPtr != NULL);
+ //
+ // Append the new option number to the original option order
+ //
+ OrderItemNum = (TempOptionSize / sizeof (UINT16)) + 1 ;
+ OptionOrderPtr = AllocateZeroPool ( OrderItemNum * sizeof (UINT16));
+ ASSERT (OptionOrderPtr!= NULL);
+ CopyMem (OptionOrderPtr, TempOptionPtr, (OrderItemNum - 1) * sizeof (UINT16));
+
+ OptionOrderPtr[Index] = RegisterOptionNumber;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OrderItemNum * sizeof (UINT16),
+ OptionOrderPtr
+ );
+ FreePool (TempOptionPtr);
+ FreePool (OptionOrderPtr);
+
+ return Status;
+}
+
+/**
+ Returns the size of a device path in bytes.
+
+ This function returns the size, in bytes, of the device path data structure
+ specified by DevicePath including the end of device path node. If DevicePath
+ is NULL, then 0 is returned. If the length of the device path is bigger than
+ MaxSize, also return 0 to indicate this is an invalidate device path.
+
+ @param DevicePath A pointer to a device path data structure.
+ @param MaxSize Max valid device path size. If big than this size,
+ return error.
+
+ @retval 0 An invalid device path.
+ @retval Others The size of a device path in bytes.
+
+**/
+UINTN
+GetDevicePathSizeEx (
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ IN UINTN MaxSize
+ )
+{
+ UINTN Size;
+ UINTN NodeSize;
+
+ if (DevicePath == NULL) {
+ return 0;
+ }
+
+ //
+ // Search for the end of the device path structure
+ //
+ Size = 0;
+ while (!IsDevicePathEnd (DevicePath)) {
+ NodeSize = DevicePathNodeLength (DevicePath);
+ if (NodeSize < END_DEVICE_PATH_LENGTH) {
+ return 0;
+ }
+ Size += NodeSize;
+ if (Size > MaxSize) {
+ return 0;
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+ Size += DevicePathNodeLength (DevicePath);
+ if (Size > MaxSize) {
+ return 0;
+ }
+
+ return Size;
+}
+
+/**
+ Returns the length of a Null-terminated Unicode string. If the length is
+ bigger than MaxStringLen, return length 0 to indicate that this is an
+ invalidate string.
+
+ This function returns the byte length of Unicode characters in the Null-terminated
+ Unicode string specified by String.
+
+ If String is NULL, then ASSERT().
+ If String is not aligned on a 16-bit boundary, then ASSERT().
+
+ @param String A pointer to a Null-terminated Unicode string.
+ @param MaxStringLen Max string len in this string.
+
+ @retval 0 An invalid string.
+ @retval Others The length of String.
+
+**/
+UINTN
+StrSizeEx (
+ IN CONST CHAR16 *String,
+ IN UINTN MaxStringLen
+ )
+{
+ UINTN Length;
+
+ ASSERT (String != NULL && MaxStringLen != 0);
+ ASSERT (((UINTN) String & BIT0) == 0);
+
+ for (Length = 0; *String != L'\0' && MaxStringLen != Length; String++, Length+=2);
+
+ if (*String != L'\0' && MaxStringLen == Length) {
+ return 0;
+ }
+
+ return Length + 2;
+}
+
+/**
+ Validate the EFI Boot#### variable (VendorGuid/Name)
+
+ @param Variable Boot#### variable data.
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+ValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ )
+{
+ UINT16 FilePathSize;
+ UINT8 *TempPtr;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN TempSize;
+
+ if (VariableSize <= sizeof (UINT16) + sizeof (UINT32)) {
+ return FALSE;
+ }
+
+ //
+ // Skip the option attribute
+ //
+ TempPtr = Variable;
+ TempPtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = *(UINT16 *) TempPtr;
+ TempPtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string size
+ //
+ TempSize = StrSizeEx ((CHAR16 *) TempPtr, VariableSize - sizeof (UINT16) - sizeof (UINT32));
+ TempPtr += TempSize;
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ TempPtr += FilePathSize;
+
+ //
+ // Validation boot option variable.
+ //
+ if ((FilePathSize == 0) || (TempSize == 0)) {
+ return FALSE;
+ }
+
+ if (TempSize + FilePathSize + sizeof (UINT16) + sizeof (UINT32) > VariableSize) {
+ return FALSE;
+ }
+
+ return (BOOLEAN) (GetDevicePathSizeEx (DevicePath, FilePathSize) != 0);
+}
+
+/**
+ Convert a single character to number.
+ It assumes the input Char is in the scope of L'0' ~ L'9' and L'A' ~ L'F'
+
+ @param Char The input char which need to change to a hex number.
+
+**/
+UINTN
+CharToUint (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= L'0') && (Char <= L'9')) {
+ return (UINTN) (Char - L'0');
+ }
+
+ if ((Char >= L'A') && (Char <= L'F')) {
+ return (UINTN) (Char - L'A' + 0xA);
+ }
+
+ ASSERT (FALSE);
+ return 0;
+}
+
+/**
+ Build the boot#### or driver#### option from the VariableName, the
+ build boot#### or driver#### will also be linked to BdsCommonOptionList.
+
+ @param BdsCommonOptionList The header of the boot#### or driver#### option
+ link list
+ @param VariableName EFI Variable name indicate if it is boot#### or
+ driver####
+
+ @retval BDS_COMMON_OPTION Get the option just been created
+ @retval NULL Failed to get the new option
+
+**/
+BDS_COMMON_OPTION *
+EFIAPI
+BdsLibVariableToOption (
+ IN OUT LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ )
+{
+ UINT32 Attribute;
+ UINT16 FilePathSize;
+ UINT8 *Variable;
+ UINT8 *TempPtr;
+ UINTN VariableSize;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BDS_COMMON_OPTION *Option;
+ VOID *LoadOptions;
+ UINT32 LoadOptionsSize;
+ CHAR16 *Description;
+ UINT8 NumOff;
+
+ //
+ // Read the variable. We will never free this data.
+ //
+ Variable = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &VariableSize
+ );
+ if (Variable == NULL) {
+ return NULL;
+ }
+
+ //
+ // Validate Boot#### variable data.
+ //
+ if (!ValidateOption(Variable, VariableSize)) {
+ FreePool (Variable);
+ return NULL;
+ }
+
+ //
+ // Notes: careful defined the variable of Boot#### or
+ // Driver####, consider use some macro to abstract the code
+ //
+ //
+ // Get the option attribute
+ //
+ TempPtr = Variable;
+ Attribute = *(UINT32 *) Variable;
+ TempPtr += sizeof (UINT32);
+
+ //
+ // Get the option's device path size
+ //
+ FilePathSize = *(UINT16 *) TempPtr;
+ TempPtr += sizeof (UINT16);
+
+ //
+ // Get the option's description string
+ //
+ Description = (CHAR16 *) TempPtr;
+
+ //
+ // Get the option's description string size
+ //
+ TempPtr += StrSize((CHAR16 *) TempPtr);
+
+ //
+ // Get the option's device path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) TempPtr;
+ TempPtr += FilePathSize;
+
+ //
+ // Get load opion data.
+ //
+ LoadOptions = TempPtr;
+ LoadOptionsSize = (UINT32) (VariableSize - (UINTN) (TempPtr - Variable));
+
+ //
+ // The Console variables may have multiple device paths, so make
+ // an Entry for each one.
+ //
+ Option = AllocateZeroPool (sizeof (BDS_COMMON_OPTION));
+ if (Option == NULL) {
+ FreePool (Variable);
+ return NULL;
+ }
+
+ Option->Signature = BDS_LOAD_OPTION_SIGNATURE;
+ Option->DevicePath = AllocateZeroPool (GetDevicePathSize (DevicePath));
+ ASSERT(Option->DevicePath != NULL);
+ CopyMem (Option->DevicePath, DevicePath, GetDevicePathSize (DevicePath));
+
+ Option->Attribute = Attribute;
+ Option->Description = AllocateZeroPool (StrSize (Description));
+ ASSERT(Option->Description != NULL);
+ CopyMem (Option->Description, Description, StrSize (Description));
+
+ Option->LoadOptions = AllocateZeroPool (LoadOptionsSize);
+ ASSERT(Option->LoadOptions != NULL);
+ CopyMem (Option->LoadOptions, LoadOptions, LoadOptionsSize);
+ Option->LoadOptionsSize = LoadOptionsSize;
+
+ //
+ // Get the value from VariableName Unicode string
+ // since the ISO standard assumes ASCII equivalent abbreviations, we can be safe in converting this
+ // Unicode stream to ASCII without any loss in meaning.
+ //
+ if (*VariableName == 'B') {
+ NumOff = (UINT8) (sizeof (L"Boot") / sizeof (CHAR16) - 1);
+ Option->BootCurrent = (UINT16) (CharToUint (VariableName[NumOff+0]) * 0x1000)
+ + (UINT16) (CharToUint (VariableName[NumOff+1]) * 0x100)
+ + (UINT16) (CharToUint (VariableName[NumOff+2]) * 0x10)
+ + (UINT16) (CharToUint (VariableName[NumOff+3]) * 0x1);
+ }
+ InsertTailList (BdsCommonOptionList, &Option->Link);
+ FreePool (Variable);
+ return Option;
+}
+
+/**
+ Process BootOrder, or DriverOrder variables, by calling
+ BdsLibVariableToOption () for each UINT16 in the variables.
+
+ @param BdsCommonOptionList The header of the option list base on variable
+ VariableName
+ @param VariableName EFI Variable name indicate the BootOrder or
+ DriverOrder
+
+ @retval EFI_SUCCESS Success create the boot option or driver option
+ list
+ @retval EFI_OUT_OF_RESOURCES Failed to get the boot option or driver option list
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibBuildOptionFromVar (
+ IN LIST_ENTRY *BdsCommonOptionList,
+ IN CHAR16 *VariableName
+ )
+{
+ UINT16 *OptionOrder;
+ UINTN OptionOrderSize;
+ UINTN Index;
+ BDS_COMMON_OPTION *Option;
+ CHAR16 OptionName[20];
+
+ //
+ // Zero Buffer in order to get all BOOT#### variables
+ //
+ ZeroMem (OptionName, sizeof (OptionName));
+
+ //
+ // Read the BootOrder, or DriverOrder variable.
+ //
+ OptionOrder = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &OptionOrderSize
+ );
+ if (OptionOrder == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < OptionOrderSize / sizeof (UINT16); Index++) {
+ if (*VariableName == 'B') {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", OptionOrder[Index]);
+ } else {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Driver%04x", OptionOrder[Index]);
+ }
+
+ Option = BdsLibVariableToOption (BdsCommonOptionList, OptionName);
+ if (Option != NULL) {
+ Option->BootCurrent = OptionOrder[Index];
+ }
+ }
+
+ FreePool (OptionOrder);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Get boot mode by looking up configuration table and parsing HOB list
+
+ @param BootMode Boot mode from PEI handoff HOB.
+
+ @retval EFI_SUCCESS Successfully get boot mode
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetBootMode (
+ OUT EFI_BOOT_MODE *BootMode
+ )
+{
+ *BootMode = GetBootModeHob ();
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Read the EFI variable (VendorGuid/Name) and return a dynamically allocated
+ buffer, and the size of the buffer. If failure return NULL.
+
+ @param Name String part of EFI variable name
+ @param VendorGuid GUID part of EFI variable name
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @return Dynamically allocated memory that contains a copy of the EFI variable
+ Caller is responsible freeing the buffer.
+ @retval NULL Variable was not read
+
+**/
+VOID *
+EFIAPI
+BdsLibGetVariableAndSize (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid,
+ OUT UINTN *VariableSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ VOID *Buffer;
+
+ Buffer = NULL;
+
+ //
+ // Pass in a zero size buffer to find the required buffer size.
+ //
+ BufferSize = 0;
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // Allocate the buffer to return
+ //
+ Buffer = AllocateZeroPool (BufferSize);
+ if (Buffer == NULL) {
+ *VariableSize = 0;
+ return NULL;
+ }
+ //
+ // Read variable into the allocated buffer.
+ //
+ Status = gRT->GetVariable (Name, VendorGuid, NULL, &BufferSize, Buffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (Buffer);
+ BufferSize = 0;
+ Buffer = NULL;
+ }
+ }
+
+ ASSERT (((Buffer == NULL) && (BufferSize == 0)) ||
+ ((Buffer != NULL) && (BufferSize != 0))
+ );
+ *VariableSize = BufferSize;
+ return Buffer;
+}
+
+/**
+ Delete the instance in Multi which matches partly with Single instance
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @return This function will remove the device path instances in Multi which partly
+ match with the Single, and return the result device path. If there is no
+ remaining device path as a result, this function will return NULL.
+
+**/
+EFI_DEVICE_PATH_PROTOCOL *
+EFIAPI
+BdsLibDelPartMatchInstance (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Instance;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TempNewDevicePath;
+ UINTN InstanceSize;
+ UINTN SingleDpSize;
+ UINTN Size;
+
+ NewDevicePath = NULL;
+ TempNewDevicePath = NULL;
+
+ if (Multi == NULL || Single == NULL) {
+ return Multi;
+ }
+
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ SingleDpSize = GetDevicePathSize (Single) - END_DEVICE_PATH_LENGTH;
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+
+ while (Instance != NULL) {
+
+ Size = (SingleDpSize < InstanceSize) ? SingleDpSize : InstanceSize;
+
+ if ((CompareMem (Instance, Single, Size) != 0)) {
+ //
+ // Append the device path instance which does not match with Single
+ //
+ TempNewDevicePath = NewDevicePath;
+ NewDevicePath = AppendDevicePathInstance (NewDevicePath, Instance);
+ if (TempNewDevicePath != NULL) {
+ FreePool(TempNewDevicePath);
+ }
+ }
+ FreePool(Instance);
+ Instance = GetNextDevicePathInstance (&Multi, &InstanceSize);
+ InstanceSize -= END_DEVICE_PATH_LENGTH;
+ }
+
+ return NewDevicePath;
+}
+
+/**
+ Function compares a device path data structure to that of all the nodes of a
+ second device path instance.
+
+ @param Multi A pointer to a multi-instance device path data
+ structure.
+ @param Single A pointer to a single-instance device path data
+ structure.
+
+ @retval TRUE If the Single device path is contained within Multi device path.
+ @retval FALSE The Single device path is not match within Multi device path.
+
+**/
+BOOLEAN
+EFIAPI
+BdsLibMatchDevicePaths (
+ IN EFI_DEVICE_PATH_PROTOCOL *Multi,
+ IN EFI_DEVICE_PATH_PROTOCOL *Single
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+
+ if (Multi == NULL || Single == NULL) {
+ return FALSE;
+ }
+
+ DevicePath = Multi;
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+
+ //
+ // Search for the match of 'Single' in 'Multi'
+ //
+ while (DevicePathInst != NULL) {
+ //
+ // If the single device path is found in multiple device paths,
+ // return success
+ //
+ if (CompareMem (Single, DevicePathInst, Size) == 0) {
+ FreePool (DevicePathInst);
+ return TRUE;
+ }
+
+ FreePool (DevicePathInst);
+ DevicePathInst = GetNextDevicePathInstance (&DevicePath, &Size);
+ }
+
+ return FALSE;
+}
+
+/**
+ This function prints a series of strings.
+
+ @param ConOut Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL
+ @param ... A variable argument list containing series of
+ strings, the last string must be NULL.
+
+ @retval EFI_SUCCESS Success print out the string using ConOut.
+ @retval EFI_STATUS Return the status of the ConOut->OutputString ().
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibOutputStrings (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut,
+ ...
+ )
+{
+ VA_LIST Args;
+ EFI_STATUS Status;
+ CHAR16 *String;
+
+ Status = EFI_SUCCESS;
+ VA_START (Args, ConOut);
+
+ while (!EFI_ERROR (Status)) {
+ //
+ // If String is NULL, then it's the end of the list
+ //
+ String = VA_ARG (Args, CHAR16 *);
+ if (String == NULL) {
+ break;
+ }
+
+ Status = ConOut->OutputString (ConOut, String);
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ VA_END(Args);
+ return Status;
+}
+
+//
+// Following are BDS Lib functions which contain all the code about setup browser reset reminder feature.
+// Setup Browser reset reminder feature is that an reset reminder will be given before user leaves the setup browser if
+// user change any option setting which needs a reset to be effective, and the reset will be applied according to the user selection.
+//
+
+
+/**
+ Enable the setup browser reset reminder feature.
+ This routine is used in platform tip. If the platform policy need the feature, use the routine to enable it.
+
+**/
+VOID
+EFIAPI
+EnableResetReminderFeature (
+ VOID
+ )
+{
+ mFeaturerSwitch = TRUE;
+}
+
+
+/**
+ Disable the setup browser reset reminder feature.
+ This routine is used in platform tip. If the platform policy do not want the feature, use the routine to disable it.
+
+**/
+VOID
+EFIAPI
+DisableResetReminderFeature (
+ VOID
+ )
+{
+ mFeaturerSwitch = FALSE;
+}
+
+
+/**
+ Record the info that a reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+EnableResetRequired (
+ VOID
+ )
+{
+ mResetRequired = TRUE;
+}
+
+
+/**
+ Record the info that no reset is required.
+ A module boolean variable is used to record whether a reset is required.
+
+**/
+VOID
+EFIAPI
+DisableResetRequired (
+ VOID
+ )
+{
+ mResetRequired = FALSE;
+}
+
+
+/**
+ Check whether platform policy enable the reset reminder feature. The default is enabled.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetReminderFeatureEnable (
+ VOID
+ )
+{
+ return mFeaturerSwitch;
+}
+
+
+/**
+ Check if user changed any option setting which needs a system reset to be effective.
+
+**/
+BOOLEAN
+EFIAPI
+IsResetRequired (
+ VOID
+ )
+{
+ return mResetRequired;
+}
+
+
+/**
+ Check whether a reset is needed, and finish the reset reminder feature.
+ If a reset is needed, Popup a menu to notice user, and finish the feature
+ according to the user selection.
+
+**/
+VOID
+EFIAPI
+SetupResetReminder (
+ VOID
+ )
+{
+ EFI_INPUT_KEY Key;
+ CHAR16 *StringBuffer1;
+ CHAR16 *StringBuffer2;
+
+
+ //
+ //check any reset required change is applied? if yes, reset system
+ //
+ if (IsResetReminderFeatureEnable ()) {
+ if (IsResetRequired ()) {
+
+ StringBuffer1 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+ ASSERT (StringBuffer1 != NULL);
+ StringBuffer2 = AllocateZeroPool (MAX_STRING_LEN * sizeof (CHAR16));
+ ASSERT (StringBuffer2 != NULL);
+ StrCpyS (
+ StringBuffer1,
+ MAX_STRING_LEN,
+ L"Configuration changed. Reset to apply it Now."
+ );
+ StrCpyS (
+ StringBuffer2,
+ MAX_STRING_LEN,
+ L"Press ENTER to reset"
+ );
+ //
+ // Popup a menu to notice user
+ //
+ do {
+ CreatePopUp (EFI_LIGHTGRAY | EFI_BACKGROUND_BLUE, &Key, StringBuffer1, StringBuffer2, NULL);
+ } while (Key.UnicodeChar != CHAR_CARRIAGE_RETURN);
+
+ FreePool (StringBuffer1);
+ FreePool (StringBuffer2);
+
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ }
+ }
+}
+
+/**
+ Get the headers (dos, image, optional header) from an image
+
+ @param Device SimpleFileSystem device handle
+ @param FileName File name for the image
+ @param DosHeader Pointer to dos header
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval EFI_SUCCESS Successfully get the machine type.
+ @retval EFI_NOT_FOUND The file is not found.
+ @retval EFI_LOAD_ERROR File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE Root;
+ EFI_FILE_HANDLE ThisFile;
+ UINTN BufferSize;
+ UINT64 FileSize;
+ EFI_FILE_INFO *Info;
+
+ Root = NULL;
+ ThisFile = NULL;
+ //
+ // Handle the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ Device,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ Status = Volume->OpenVolume (
+ Volume,
+ &Root
+ );
+ if (EFI_ERROR (Status)) {
+ Root = NULL;
+ goto Done;
+ }
+ ASSERT (Root != NULL);
+ Status = Root->Open (Root, &ThisFile, FileName, EFI_FILE_MODE_READ, 0);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ ASSERT (ThisFile != NULL);
+
+ //
+ // Get file size
+ //
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+ do {
+ Info = NULL;
+ Status = gBS->AllocatePool (EfiBootServicesData, BufferSize, (VOID **) &Info);
+ if (EFI_ERROR (Status)) {
+ goto Done;
+ }
+ Status = ThisFile->GetInfo (
+ ThisFile,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Info
+ );
+ if (!EFI_ERROR (Status)) {
+ break;
+ }
+ if (Status != EFI_BUFFER_TOO_SMALL) {
+ FreePool (Info);
+ goto Done;
+ }
+ FreePool (Info);
+ } while (TRUE);
+
+ FileSize = Info->FileSize;
+ FreePool (Info);
+
+ //
+ // Read dos header
+ //
+ BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
+ Status = ThisFile->Read (ThisFile, &BufferSize, DosHeader);
+ if (EFI_ERROR (Status) ||
+ BufferSize < sizeof (EFI_IMAGE_DOS_HEADER) ||
+ FileSize <= DosHeader->e_lfanew ||
+ DosHeader->e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Move to PE signature
+ //
+ Status = ThisFile->SetPosition (ThisFile, DosHeader->e_lfanew);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Read and check PE signature
+ //
+ BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ Status = ThisFile->Read (ThisFile, &BufferSize, Hdr.Pe32);
+ if (EFI_ERROR (Status) ||
+ BufferSize < sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION) ||
+ Hdr.Pe32->Signature != EFI_IMAGE_NT_SIGNATURE) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ //
+ // Check PE32 or PE32+ magic
+ //
+ if (Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC &&
+ Hdr.Pe32->OptionalHeader.Magic != EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ Status = EFI_LOAD_ERROR;
+ goto Done;
+ }
+
+ Done:
+ if (ThisFile != NULL) {
+ ThisFile->Close (ThisFile);
+ }
+ if (Root != NULL) {
+ Root->Close (Root);
+ }
+ return Status;
+}
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot.
+**/
+VOID
+BdsSetMemoryTypeInformationVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_MEMORY_TYPE_INFORMATION *PreviousMemoryTypeInformation;
+ EFI_MEMORY_TYPE_INFORMATION *CurrentMemoryTypeInformation;
+ UINTN VariableSize;
+ UINTN Index;
+ UINTN Index1;
+ UINT32 Previous;
+ UINT32 Current;
+ UINT32 Next;
+ EFI_HOB_GUID_TYPE *GuidHob;
+ BOOLEAN MemoryTypeInformationModified;
+ BOOLEAN MemoryTypeInformationVariableExists;
+ EFI_BOOT_MODE BootMode;
+
+ MemoryTypeInformationModified = FALSE;
+ MemoryTypeInformationVariableExists = FALSE;
+
+
+ BootMode = GetBootModeHob ();
+ //
+ // In BOOT_IN_RECOVERY_MODE, Variable region is not reliable.
+ //
+ if (BootMode == BOOT_IN_RECOVERY_MODE) {
+ return;
+ }
+
+ //
+ // Only check the the Memory Type Information variable in the boot mode
+ // other than BOOT_WITH_DEFAULT_SETTINGS because the Memory Type
+ // Information is not valid in this boot mode.
+ //
+ if (BootMode != BOOT_WITH_DEFAULT_SETTINGS) {
+ VariableSize = 0;
+ Status = gRT->GetVariable (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ NULL,
+ &VariableSize,
+ NULL
+ );
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ MemoryTypeInformationVariableExists = TRUE;
+ }
+ }
+
+ //
+ // Retrieve the current memory usage statistics. If they are not found, then
+ // no adjustments can be made to the Memory Type Information variable.
+ //
+ Status = EfiGetSystemConfigurationTable (
+ &gEfiMemoryTypeInformationGuid,
+ (VOID **) &CurrentMemoryTypeInformation
+ );
+ if (EFI_ERROR (Status) || CurrentMemoryTypeInformation == NULL) {
+ return;
+ }
+
+ //
+ // Get the Memory Type Information settings from Hob if they exist,
+ // PEI is responsible for getting them from variable and build a Hob to save them.
+ // If the previous Memory Type Information is not available, then set defaults
+ //
+ GuidHob = GetFirstGuidHob (&gEfiMemoryTypeInformationGuid);
+ if (GuidHob == NULL) {
+ //
+ // If Platform has not built Memory Type Info into the Hob, just return.
+ //
+ return;
+ }
+ PreviousMemoryTypeInformation = GET_GUID_HOB_DATA (GuidHob);
+ VariableSize = GET_GUID_HOB_DATA_SIZE (GuidHob);
+
+ //
+ // Use a heuristic to adjust the Memory Type Information for the next boot
+ //
+ DEBUG ((EFI_D_INFO, "Memory Previous Current Next \n"));
+ DEBUG ((EFI_D_INFO, " Type Pages Pages Pages \n"));
+ DEBUG ((EFI_D_INFO, "====== ======== ======== ========\n"));
+
+ for (Index = 0; PreviousMemoryTypeInformation[Index].Type != EfiMaxMemoryType; Index++) {
+
+ for (Index1 = 0; CurrentMemoryTypeInformation[Index1].Type != EfiMaxMemoryType; Index1++) {
+ if (PreviousMemoryTypeInformation[Index].Type == CurrentMemoryTypeInformation[Index1].Type) {
+ break;
+ }
+ }
+ if (CurrentMemoryTypeInformation[Index1].Type == EfiMaxMemoryType) {
+ continue;
+ }
+
+ //
+ // Previous is the number of pages pre-allocated
+ // Current is the number of pages actually needed
+ //
+ Previous = PreviousMemoryTypeInformation[Index].NumberOfPages;
+ Current = CurrentMemoryTypeInformation[Index1].NumberOfPages;
+ Next = Previous;
+
+ //
+ // Inconsistent Memory Reserved across bootings may lead to S4 fail
+ // Write next varible to 125% * current when the pre-allocated memory is:
+ // 1. More than 150% of needed memory and boot mode is BOOT_WITH_DEFAULT_SETTING
+ // 2. Less than the needed memory
+ //
+ if ((Current + (Current >> 1)) < Previous) {
+ if (BootMode == BOOT_WITH_DEFAULT_SETTINGS) {
+ Next = Current + (Current >> 2);
+ }
+ } else if (Current > Previous) {
+ Next = Current + (Current >> 2);
+ }
+ if (Next > 0 && Next < 4) {
+ Next = 4;
+ }
+
+ if (Next != Previous) {
+ PreviousMemoryTypeInformation[Index].NumberOfPages = Next;
+ MemoryTypeInformationModified = TRUE;
+ }
+
+ DEBUG ((EFI_D_INFO, " %02x %08x %08x %08x\n", PreviousMemoryTypeInformation[Index].Type, Previous, Current, Next));
+ }
+
+ //
+ // If any changes were made to the Memory Type Information settings, then set the new variable value;
+ // Or create the variable in first boot.
+ //
+ if (MemoryTypeInformationModified || !MemoryTypeInformationVariableExists) {
+ Status = SetVariableAndReportStatusCodeOnError (
+ EFI_MEMORY_TYPE_INFORMATION_VARIABLE_NAME,
+ &gEfiMemoryTypeInformationGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS,
+ VariableSize,
+ PreviousMemoryTypeInformation
+ );
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // If the Memory Type Information settings have been modified, then reset the platform
+ // so the new Memory Type Information setting will be used to guarantee that an S4
+ // entry/resume cycle will not fail.
+ //
+ if (MemoryTypeInformationModified && PcdGetBool (PcdResetOnMemoryTypeInformationChange)) {
+ DEBUG ((EFI_D_INFO, "Memory Type Information settings change. Warm Reset!!!\n"));
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ } else {
+ DEBUG ((EFI_D_ERROR, "Memory Type Information settings cannot be saved. OS S4 may fail!\n"));
+ }
+ }
+}
+
+/**
+ This routine is kept for backward compatibility.
+**/
+VOID
+EFIAPI
+BdsLibSaveMemoryTypeInformation (
+ VOID
+ )
+{
+}
+
+
+/**
+ Identify a user and, if authenticated, returns the current user profile handle.
+
+ @param[out] User Point to user profile handle.
+
+ @retval EFI_SUCCESS User is successfully identified, or user identification
+ is not supported.
+ @retval EFI_ACCESS_DENIED User is not successfully identified
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibUserIdentify (
+ OUT EFI_USER_PROFILE_HANDLE *User
+ )
+{
+ EFI_STATUS Status;
+ EFI_USER_MANAGER_PROTOCOL *Manager;
+
+ Status = gBS->LocateProtocol (
+ &gEfiUserManagerProtocolGuid,
+ NULL,
+ (VOID **) &Manager
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_SUCCESS;
+ }
+
+ return Manager->Identify (Manager, User);
+}
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+SetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+ UINTN NameSize;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = DataSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = Attributes;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ if ((Data != NULL) && (DataSize != 0)) {
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
+ }
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c
new file mode 100644
index 0000000000..2f22e7df7f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/DevicePath.c
@@ -0,0 +1,33 @@
+/** @file
+ BDS internal function define the default device path string, it can be
+ replaced by platform device path.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+/**
+ This function converts an input device structure to a Unicode string.
+
+ @param DevPath A pointer to the device path structure.
+
+ @return A new allocated Unicode string that represents the device path.
+
+**/
+CHAR16 *
+EFIAPI
+DevicePathToStr (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ return ConvertDevicePathToText (DevPath, TRUE, TRUE);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
new file mode 100644
index 0000000000..5a138a9169
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.inf
@@ -0,0 +1,145 @@
+## @file
+# General BDS library.
+#
+# General BDS defines and produce general interfaces for platform BDS driver including:
+# 1) BDS boot policy interface;
+# 2) BDS boot device connect interface;
+# 3) BDS Misc interfaces for mainting boot variable, ouput string, etc.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = GenericBdsLib
+ MODULE_UNI_FILE = GenericBdsLib.uni
+ FILE_GUID = e405ec31-ccaa-4dd4-83e8-0aec01703f7e
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = GenericBdsLib|DXE_DRIVER DXE_RUNTIME_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = GenericBdsLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DevicePath.c
+ Performance.c
+ BdsConnect.c
+ BdsMisc.c
+ BdsConsole.c
+ BdsBoot.c
+ InternalBdsLib.h
+ String.h
+ String.c
+ GenericBdsStrings.uni
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ PeCoffGetEntryPointLib
+ BaseLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ PcdLib
+ PerformanceLib
+ TimerLib
+ DxeServicesLib
+ HiiLib
+ ReportStatusCodeLib
+
+[Guids]
+ ## SOMETIMES_CONSUMES ## HOB # The hob holding memory type information
+ ## SOMETIMES_CONSUMES ## SystemTable # The identifier of memory type information type in system table
+ ## SOMETIMES_CONSUMES ## Variable:L"MemoryTypeInformation"
+ ## SOMETIMES_PRODUCES ## Variable:L"MemoryTypeInformation"
+ gEfiMemoryTypeInformationGuid
+ ## SOMETIMES_CONSUMES ## Variable:L"BootXXXX" # Boot option variable
+ ## SOMETIMES_PRODUCES ## Variable:L"BootXXXX" # Boot option variable
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverXXXX" # Driver load option.
+ ## SOMETIMES_PRODUCES ## Variable:L"DriverXXXX" # Driver load option.
+ ## SOMETIMES_CONSUMES ## Variable:L"BootNext" # Next Boot Option
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext" # Next Boot Option
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" # The boot option array
+ ## SOMETIMES_PRODUCES ## Variable:L"BootOrder" # The boot option array
+ ## SOMETIMES_CONSUMES ## Variable:L"DriverOrder" # The driver order list
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"BootCurrent" # The boot option of current boot
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext" # The number of next boot option
+ gEfiGlobalVariableGuid
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## GUID
+ gPerformanceProtocolGuid ## SOMETIMES_PRODUCES ## Variable:L"PerfDataMemAddr" # The ACPI address of performance data
+ gLastEnumLangGuid ## SOMETIMES_PRODUCES ## Variable:L"LastEnumLang" # Platform language at last time enumeration.
+ gHdBootDevicePathVariablGuid ## SOMETIMES_PRODUCES ## Variable:L"HDDP" # The device path of Boot file on Hard device.
+ gBdsLibStringPackageGuid ## CONSUMES ## HII # HII String PackageList Guid
+ ## SOMETIMES_PRODUCES ## Variable:L"LegacyDevOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"LegacyDevOrder"
+ gEfiLegacyDevOrderVariableGuid
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextOutProtocolGuid ## CONSUMES
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadedImageProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleNetworkProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDebugPortProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSimpleTextInProtocolGuid ## CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiCpuArchProtocolGuid ## CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUgaDrawProtocolGuid |gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## SOMETIMES_CONSUMES
+ gEfiOEMBadgingProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiHiiFontProtocolGuid ## CONSUMES
+ gEfiUserManagerProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUsbIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootlogoOnlyEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdResetOnMemoryTypeInformationChange ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderLoad ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdProgressCodeOsLoaderStart ## SOMETIMES_CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdShellFile ## CONSUMES
+
+#
+# [BootMode]
+# RECOVERY_FULL ## SOMETIMES_CONSUMES # Memory Type Information variable
+#
+
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.uni b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.uni
new file mode 100644
index 0000000000..5611f6f6bf
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni
new file mode 100644
index 0000000000..7c3b4f9690
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/GenericBdsStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h
new file mode 100644
index 0000000000..7201d8a335
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/InternalBdsLib.h
@@ -0,0 +1,194 @@
+/** @file
+ BDS library definition, include the file and data structure
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_BDS_LIB_H_
+#define _INTERNAL_BDS_LIB_H_
+
+#include <FrameworkDxe.h>
+
+#include <IndustryStandard/Pci.h>
+#include <IndustryStandard/PeImage.h>
+
+#include <Protocol/BlockIo.h>
+#include <Protocol/LoadedImage.h>
+#include <Protocol/Cpu.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/LoadFile.h>
+#include <Protocol/DebugPort.h>
+#include <Protocol/DevicePath.h>
+#include <Protocol/SimpleTextIn.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/SimpleNetwork.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/OEMBadging.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/HiiFont.h>
+#include <Protocol/HiiImage.h>
+#include <Protocol/UsbIo.h>
+#include <Protocol/BootLogo.h>
+
+#include <Guid/MemoryTypeInformation.h>
+#include <Guid/FileInfo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/PcAnsi.h>
+#include <Guid/Performance.h>
+#include <Guid/BdsLibHii.h>
+#include <Guid/HdBootVariable.h>
+#include <Guid/LastEnumLang.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeCoffGetEntryPointLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/TimerLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DxeServicesLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#if !defined (EFI_REMOVABLE_MEDIA_FILE_NAME)
+ #if defined (MDE_CPU_EBC)
+ //
+ // Uefi specification only defines the default boot file name for IA32, X64
+ // and IPF processor, so need define boot file name for EBC architecture here.
+ //
+ #define EFI_REMOVABLE_MEDIA_FILE_NAME L"\\EFI\\BOOT\\BOOTEBC.EFI"
+ #else
+ #error "Can not determine the default boot file name for unknown processor type!"
+ #endif
+#endif
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+WriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+/**
+ Get the headers (dos, image, optional header) from an image
+
+ @param Device SimpleFileSystem device handle
+ @param FileName File name for the image
+ @param DosHeader Pointer to dos header
+ @param Hdr The buffer in which to return the PE32, PE32+, or TE header.
+
+ @retval EFI_SUCCESS Successfully get the machine type.
+ @retval EFI_NOT_FOUND The file is not found.
+ @retval EFI_LOAD_ERROR File is not a valid image file.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsLibGetImageHeader (
+ IN EFI_HANDLE Device,
+ IN CHAR16 *FileName,
+ OUT EFI_IMAGE_DOS_HEADER *DosHeader,
+ OUT EFI_IMAGE_OPTIONAL_HEADER_PTR_UNION Hdr
+ );
+
+/**
+ This routine adjust the memory information for different memory type and
+ save them into the variables for next boot.
+**/
+VOID
+BdsSetMemoryTypeInformationVariable (
+ VOID
+ );
+
+/**
+ Validate the EFI Boot#### or Driver#### variable (VendorGuid/Name)
+
+ @param Variable Boot#### variable data.
+ @param VariableSize Returns the size of the EFI variable that was read
+
+ @retval TRUE The variable data is correct.
+ @retval FALSE The variable data is corrupted.
+
+**/
+BOOLEAN
+ValidateOption (
+ UINT8 *Variable,
+ UINTN VariableSize
+ );
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+SetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+#endif // _BDS_LIB_H_
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c
new file mode 100644
index 0000000000..e50345a597
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/Performance.c
@@ -0,0 +1,313 @@
+/** @file
+ This file include the file which can help to get the system
+ performance, all the function will only include if the performance
+ switch is set.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalBdsLib.h"
+
+PERF_HEADER mPerfHeader;
+PERF_DATA mPerfData;
+EFI_PHYSICAL_ADDRESS mAcpiLowMemoryBase = 0x0FFFFFFFFULL;
+
+/**
+ Get the short verion of PDB file name to be
+ used in performance data logging.
+
+ @param PdbFileName The long PDB file name.
+ @param GaugeString The output string to be logged by performance logger.
+
+**/
+VOID
+GetShortPdbFileName (
+ IN CONST CHAR8 *PdbFileName,
+ OUT CHAR8 *GaugeString
+ )
+{
+ UINTN Index;
+ UINTN Index1;
+ UINTN StartIndex;
+ UINTN EndIndex;
+
+ if (PdbFileName == NULL) {
+ AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
+ } else {
+ StartIndex = 0;
+ for (EndIndex = 0; PdbFileName[EndIndex] != 0; EndIndex++)
+ ;
+
+ for (Index = 0; PdbFileName[Index] != 0; Index++) {
+ if (PdbFileName[Index] == '\\') {
+ StartIndex = Index + 1;
+ }
+
+ if (PdbFileName[Index] == '.') {
+ EndIndex = Index;
+ }
+ }
+
+ Index1 = 0;
+ for (Index = StartIndex; Index < EndIndex; Index++) {
+ GaugeString[Index1] = PdbFileName[Index];
+ Index1++;
+ if (Index1 == PERF_TOKEN_LENGTH) {
+ break;
+ }
+ }
+
+ GaugeString[Index1] = 0;
+ }
+
+ return ;
+}
+
+/**
+ Get the name from the Driver handle, which can be a handle with
+ EFI_LOADED_IMAGE_PROTOCOL or EFI_DRIVER_BINDING_PROTOCOL installed.
+ This name can be used in performance data logging.
+
+ @param Handle Driver handle.
+ @param GaugeString The output string to be logged by performance logger.
+
+**/
+VOID
+GetNameFromHandle (
+ IN EFI_HANDLE Handle,
+ OUT CHAR8 *GaugeString
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *Image;
+ CHAR8 *PdbFileName;
+ EFI_DRIVER_BINDING_PROTOCOL *DriverBinding;
+
+ AsciiStrCpyS (GaugeString, PERF_TOKEN_SIZE, " ");
+
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+
+ if (EFI_ERROR (Status)) {
+ Status = gBS->OpenProtocol (
+ Handle,
+ &gEfiDriverBindingProtocolGuid,
+ (VOID **) &DriverBinding,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+ //
+ // Get handle name from image protocol
+ //
+ Status = gBS->HandleProtocol (
+ DriverBinding->ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **) &Image
+ );
+ }
+
+ PdbFileName = PeCoffLoaderGetPdbPointer (Image->ImageBase);
+
+ if (PdbFileName != NULL) {
+ GetShortPdbFileName (PdbFileName, GaugeString);
+ }
+
+ return ;
+}
+
+/**
+
+ Writes performance data of booting into the allocated memory.
+ OS can process these records.
+
+ @param Event The triggered event.
+ @param Context Context for this event.
+
+**/
+VOID
+EFIAPI
+WriteBootToOsPerformanceData (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINT32 LimitCount;
+ EFI_HANDLE *Handles;
+ UINTN NoHandles;
+ CHAR8 GaugeString[PERF_TOKEN_SIZE];
+ UINT8 *Ptr;
+ UINT32 Index;
+ UINT64 Ticker;
+ UINT64 Freq;
+ UINT32 Duration;
+ UINTN LogEntryKey;
+ CONST VOID *Handle;
+ CONST CHAR8 *Token;
+ CONST CHAR8 *Module;
+ UINT64 StartTicker;
+ UINT64 EndTicker;
+ UINT64 StartValue;
+ UINT64 EndValue;
+ BOOLEAN CountUp;
+ UINTN VarSize;
+ BOOLEAN Found;
+
+ //
+ // Record the performance data for End of BDS
+ //
+ PERF_END(NULL, "BDS", NULL, 0);
+
+ //
+ // Retrieve time stamp count as early as possible
+ //
+ Ticker = GetPerformanceCounter ();
+
+ Freq = GetPerformanceCounterProperties (&StartValue, &EndValue);
+
+ Freq = DivU64x32 (Freq, 1000);
+
+ mPerfHeader.CpuFreq = Freq;
+
+ //
+ // Record BDS raw performance data
+ //
+ if (EndValue >= StartValue) {
+ mPerfHeader.BDSRaw = Ticker - StartValue;
+ CountUp = TRUE;
+ } else {
+ mPerfHeader.BDSRaw = StartValue - Ticker;
+ CountUp = FALSE;
+ }
+
+ //
+ // Reset the entry count
+ //
+ mPerfHeader.Count = 0;
+
+ if (mAcpiLowMemoryBase == 0x0FFFFFFFF) {
+ VarSize = sizeof (EFI_PHYSICAL_ADDRESS);
+ Status = gRT->GetVariable (
+ L"PerfDataMemAddr",
+ &gPerformanceProtocolGuid,
+ NULL,
+ &VarSize,
+ &mAcpiLowMemoryBase
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Fail to get the variable, return.
+ //
+ return;
+ }
+ }
+
+ //
+ // Put Detailed performance data into memory
+ //
+ Handles = NULL;
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ return ;
+ }
+
+ Ptr = (UINT8 *) ((UINT32) mAcpiLowMemoryBase + sizeof (PERF_HEADER));
+ LimitCount = (UINT32) (PERF_DATA_MAX_LENGTH - sizeof (PERF_HEADER)) / sizeof (PERF_DATA);
+
+ //
+ // Get performance data
+ //
+ LogEntryKey = 0;
+ while ((LogEntryKey = GetPerformanceMeasurement (
+ LogEntryKey,
+ &Handle,
+ &Token,
+ &Module,
+ &StartTicker,
+ &EndTicker)) != 0) {
+ if (EndTicker != 0) {
+ if (StartTicker == 1) {
+ StartTicker = StartValue;
+ }
+ if (EndTicker == 1) {
+ EndTicker = StartValue;
+ }
+ Ticker = CountUp ? (EndTicker - StartTicker) : (StartTicker - EndTicker);
+
+ Duration = (UINT32) DivU64x32 (Ticker, (UINT32) Freq);
+ if (Duration == 0) {
+ continue;
+ }
+
+ ZeroMem (&mPerfData, sizeof (PERF_DATA));
+
+ mPerfData.Duration = Duration;
+
+ //
+ // See if the Handle is in the handle buffer
+ //
+ Found = FALSE;
+ for (Index = 0; Index < NoHandles; Index++) {
+ if (Handle == Handles[Index]) {
+ GetNameFromHandle (Handles[Index], GaugeString);
+ AsciiStrCpyS (mPerfData.Token, PERF_TOKEN_SIZE, GaugeString);
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ AsciiStrnCpyS (mPerfData.Token, PERF_TOKEN_SIZE, Token, PERF_TOKEN_LENGTH);
+ }
+
+ CopyMem (Ptr, &mPerfData, sizeof (PERF_DATA));
+ Ptr += sizeof (PERF_DATA);
+
+ mPerfHeader.Count++;
+ if (mPerfHeader.Count == LimitCount) {
+ goto Done;
+ }
+ }
+ }
+
+Done:
+
+ FreePool (Handles);
+
+ mPerfHeader.Signiture = PERFORMANCE_SIGNATURE;
+
+ //
+ // Put performance data to Reserved memory
+ //
+ CopyMem (
+ (UINTN *) (UINTN) mAcpiLowMemoryBase,
+ &mPerfHeader,
+ sizeof (PERF_HEADER)
+ );
+
+ return ;
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c
new file mode 100644
index 0000000000..762871605d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.c
@@ -0,0 +1,32 @@
+/** @file
+ String support
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "String.h"
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+BdsLibGetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (gBdsLibStringPackHandle, Id, NULL);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h
new file mode 100644
index 0000000000..13b745de87
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/GenericBdsLib/String.h
@@ -0,0 +1,48 @@
+/** @file
+ String support
+
+Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#include <Library/HiiLib.h>
+#include <Library/DebugLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+extern EFI_HII_HANDLE gBdsLibStringPackHandle;
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+
+extern UINT8 GenericBdsLibStrings[];
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+BdsLibGetStringById (
+ IN EFI_STRING_ID Id
+ );
+
+#endif // _STRING_H_
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.c b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.c
new file mode 100644
index 0000000000..bb320f37b2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.c
@@ -0,0 +1,1456 @@
+/** @file
+ Legacy Boot Maintainence UI implementation.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#include "LegacyBootMaintUi.h"
+
+LEGACY_BOOT_OPTION_CALLBACK_DATA *mLegacyBootOptionPrivate;
+EFI_GUID mLegacyBootOptionGuid = LEGACY_BOOT_OPTION_FORMSET_GUID;
+CHAR16 mLegacyBootStorageName[] = L"LegacyBootData";
+BBS_TYPE mBbsType[] = {BBS_FLOPPY, BBS_HARDDISK, BBS_CDROM, BBS_EMBED_NETWORK, BBS_BEV_DEVICE, BBS_UNKNOWN};
+
+
+///
+/// Legacy FD Info from LegacyBios.GetBbsInfo()
+///
+LEGACY_MENU_OPTION LegacyFDMenu = {
+ LEGACY_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy HD Info from LegacyBios.GetBbsInfo()
+///
+LEGACY_MENU_OPTION LegacyHDMenu = {
+ LEGACY_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy CD Info from LegacyBios.GetBbsInfo()
+///
+LEGACY_MENU_OPTION LegacyCDMenu = {
+ LEGACY_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy NET Info from LegacyBios.GetBbsInfo()
+///
+LEGACY_MENU_OPTION LegacyNETMenu = {
+ LEGACY_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy NET Info from LegacyBios.GetBbsInfo()
+///
+LEGACY_MENU_OPTION LegacyBEVMenu = {
+ LEGACY_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+
+VOID *mLegacyStartOpCodeHandle = NULL;
+VOID *mLegacyEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mLegacyStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mLegacyEndLabel = NULL;
+
+
+HII_VENDOR_DEVICE_PATH mLegacyBootOptionHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } }
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+
+/**
+ Re-order the Boot Option according to the DevOrder.
+
+ The routine re-orders the Boot Option in BootOption array according to
+ the order specified by DevOrder.
+
+ @param DevOrder Pointer to buffer containing the BBS Index,
+ high 8-bit value 0xFF indicating a disabled boot option
+ @param DevOrderCount Count of the BBS Index
+ @param EnBootOption Callee allocated buffer containing the enabled Boot Option Numbers
+ @param EnBootOptionCount Count of the enabled Boot Option Numbers
+ @param DisBootOption Callee allocated buffer containing the disabled Boot Option Numbers
+ @param DisBootOptionCount Count of the disabled Boot Option Numbers
+**/
+VOID
+OrderLegacyBootOption4SameType (
+ UINT16 *DevOrder,
+ UINTN DevOrderCount,
+ UINT16 **EnBootOption,
+ UINTN *EnBootOptionCount,
+ UINT16 **DisBootOption,
+ UINTN *DisBootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *NewBootOption;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ UINTN Index;
+ UINTN StartPosition;
+
+ EFI_BOOT_MANAGER_LOAD_OPTION BootOption;
+
+ CHAR16 OptionName[sizeof ("Boot####")];
+ UINT16 *BbsIndexArray;
+ UINT16 *DeviceTypeArray;
+
+ GetEfiGlobalVariable2 (L"BootOrder", (VOID **) &BootOrder, &BootOrderSize);
+ ASSERT (BootOrder != NULL);
+
+ BbsIndexArray = AllocatePool (BootOrderSize);
+ DeviceTypeArray = AllocatePool (BootOrderSize);
+ *EnBootOption = AllocatePool (BootOrderSize);
+ *DisBootOption = AllocatePool (BootOrderSize);
+ *DisBootOptionCount = 0;
+ *EnBootOptionCount = 0;
+ Index = 0;
+
+ ASSERT (BbsIndexArray != NULL);
+ ASSERT (DeviceTypeArray != NULL);
+ ASSERT (*EnBootOption != NULL);
+ ASSERT (*DisBootOption != NULL);
+
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
+ Status = EfiBootManagerVariableToLoadOption (OptionName, &BootOption);
+ ASSERT_EFI_ERROR (Status);
+
+ if ((DevicePathType (BootOption.FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption.FilePath) == BBS_BBS_DP)) {
+ //
+ // Legacy Boot Option
+ //
+ ASSERT (BootOption.OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
+
+ DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption.FilePath)->DeviceType;
+ BbsIndexArray [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption.OptionalData)->BbsIndex;
+ } else {
+ DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
+ BbsIndexArray [Index] = 0xFFFF;
+ }
+ EfiBootManagerFreeLoadOption (&BootOption);
+ }
+
+ //
+ // Record the corresponding Boot Option Numbers according to the DevOrder
+ // Record the EnBootOption and DisBootOption according to the DevOrder
+ //
+ StartPosition = BootOrderSize / sizeof (UINT16);
+ NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
+ ASSERT (NewBootOption != NULL);
+ while (DevOrderCount-- != 0) {
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
+ StartPosition = MIN (StartPosition, Index);
+ NewBootOption[DevOrderCount] = BootOrder[Index];
+
+ if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
+ (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
+ (*DisBootOptionCount)++;
+ } else {
+ (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
+ (*EnBootOptionCount)++;
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // Overwrite the old BootOption
+ //
+ CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ BootOrderSize,
+ BootOrder
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (NewBootOption);
+ FreePool (DeviceTypeArray);
+ FreePool (BbsIndexArray);
+}
+
+/**
+ Update the legacy BBS boot option. L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable
+ is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
+ is also updated.
+
+ @param NVMapData The data for egacy BBS boot.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND If L"LegacyDevOrder" and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource
+**/
+EFI_STATUS
+UpdateBBSOption (
+ IN LEGACY_BOOT_NV_DATA *NVMapData
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+ UINTN CurrentType;
+ VOID *BootOptionVar;
+ CHAR16 VarName[100];
+ UINTN OptionSize;
+ EFI_STATUS Status;
+ UINT32 *Attribute;
+ LEGACY_MENU_OPTION *OptionMenu;
+ UINT16 *LegacyDev;
+ UINT16 *InitialLegacyDev;
+ UINT8 *VarData;
+ UINTN VarSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ UINT8 *OriginalPtr;
+ UINT8 *DisMap;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 *NewOrder;
+ UINT16 Tmp;
+ UINT16 *EnBootOption;
+ UINTN EnBootOptionCount;
+ UINT16 *DisBootOption;
+ UINTN DisBootOptionCount;
+ UINTN BufferSize;
+
+
+ DisMap = NULL;
+ NewOrder = NULL;
+ CurrentType = 0;
+
+
+ DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
+ Status = EFI_SUCCESS;
+
+ //
+ // Update the Variable "LegacyDevOrder"
+ //
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
+ if (VarData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ OriginalPtr = VarData;
+
+ while (mBbsType[CurrentType] != BBS_UNKNOWN) {
+ switch (mBbsType[CurrentType]) {
+ case BBS_FLOPPY:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
+ LegacyDev = NVMapData->LegacyFD;
+ InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
+ BufferSize = sizeof (NVMapData->LegacyFD);
+ break;
+
+ case BBS_HARDDISK:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
+ LegacyDev = NVMapData->LegacyHD;
+ InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
+
+ BufferSize = sizeof (NVMapData->LegacyHD);
+ break;
+
+ case BBS_CDROM:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
+ LegacyDev = NVMapData->LegacyCD;
+ InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
+ BufferSize = sizeof (NVMapData->LegacyCD);
+ break;
+
+ case BBS_EMBED_NETWORK:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
+ LegacyDev = NVMapData->LegacyNET;
+ InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
+ BufferSize = sizeof (NVMapData->LegacyNET);
+ break;
+
+ default:
+ ASSERT (mBbsType[CurrentType] == BBS_BEV_DEVICE);
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
+ LegacyDev = NVMapData->LegacyBEV;
+ InitialLegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
+ BufferSize = sizeof (NVMapData->LegacyBEV);
+ break;
+ }
+
+ //
+ // Check whether has value changed.
+ //
+ if (CompareMem (LegacyDev, InitialLegacyDev, BufferSize) == 0) {
+ CurrentType++;
+ continue;
+ }
+
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) OriginalPtr;
+ while (VarData < OriginalPtr + VarSize) {
+ if (DevOrder->BbsType == mBbsType[CurrentType]) {
+ break;
+ }
+
+ VarData += sizeof (BBS_TYPE) + DevOrder->Length;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ }
+
+ if (VarData >= OriginalPtr + VarSize) {
+ FreePool (OriginalPtr);
+ return EFI_NOT_FOUND;
+ }
+
+ NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
+ if (NewOrder == NULL) {
+ FreePool (OriginalPtr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ if (0xFF == LegacyDev[Index]) {
+ break;
+ }
+
+ NewOrder[Index] = LegacyDev[Index];
+ }
+
+ //
+ // Only the enable/disable state of each boot device with same device type can be changed,
+ // so we can count on the index information in DevOrder.
+ // DisMap bit array is the only reliable source to check a device's en/dis state,
+ // so we use DisMap to set en/dis state of each item in NewOrder array
+ //
+ for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
+ Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
+ Pos = Tmp / 8;
+ Bit = 7 - (Tmp % 8);
+ if ((DisMap[Pos] & (1 << Bit)) != 0) {
+ NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
+ Index++;
+ }
+ }
+
+ CopyMem (
+ DevOrder->Data,
+ NewOrder,
+ DevOrder->Length - sizeof (DevOrder->Length)
+ );
+ FreePool (NewOrder);
+
+ //
+ // Update BootOrder and Boot####.Attribute
+ //
+ // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
+ //
+ ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
+
+ OrderLegacyBootOption4SameType (
+ DevOrder->Data,
+ DevOrder->Length / sizeof (UINT16) - 1,
+ &EnBootOption,
+ &EnBootOptionCount,
+ &DisBootOption,
+ &DisBootOptionCount
+ );
+
+ //
+ // 2. Deactivate the DisBootOption and activate the EnBootOption
+ //
+ for (Index = 0; Index < DisBootOptionCount; Index++) {
+ UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
+ GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
+ if (BootOptionVar != NULL) {
+ Attribute = (UINT32 *) BootOptionVar;
+ *Attribute &= ~LOAD_OPTION_ACTIVE;
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ OptionSize,
+ BootOptionVar
+ );
+
+ FreePool (BootOptionVar);
+ }
+ }
+
+ for (Index = 0; Index < EnBootOptionCount; Index++) {
+ UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
+ GetEfiGlobalVariable2 (VarName, (VOID **) &BootOptionVar, &OptionSize);
+ if (BootOptionVar != NULL) {
+ Attribute = (UINT32 *) BootOptionVar;
+ *Attribute |= LOAD_OPTION_ACTIVE;
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ VAR_FLAG,
+ OptionSize,
+ BootOptionVar
+ );
+
+ FreePool (BootOptionVar);
+ }
+ }
+
+
+ FreePool (EnBootOption);
+ FreePool (DisBootOption);
+
+ CurrentType++;
+ }
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VarSize,
+ OriginalPtr
+ );
+
+ FreePool (OriginalPtr);
+ return Status;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp> format.
+ @param Progress A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ LEGACY_BOOT_NV_DATA *CurrentNVMapData;
+ UINTN BufferSize;
+
+
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: there is no name for Name/Value storage, only GUID will be checked
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &mLegacyBootOptionGuid, mLegacyBootStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID **) &ConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ CurrentNVMapData = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
+ Status = ConfigRouting->ConfigToBlock (
+ ConfigRouting,
+ Configuration,
+ (UINT8 *) CurrentNVMapData,
+ &BufferSize,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = UpdateBBSOption (CurrentNVMapData);
+
+ return Status;
+}
+
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+RefreshLegacyUpdateData (
+ VOID
+ )
+{
+ //
+ // Free current updated date
+ //
+ if (mLegacyStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mLegacyStartOpCodeHandle);
+ }
+ if (mLegacyEndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mLegacyEndOpCodeHandle);
+ }
+
+ //
+ // Create new OpCode Handle
+ //
+ mLegacyStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ mLegacyEndOpCodeHandle = HiiAllocateOpCodeHandle ();
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mLegacyStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mLegacyStartOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mLegacyStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ mLegacyStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mLegacyEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (
+ mLegacyEndOpCodeHandle,
+ &gEfiIfrTianoGuid,
+ NULL,
+ sizeof (EFI_IFR_GUID_LABEL)
+ );
+ mLegacyEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ mLegacyEndLabel->Number = FORM_BOOT_LEGACY_LABEL_END;
+
+}
+
+/**
+ Get the Menu Entry from the list in Menu Entry List.
+
+ If MenuNumber is great or equal to the number of Menu
+ Entry in the list, then ASSERT.
+
+ @param MenuOption The Menu Entry List to read the menu entry.
+ @param MenuNumber The index of Menu Entry.
+
+ @return The Menu Entry.
+
+**/
+LEGACY_MENU_ENTRY *
+GetMenuEntry (
+ LEGACY_MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ )
+{
+ LEGACY_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+ LIST_ENTRY *List;
+
+ ASSERT (MenuNumber < MenuOption->MenuNumber);
+
+ List = MenuOption->Head.ForwardLink;
+ for (Index = 0; Index < MenuNumber; Index++) {
+ List = List->ForwardLink;
+ }
+
+ NewMenuEntry = CR (List, LEGACY_MENU_ENTRY, Link, LEGACY_MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+/**
+ Create string tokens for a menu from its help strings and display strings
+
+ @param HiiHandle Hii Handle of the package to be updated.
+ @param MenuOption The Menu whose string tokens need to be created
+
+**/
+VOID
+CreateLegacyMenuStringToken (
+ IN EFI_HII_HANDLE HiiHandle,
+ IN LEGACY_MENU_OPTION *MenuOption
+ )
+{
+ LEGACY_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (MenuOption, Index);
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->DisplayString,
+ NULL
+ );
+
+ if (NULL == NewMenuEntry->HelpString) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ NewMenuEntry->HelpStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->HelpString,
+ NULL
+ );
+ }
+ }
+}
+
+/**
+ Create a dynamic page so that Legacy Device boot order
+ can be set for specified device type.
+
+ @param UpdatePageId The form ID. It also spefies the legacy device type.
+
+
+**/
+VOID
+UpdateLegacyDeviceOrderPage (
+ IN UINT16 UpdatePageId
+ )
+{
+ LEGACY_MENU_OPTION *OptionMenu;
+ LEGACY_MENU_ENTRY *NewMenuEntry;
+ EFI_STRING_ID StrRef;
+ EFI_STRING_ID StrRefHelp;
+ UINT16 *Default;
+ UINT16 Index;
+ UINT16 Key;
+ CHAR16 String[100];
+ CHAR16 *TypeStr;
+ CHAR16 *TypeStrHelp;
+ CHAR16 *FormTitle;
+ VOID *OptionsOpCodeHandle;
+ VOID *DefaultOpCodeHandle;
+
+ Key = 0;
+ StrRef = 0;
+ StrRefHelp = 0;
+ OptionMenu = NULL;
+ TypeStr = NULL;
+ TypeStrHelp = NULL;
+ Default = NULL;
+
+ RefreshLegacyUpdateData();
+
+ //
+ // Create oneof option list
+ //
+ switch (UpdatePageId) {
+ case FORM_FLOPPY_BOOT_ID:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyFDMenu;
+ Key = (UINT16) LEGACY_FD_QUESTION_ID;
+ TypeStr = STR_FLOPPY;
+ TypeStrHelp = STR_FLOPPY_HELP;
+ FormTitle = STR_FLOPPY_TITLE;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyFD;
+ break;
+
+ case FORM_HARDDISK_BOOT_ID:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyHDMenu;
+ Key = (UINT16) LEGACY_HD_QUESTION_ID;
+ TypeStr = STR_HARDDISK;
+ TypeStrHelp = STR_HARDDISK_HELP;
+ FormTitle = STR_HARDDISK_TITLE;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyHD;
+ break;
+
+ case FORM_CDROM_BOOT_ID:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyCDMenu;
+ Key = (UINT16) LEGACY_CD_QUESTION_ID;
+ TypeStr = STR_CDROM;
+ TypeStrHelp = STR_CDROM_HELP;
+ FormTitle = STR_CDROM_TITLE;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyCD;
+ break;
+
+ case FORM_NET_BOOT_ID:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyNETMenu;
+ Key = (UINT16) LEGACY_NET_QUESTION_ID;
+ TypeStr = STR_NET;
+ TypeStrHelp = STR_NET_HELP;
+ FormTitle = STR_NET_TITLE;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyNET;
+ break;
+
+ case FORM_BEV_BOOT_ID:
+ OptionMenu = (LEGACY_MENU_OPTION *) &LegacyBEVMenu;
+ Key = (UINT16) LEGACY_BEV_QUESTION_ID;
+ TypeStr = STR_BEV;
+ TypeStrHelp = STR_BEV_HELP;
+ FormTitle = STR_BEV_TITLE;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData.LegacyBEV;
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n"));
+ return;
+ }
+
+ HiiSetString (mLegacyBootOptionPrivate->HiiHandle, STRING_TOKEN(STR_ORDER_CHANGE_PROMPT), FormTitle, NULL);
+
+ CreateLegacyMenuStringToken (mLegacyBootOptionPrivate->HiiHandle, OptionMenu);
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = GetMenuEntry (OptionMenu, Index);
+ //
+ // Create OneOf for each legacy device
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ ((LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex
+ );
+ }
+
+ //
+ // Create OneOf for item "Disabled"
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE),
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ 0xFF
+ );
+
+ //
+ // Create oneof tag here for FD/HD/CD #1 #2
+ //
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (DefaultOpCodeHandle != NULL);
+
+ HiiCreateDefaultOpCode (
+ DefaultOpCodeHandle,
+ EFI_HII_DEFAULT_CLASS_STANDARD,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ *Default++
+ );
+
+ //
+ // Create the string for oneof tag
+ //
+ UnicodeSPrint (String, sizeof (String), TypeStr, Index);
+ StrRef = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
+
+ UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
+ StrRefHelp = HiiSetString (mLegacyBootOptionPrivate->HiiHandle, 0, String, NULL);
+
+ HiiCreateOneOfOpCode (
+ mLegacyStartOpCodeHandle,
+ (EFI_QUESTION_ID) (Key + Index),
+ VARSTORE_ID_LEGACY_BOOT,
+ (UINT16) (Key + Index * 2 - CONFIG_OPTION_OFFSET),
+ StrRef,
+ StrRefHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_2,
+ OptionsOpCodeHandle,
+ DefaultOpCodeHandle //NULL //
+ );
+
+ HiiFreeOpCodeHandle (DefaultOpCodeHandle);
+ }
+
+ HiiUpdateForm (
+ mLegacyBootOptionPrivate->HiiHandle,
+ &mLegacyBootOptionGuid,
+ LEGACY_ORDER_CHANGE_FORM_ID,
+ mLegacyStartOpCodeHandle,
+ mLegacyEndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+}
+
+
+/**
+ Adjust question value when one question value has been changed.
+
+ @param QuestionId The question id for the value changed question.
+ @param Value The value for the changed question.
+
+**/
+VOID
+AdjustOptionValue (
+ IN UINT16 QuestionId,
+ IN EFI_IFR_TYPE_VALUE *Value
+ )
+{
+ UINTN Number;
+ UINT16 *Default;
+ LEGACY_BOOT_NV_DATA *CurrentNVMap;
+ UINT16 *CurrentVal;
+ UINTN Index;
+ UINTN Index2;
+ UINTN Index3;
+ UINTN NewValuePos;
+ UINTN OldValue;
+ UINTN NewValue;
+ UINT8 *DisMap;
+ UINTN Pos;
+ UINTN Bit;
+
+ Number = 0;
+ CurrentVal = 0;
+ Default = NULL;
+ NewValue = 0;
+ NewValuePos = 0;
+ OldValue = 0;
+
+ //
+ // Update Select FD/HD/CD/NET/BEV Order Form
+ //
+ ASSERT ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER));
+
+ CurrentNVMap = &mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData;
+ HiiGetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap);
+ DisMap = mLegacyBootOptionPrivate->MaintainMapData->DisableMap;
+
+ if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyFDMenu.MenuNumber;
+ CurrentVal = CurrentNVMap->LegacyFD;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyFD;
+ } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyHDMenu.MenuNumber;
+ CurrentVal = CurrentNVMap->LegacyHD;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyHD;
+ } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyCDMenu.MenuNumber;
+ CurrentVal = CurrentNVMap->LegacyCD;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyCD;
+ } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyNETMenu.MenuNumber;
+ CurrentVal = CurrentNVMap->LegacyNET;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyNET;
+ } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyBEVMenu.MenuNumber;
+ CurrentVal = CurrentNVMap->LegacyBEV;
+ Default = mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData.LegacyBEV;
+ }
+
+ //
+ // First, find the different position
+ // if there is change, it should be only one
+ //
+ for (Index = 0; Index < Number; Index++) {
+ if (CurrentVal[Index] != Default[Index]) {
+ OldValue = Default[Index];
+ NewValue = CurrentVal[Index];
+ break;
+ }
+ }
+
+ if (Index != Number) {
+ //
+ // there is change, now process
+ //
+ if (0xFF == NewValue) {
+ //
+ // This item will be disable
+ // Just move the items behind this forward to overlap it
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ for (Index2 = Index; Index2 < Number - 1; Index2++) {
+ CurrentVal[Index2] = CurrentVal[Index2 + 1];
+ }
+
+ CurrentVal[Index2] = 0xFF;
+ } else {
+ for (Index2 = 0; Index2 < Number; Index2++) {
+ if (Index2 == Index) {
+ continue;
+ }
+
+ if (Default[Index2] == NewValue) {
+ //
+ // If NewValue is in OldLegacyDev array
+ // remember its old position
+ //
+ NewValuePos = Index2;
+ break;
+ }
+ }
+
+ if (Index2 != Number) {
+ //
+ // We will change current item to an existing item
+ // (It's hard to describe here, please read code, it's like a cycle-moving)
+ //
+ for (Index2 = NewValuePos; Index2 != Index;) {
+ if (NewValuePos < Index) {
+ CurrentVal[Index2] = Default[Index2 + 1];
+ Index2++;
+ } else {
+ CurrentVal[Index2] = Default[Index2 - 1];
+ Index2--;
+ }
+ }
+ } else {
+ //
+ // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
+ // so we should modify DisMap to reflect the change
+ //
+ Pos = NewValue / 8;
+ Bit = 7 - (NewValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
+ if (0xFF != OldValue) {
+ //
+ // Because NewValue is a item that was disabled before
+ // so after changing the OldValue should be disabled
+ // actually we are doing a swap of enable-disable states of two items
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ }
+ }
+ }
+ //
+ // To prevent DISABLE appears in the middle of the list
+ // we should perform a re-ordering
+ //
+ Index3 = Index;
+ Index = 0;
+ while (Index < Number) {
+ if (0xFF != CurrentVal[Index]) {
+ Index++;
+ continue;
+ }
+
+ Index2 = Index;
+ Index2++;
+ while (Index2 < Number) {
+ if (0xFF != CurrentVal[Index2]) {
+ break;
+ }
+
+ Index2++;
+ }
+
+ if (Index2 < Number) {
+ CurrentVal[Index] = CurrentVal[Index2];
+ CurrentVal[Index2] = 0xFF;
+ }
+
+ Index++;
+ }
+
+ //
+ // Return correct question value.
+ //
+ Value->u16 = CurrentVal[Index3];
+ CopyMem (Default, CurrentVal, sizeof (UINT16) * Number);
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ HiiSetBrowserData (&mLegacyBootOptionGuid, mLegacyBootStorageName, sizeof (LEGACY_BOOT_NV_DATA), (UINT8 *) CurrentNVMap, NULL);
+}
+
+/**
+ This call back function is registered with Boot Manager formset.
+ When user selects a boot option, this call back function will
+ be triggered. The boot option is saved for later processing.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action != EFI_BROWSER_ACTION_CHANGED && Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // Do nothing for other UEFI Action. Only do call back when data is changed.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ switch (QuestionId) {
+ case FORM_FLOPPY_BOOT_ID:
+ case FORM_HARDDISK_BOOT_ID:
+ case FORM_CDROM_BOOT_ID:
+ case FORM_NET_BOOT_ID:
+ case FORM_BEV_BOOT_ID:
+ UpdateLegacyDeviceOrderPage (QuestionId);
+ break;
+
+ default:
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
+ AdjustOptionValue(QuestionId, Value);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Create a menu entry by given menu type.
+
+ @param MenuType The Menu type to be created.
+
+ @retval NULL If failed to create the menu.
+ @return the new menu entry.
+
+**/
+LEGACY_MENU_ENTRY *
+CreateMenuEntry (
+ VOID
+ )
+{
+ LEGACY_MENU_ENTRY *MenuEntry;
+
+ //
+ // Create new menu entry
+ //
+ MenuEntry = AllocateZeroPool (sizeof (LEGACY_MENU_ENTRY));
+ if (MenuEntry == NULL) {
+ return NULL;
+ }
+
+ MenuEntry->VariableContext = AllocateZeroPool (sizeof (LEGACY_DEVICE_CONTEXT));
+ if (MenuEntry->VariableContext == NULL) {
+ FreePool (MenuEntry);
+ return NULL;
+ }
+
+ MenuEntry->Signature = LEGACY_MENU_ENTRY_SIGNATURE;
+ return MenuEntry;
+}
+
+/**
+
+ Base on the L"LegacyDevOrder" variable to build the current order data.
+
+**/
+VOID
+GetLegacyOptionsOrder (
+ VOID
+ )
+{
+ UINTN VarSize;
+ UINT8 *VarData;
+ UINT8 *VarTmp;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ UINT16 *LegacyDev;
+ UINTN Index;
+ LEGACY_MENU_OPTION *OptionMenu;
+ UINT16 VarDevOrder;
+ UINTN Pos;
+ UINTN Bit;
+ UINT8 *DisMap;
+ UINTN TotalLength;
+
+ LegacyDev = NULL;
+ OptionMenu = NULL;
+
+ DisMap = ZeroMem (mLegacyBootOptionPrivate->MaintainMapData->DisableMap, sizeof (mLegacyBootOptionPrivate->MaintainMapData->DisableMap));
+
+ //
+ // Get Device Order from variable
+ //
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &VarData, &VarSize);
+ VarTmp = VarData;
+ if (NULL != VarData) {
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ while (VarData < VarTmp + VarSize) {
+ switch (DevOrder->BbsType) {
+ case BBS_FLOPPY:
+ LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyFD;
+ OptionMenu = &LegacyFDMenu;
+ break;
+
+ case BBS_HARDDISK:
+ LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyHD;
+ OptionMenu = &LegacyHDMenu;
+ break;
+
+ case BBS_CDROM:
+ LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyCD;
+ OptionMenu = &LegacyCDMenu;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyNET;
+ OptionMenu = &LegacyNETMenu;
+ break;
+
+ case BBS_BEV_DEVICE:
+ LegacyDev = mLegacyBootOptionPrivate->MaintainMapData->InitialNvData.LegacyBEV;
+ OptionMenu = &LegacyBEVMenu;
+ break;
+
+ case BBS_UNKNOWN:
+ default:
+ ASSERT (FALSE);
+ DEBUG ((DEBUG_ERROR, "Unsupported device type found!\n"));
+ break;
+ }
+
+ //
+ // Create oneof tag here for FD/HD/CD #1 #2
+ //
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ TotalLength = sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16);
+ VarDevOrder = *(UINT16 *) ((UINT8 *) DevOrder + TotalLength);
+
+ if (0xFF00 == (VarDevOrder & 0xFF00)) {
+ LegacyDev[Index] = 0xFF;
+ Pos = (VarDevOrder & 0xFF) / 8;
+ Bit = 7 - ((VarDevOrder & 0xFF) % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ } else {
+ LegacyDev[Index] = VarDevOrder & 0xFF;
+ }
+ }
+
+ VarData ++;
+ VarData += *(UINT16 *) VarData;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ }
+ }
+
+ CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->LastTimeNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
+ CopyMem (&mLegacyBootOptionPrivate->MaintainMapData->CurrentNvData, &mLegacyBootOptionPrivate->MaintainMapData->InitialNvData, sizeof (LEGACY_BOOT_NV_DATA));
+}
+
+/**
+
+ Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
+
+**/
+VOID
+GetLegacyOptions (
+ VOID
+ )
+{
+ LEGACY_MENU_ENTRY *NewMenuEntry;
+ LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ UINT16 Index;
+ UINTN FDNum;
+ UINTN HDNum;
+ UINTN CDNum;
+ UINTN NETNum;
+ UINTN BEVNum;
+
+ //
+ // Initialize Bbs Table Context from BBS info data
+ //
+ InitializeListHead (&LegacyFDMenu.Head);
+ InitializeListHead (&LegacyHDMenu.Head);
+ InitializeListHead (&LegacyCDMenu.Head);
+ InitializeListHead (&LegacyNETMenu.Head);
+ InitializeListHead (&LegacyBEVMenu.Head);
+
+ FDNum = 0;
+ HDNum = 0;
+ CDNum = 0;
+ NETNum = 0;
+ BEVNum = 0;
+
+ EfiBootManagerConnectAll ();
+
+ //
+ // for better user experience
+ // 1. User changes HD configuration (e.g.: unplug HDD), here we have a chance to remove the HDD boot option
+ // 2. User enables/disables UEFI PXE, here we have a chance to add/remove EFI Network boot option
+ //
+ EfiBootManagerRefreshAllBootOption ();
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)
+ ) {
+ continue;
+ }
+ ASSERT (BootOption[Index].OptionalDataSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
+ NewMenuEntry = CreateMenuEntry ();
+ ASSERT (NewMenuEntry != NULL);
+
+ NewLegacyDevContext = (LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLegacyDevContext->BbsIndex = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex;
+ NewLegacyDevContext->Description = AllocateCopyPool (StrSize (BootOption[Index].Description), BootOption[Index].Description);
+ ASSERT (NewLegacyDevContext->Description != NULL);
+
+ NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
+ NewMenuEntry->HelpString = NULL;
+
+ switch (((BBS_BBS_DEVICE_PATH *) BootOption[Index].FilePath)->DeviceType) {
+ case BBS_TYPE_FLOPPY:
+ InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
+ FDNum++;
+ break;
+
+ case BBS_TYPE_HARDDRIVE:
+ InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
+ HDNum++;
+ break;
+
+ case BBS_TYPE_CDROM:
+ InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
+ CDNum++;
+ break;
+
+ case BBS_TYPE_EMBEDDED_NETWORK:
+ InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
+ NETNum++;
+ break;
+
+ case BBS_TYPE_BEV:
+ InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
+ BEVNum++;
+ break;
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+ LegacyFDMenu.MenuNumber = FDNum;
+ LegacyHDMenu.MenuNumber = HDNum;
+ LegacyCDMenu.MenuNumber = CDNum;
+ LegacyNETMenu.MenuNumber = NETNum;
+ LegacyBEVMenu.MenuNumber = BEVNum;
+}
+
+
+/**
+
+ Install Boot Manager Menu driver.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS Install Boot manager menu success.
+ @retval Other Return error status.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootMaintUiLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ LEGACY_BOOT_OPTION_CALLBACK_DATA *LegacyBootOptionData;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Create LegacyBootOptionData structures for Driver Callback
+ //
+ LegacyBootOptionData = AllocateZeroPool (sizeof (LEGACY_BOOT_OPTION_CALLBACK_DATA));
+ ASSERT (LegacyBootOptionData != NULL);
+
+ LegacyBootOptionData->MaintainMapData = AllocateZeroPool (sizeof (LEGACY_BOOT_MAINTAIN_DATA));
+ ASSERT (LegacyBootOptionData->MaintainMapData != NULL);
+
+ LegacyBootOptionData->ConfigAccess.ExtractConfig = LegacyBootOptionExtractConfig;
+ LegacyBootOptionData->ConfigAccess.RouteConfig = LegacyBootOptionRouteConfig;
+ LegacyBootOptionData->ConfigAccess.Callback = LegacyBootOptionCallback;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &LegacyBootOptionData->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mLegacyBootOptionHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &LegacyBootOptionData->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ LegacyBootOptionData->HiiHandle = HiiAddPackages (
+ &mLegacyBootOptionGuid,
+ LegacyBootOptionData->DriverHandle,
+ LegacyBootMaintUiVfrBin,
+ LegacyBootMaintUiLibStrings,
+ NULL
+ );
+ ASSERT (LegacyBootOptionData->HiiHandle != NULL);
+
+ mLegacyBootOptionPrivate = LegacyBootOptionData;
+
+ GetLegacyOptions ();
+
+ GetLegacyOptionsOrder();
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Destructor of Customized Display Library Instance.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The destructor completed successfully.
+ @retval Other value The destructor did not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootMaintUiLibDestructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (mLegacyBootOptionPrivate->DriverHandle != NULL) {
+ Status = gBS->UninstallMultipleProtocolInterfaces (
+ mLegacyBootOptionPrivate->DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mLegacyBootOptionHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &mLegacyBootOptionPrivate->ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HiiRemovePackages (mLegacyBootOptionPrivate->HiiHandle);
+
+ FreePool (mLegacyBootOptionPrivate->MaintainMapData);
+ FreePool (mLegacyBootOptionPrivate);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.h b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.h
new file mode 100644
index 0000000000..86ea8eba7a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUi.h
@@ -0,0 +1,255 @@
+/** @file
+ Legacy boot maintainence Ui definition.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_LEGACY_BOOT_OPTION_H_
+#define _EFI_LEGACY_BOOT_OPTION_H_
+
+#include <PiDxe.h>
+
+
+#include <Guid/GlobalVariable.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/MdeModuleHii.h>
+
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/HiiConfigRouting.h>
+
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/LegacyBios.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/DebugLib.h>
+#include <Library/HiiLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/BaseMemoryLib.h>
+
+#include "LegacyBootMaintUiVfr.h"
+
+#define CONFIG_OPTION_OFFSET 0x1200
+
+//
+// VarOffset that will be used to create question
+// all these values are computed from the structure
+// defined below
+//
+#define VAR_OFFSET(Field) ((UINT16) ((UINTN) &(((LEGACY_BOOT_NV_DATA *) 0)->Field)))
+
+//
+// Question Id of Zero is invalid, so add an offset to it
+//
+#define QUESTION_ID(Field) (VAR_OFFSET (Field) + CONFIG_OPTION_OFFSET)
+
+
+#define LEGACY_FD_QUESTION_ID QUESTION_ID (LegacyFD)
+#define LEGACY_HD_QUESTION_ID QUESTION_ID (LegacyHD)
+#define LEGACY_CD_QUESTION_ID QUESTION_ID (LegacyCD)
+#define LEGACY_NET_QUESTION_ID QUESTION_ID (LegacyNET)
+#define LEGACY_BEV_QUESTION_ID QUESTION_ID (LegacyBEV)
+
+
+//
+// String Contant
+//
+#define STR_FLOPPY L"Floppy Drive #%02x"
+#define STR_HARDDISK L"HardDisk Drive #%02x"
+#define STR_CDROM L"ATAPI CDROM Drive #%02x"
+#define STR_NET L"NET Drive #%02x"
+#define STR_BEV L"BEV Drive #%02x"
+
+#define STR_FLOPPY_HELP L"Select Floppy Drive #%02x"
+#define STR_HARDDISK_HELP L"Select HardDisk Drive #%02x"
+#define STR_CDROM_HELP L"Select ATAPI CDROM Drive #%02x"
+#define STR_NET_HELP L"NET Drive #%02x"
+#define STR_BEV_HELP L"BEV Drive #%02x"
+
+#define STR_FLOPPY_TITLE L"Set Legacy Floppy Drive Order"
+#define STR_HARDDISK_TITLE L"Set Legacy HardDisk Drive Order"
+#define STR_CDROM_TITLE L"Set Legacy CDROM Drive Order"
+#define STR_NET_TITLE L"Set Legacy NET Drive Order"
+#define STR_BEV_TITLE L"Set Legacy BEV Drive Order"
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 LegacyBootMaintUiVfrBin[];
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+
+
+//
+// Variable created with this flag will be "Efi:...."
+//
+#define VAR_FLAG EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE
+
+
+#define LEGACY_BOOT_OPTION_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('L', 'G', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+
+ //
+ // Maintain the data.
+ //
+ LEGACY_BOOT_MAINTAIN_DATA *MaintainMapData;
+} LEGACY_BOOT_OPTION_CALLBACK_DATA;
+
+//
+// All of the signatures that will be used in list structure
+//
+#define LEGACY_MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u')
+#define LEGACY_MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r')
+
+#define LEGACY_LEGACY_DEV_CONTEXT_SELECT 0x9
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+} LEGACY_MENU_OPTION;
+
+typedef struct {
+ UINT16 BbsIndex;
+ CHAR16 *Description;
+} LEGACY_DEVICE_CONTEXT;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINTN OptionNumber;
+ UINT16 *DisplayString;
+ UINT16 *HelpString;
+ EFI_STRING_ID DisplayStringToken;
+ EFI_STRING_ID HelpStringToken;
+ VOID *VariableContext;
+} LEGACY_MENU_ENTRY;
+
+typedef struct {
+ UINT16 BbsIndex;
+} LEGACY_BOOT_OPTION_BBS_DATA;
+
+#pragma pack()
+
+/**
+ This call back function is registered with Boot Manager formset.
+ When user selects a boot option, this call back function will
+ be triggered. The boot option is saved for later processing.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request - A null-terminated Unicode string in <ConfigRequest> format.
+ @param Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ @param Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootOptionRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
new file mode 100644
index 0000000000..17c9cac811
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.inf
@@ -0,0 +1,69 @@
+## @file
+# Legacy Boot Maintainence UI module is library for BDS phase.
+#
+# Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBootMaintUiLib
+ MODULE_UNI_FILE = LegacyBootMaintUiLib.uni
+ FILE_GUID = e6f7f038-3ed9-401a-af1f-5ea7bf644d34
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = LegacyBootMaintUiLibConstructor
+ DESTRUCTOR = LegacyBootMaintUiLibDestructor
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ LegacyBootMaintUiVfr.h
+ LegacyBootMaintUi.h
+ LegacyBootMaintUiVfr.Vfr
+ LegacyBootMaintUiStrings.uni
+ LegacyBootMaintUi.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ DebugLib
+ HiiLib
+ MemoryAllocationLib
+ UefiBootManagerLib
+ UefiLib
+ PrintLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Extended IFR Guid Opcode
+ gEfiIfrBootMaintenanceGuid ## CONSUMES ## HII # BootMaint HII Package
+ gEfiLegacyDevOrderVariableGuid ## PRODUCES ## Variable:L"LegacyDevOrder"
+
+[Protocols]
+ gEfiHiiConfigAccessProtocolGuid ## PRODUCES
+ gEfiLegacyBiosProtocolGuid ## CONSUMES
+ gEfiHiiConfigRoutingProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiHiiDatabaseProtocolGuid
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni
new file mode 100644
index 0000000000..892d6e218e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni
new file mode 100644
index 0000000000..dbec69bfd6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr
new file mode 100644
index 0000000000..882da99f9e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.Vfr
@@ -0,0 +1,73 @@
+///** @file
+//
+// Browser formset.
+//
+// Copyright (c) 2015, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include "LegacyBootMaintUiVfr.h"
+
+
+formset
+ guid = LEGACY_BOOT_OPTION_FORMSET_GUID,
+ title = STRING_TOKEN(STR_LEGACY_BOOT_PROMPT),
+ help = STRING_TOKEN(STR_LEGACY_BOOT_HELP),
+ classguid = EFI_IFR_BOOT_MAINTENANCE_GUID,
+
+ varstore LEGACY_BOOT_NV_DATA,
+ varid = VARSTORE_ID_LEGACY_BOOT,
+ name = LegacyBootData,
+ guid = LEGACY_BOOT_OPTION_FORMSET_GUID;
+
+ form formid = LEGACY_BOOT_FORM_ID,
+ title = STRING_TOKEN(STR_LEGACY_BOOT_PROMPT);
+
+ goto LEGACY_ORDER_CHANGE_FORM_ID,
+ prompt = STRING_TOKEN(STR_FORM_FLOPPY_BOOT_TITLE),
+ help = STRING_TOKEN(STR_FORM_FLOPPY_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_FLOPPY_BOOT_ID;
+
+ goto LEGACY_ORDER_CHANGE_FORM_ID,
+ prompt = STRING_TOKEN(STR_FORM_HARDDISK_BOOT_TITLE),
+ help = STRING_TOKEN(STR_FORM_HARDDISK_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_HARDDISK_BOOT_ID;
+
+ goto LEGACY_ORDER_CHANGE_FORM_ID,
+ prompt = STRING_TOKEN(STR_FORM_CDROM_BOOT_TITLE),
+ help = STRING_TOKEN(STR_FORM_CDROM_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CDROM_BOOT_ID;
+
+ goto LEGACY_ORDER_CHANGE_FORM_ID,
+ prompt = STRING_TOKEN(STR_FORM_NET_BOOT_TITLE),
+ help = STRING_TOKEN(STR_FORM_NET_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_NET_BOOT_ID;
+
+ goto LEGACY_ORDER_CHANGE_FORM_ID,
+ prompt = STRING_TOKEN(STR_FORM_BEV_BOOT_TITLE),
+ help = STRING_TOKEN(STR_FORM_BEV_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BEV_BOOT_ID;
+
+ endform;
+
+ form formid = LEGACY_ORDER_CHANGE_FORM_ID,
+ title = STRING_TOKEN(STR_ORDER_CHANGE_PROMPT);
+
+ label FORM_BOOT_LEGACY_DEVICE_ID;
+ label FORM_BOOT_LEGACY_LABEL_END;
+
+ endform;
+
+endformset;
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h
new file mode 100644
index 0000000000..713ea4c640
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootMaintUiLib/LegacyBootMaintUiVfr.h
@@ -0,0 +1,85 @@
+/** @file
+ Legacy Boot Maintainence UI definition.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _EFI_LEGACY_BOOT_OPTION_VFR_H_
+#define _EFI_LEGACY_BOOT_OPTION_VFR_H_
+
+#include <Guid/HiiBootMaintenanceFormset.h>
+
+#define MAX_MENU_NUMBER 100
+
+#define LEGACY_BOOT_OPTION_FORMSET_GUID { 0x6bc75598, 0x89b4, 0x483d, { 0x91, 0x60, 0x7f, 0x46, 0x9a, 0x96, 0x35, 0x31 } }
+
+#define VARSTORE_ID_LEGACY_BOOT 0x0001
+
+
+#define LEGACY_BOOT_FORM_ID 0x1000
+#define LEGACY_ORDER_CHANGE_FORM_ID 0x1001
+
+
+#define FORM_FLOPPY_BOOT_ID 0x2000
+#define FORM_HARDDISK_BOOT_ID 0x2001
+#define FORM_CDROM_BOOT_ID 0x2002
+#define FORM_NET_BOOT_ID 0x2003
+#define FORM_BEV_BOOT_ID 0x2004
+
+
+
+#define FORM_BOOT_LEGACY_DEVICE_ID 0x9000
+#define FORM_BOOT_LEGACY_LABEL_END 0x9001
+
+
+#pragma pack(1)
+
+///
+/// This is the structure that will be used to store the
+/// question's current value. Use it at initialize time to
+/// set default value for each question. When using at run
+/// time, this map is returned by the callback function,
+/// so dynamically changing the question's value will be
+/// possible through this mechanism
+///
+typedef struct {
+ //
+ // Legacy Device Order Selection Storage
+ //
+ UINT16 LegacyFD[MAX_MENU_NUMBER];
+ UINT16 LegacyHD[MAX_MENU_NUMBER];
+ UINT16 LegacyCD[MAX_MENU_NUMBER];
+ UINT16 LegacyNET[MAX_MENU_NUMBER];
+ UINT16 LegacyBEV[MAX_MENU_NUMBER];
+} LEGACY_BOOT_NV_DATA;
+
+///
+/// This is the structure that will be used to store the
+/// question's current value. Use it at initialize time to
+/// set default value for each question. When using at run
+/// time, this map is returned by the callback function,
+/// so dynamically changing the question's value will be
+/// possible through this mechanism
+///
+typedef struct {
+ //
+ // Legacy Device Order Selection Storage
+ //
+ LEGACY_BOOT_NV_DATA InitialNvData;
+ LEGACY_BOOT_NV_DATA CurrentNvData;
+ LEGACY_BOOT_NV_DATA LastTimeNvData;
+ UINT8 DisableMap[32];
+} LEGACY_BOOT_MAINTAIN_DATA;
+
+#pragma pack()
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
new file mode 100644
index 0000000000..e7bdde9def
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/InternalLegacyBm.h
@@ -0,0 +1,66 @@
+/** @file
+
+Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _INTERNAL_LEGACY_BM_H_
+#define _INTERNAL_LEGACY_BM_H_
+
+#include <PiDxe.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/GlobalVariable.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/PciRootBridgeIo.h>
+#include <Protocol/PciIo.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiBootManagerLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PerformanceLib.h>
+
+#pragma pack(1)
+typedef struct {
+ UINT16 BbsIndex;
+} LEGACY_BM_BOOT_OPTION_BBS_DATA;
+#pragma pack()
+
+/**
+ Boot the legacy system with the boot option.
+
+ @param BootOption The legacy boot option which have BBS device path
+ On return, BootOption->Status contains the boot status.
+ EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ EFI_STATUS The status of LegacyBios->LegacyBoot ().
+**/
+VOID
+EFIAPI
+LegacyBmBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ );
+
+/**
+ Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBmRefreshAllBootOption (
+ VOID
+ );
+
+#endif // _INTERNAL_LEGACY_BM_H_ \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c
new file mode 100644
index 0000000000..d3b48e8d0b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBm.c
@@ -0,0 +1,1536 @@
+/** @file
+ This function deal with the legacy boot option, it create, delete
+ and manage the legacy boot option, all legacy boot option is getting from
+ the legacy BBS table.
+
+Copyright (c) 2011 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "InternalLegacyBm.h"
+
+#define LEGACY_BM_BOOT_DESCRIPTION_LENGTH 32
+
+/**
+ Initialize legacy boot manager library by call EfiBootManagerRegisterLegacyBootSupport
+ function to export two function pointer.
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCCESS The legacy boot manager library is initialized correctly.
+ @return Other value if failed to initialize the legacy boot manager library.
+**/
+EFI_STATUS
+EFIAPI
+LegacyBootManagerLibConstructor (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+)
+{
+ EfiBootManagerRegisterLegacyBootSupport (
+ LegacyBmRefreshAllBootOption,
+ LegacyBmBoot
+ );
+ return EFI_SUCCESS;
+}
+
+/**
+ Get the device type from the input legacy device path.
+
+ @param DevicePath The legacy device path.
+
+ @retval The legacy device type.
+**/
+UINT16
+LegacyBmDeviceType (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT ((DevicePathType (DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == BBS_BBS_DP));
+ return ((BBS_BBS_DEVICE_PATH *) DevicePath)->DeviceType;
+}
+
+/**
+ Validate the BbsEntry base on the Boot Priority info in the BbsEntry.
+
+ @param BbsEntry The input bbs entry info.
+
+ @retval TRUE The BbsEntry is valid.
+ @retval FALSE The BbsEntry is invalid.
+**/
+BOOLEAN
+LegacyBmValidBbsEntry (
+ IN BBS_TABLE *BbsEntry
+ )
+{
+ switch (BbsEntry->BootPriority) {
+ case BBS_IGNORE_ENTRY:
+ case BBS_DO_NOT_BOOT_FROM:
+ case BBS_LOWEST_PRIORITY:
+ return FALSE;
+ default:
+ return TRUE;
+ }
+}
+
+/**
+ Build Legacy Device Name String according.
+
+ @param CurBBSEntry BBS Table.
+ @param Index Index.
+ @param BufSize The buffer size.
+ @param BootString The output string.
+
+**/
+VOID
+LegacyBmBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ )
+{
+ CHAR16 *Fmt;
+ CHAR16 *Type;
+ CHAR8 *StringDesc;
+ CHAR8 StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ CHAR16 StringBufferU[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+
+ switch (Index) {
+ //
+ // Primary Master
+ //
+ case 1:
+ Fmt = L"Primary Master %s";
+ break;
+
+ //
+ // Primary Slave
+ //
+ case 2:
+ Fmt = L"Primary Slave %s";
+ break;
+
+ //
+ // Secondary Master
+ //
+ case 3:
+ Fmt = L"Secondary Master %s";
+ break;
+
+ //
+ // Secondary Slave
+ //
+ case 4:
+ Fmt = L"Secondary Slave %s";
+ break;
+
+ default:
+ Fmt = L"%s";
+ break;
+ }
+
+ switch (CurBBSEntry->DeviceType) {
+ case BBS_FLOPPY:
+ Type = L"Floppy";
+ break;
+
+ case BBS_HARDDISK:
+ Type = L"Harddisk";
+ break;
+
+ case BBS_CDROM:
+ Type = L"CDROM";
+ break;
+
+ case BBS_PCMCIA:
+ Type = L"PCMCIAe";
+ break;
+
+ case BBS_USB:
+ Type = L"USB";
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Type = L"Network";
+ break;
+
+ case BBS_BEV_DEVICE:
+ Type = L"BEVe";
+ break;
+
+ case BBS_UNKNOWN:
+ default:
+ Type = L"Unknown";
+ break;
+ }
+ //
+ // If current BBS entry has its description then use it.
+ //
+ StringDesc = (CHAR8 *) (UINTN) ((CurBBSEntry->DescStringSegment << 4) + CurBBSEntry->DescStringOffset);
+ if (NULL != StringDesc) {
+ //
+ // Only get fisrt 32 characters, this is suggested by BBS spec
+ //
+ CopyMem (StringBufferA, StringDesc, LEGACY_BM_BOOT_DESCRIPTION_LENGTH);
+ StringBufferA[LEGACY_BM_BOOT_DESCRIPTION_LENGTH] = 0;
+ AsciiStrToUnicodeStrS (StringBufferA, StringBufferU, sizeof (StringBufferU) / sizeof (StringBufferU[0]));
+ Fmt = L"%s";
+ Type = StringBufferU;
+ }
+
+ //
+ // BbsTable 16 entries are for onboard IDE.
+ // Set description string for SATA harddisks, Harddisk 0 ~ Harddisk 11
+ //
+ if (Index >= 5 && Index <= 16 && (CurBBSEntry->DeviceType == BBS_HARDDISK || CurBBSEntry->DeviceType == BBS_CDROM)) {
+ Fmt = L"%s %d";
+ UnicodeSPrint (BootString, BufSize, Fmt, Type, Index - 5);
+ } else {
+ UnicodeSPrint (BootString, BufSize, Fmt, Type);
+ }
+}
+
+/**
+ Get the Bbs index for the input boot option.
+
+ @param BootOption The input boot option info.
+ @param BbsTable The input Bbs table.
+ @param BbsCount The input total bbs entry number.
+ @param BbsIndexUsed The array shows how many BBS table indexs have been used.
+
+ @retval The index for the input boot option.
+**/
+UINT16
+LegacyBmFuzzyMatch (
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ BBS_TABLE *BbsTable,
+ UINT16 BbsCount,
+ BOOLEAN *BbsIndexUsed
+ )
+{
+ UINT16 Index;
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *BbsData;
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+
+ BbsData = (LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData;
+
+ //
+ // Directly check the BBS index stored in BootOption
+ //
+ if ((BbsData->BbsIndex < BbsCount) &&
+ (LegacyBmDeviceType (BootOption->FilePath) == BbsTable[BbsData->BbsIndex].DeviceType)) {
+ LegacyBmBuildLegacyDevNameString (
+ &BbsTable[BbsData->BbsIndex],
+ BbsData->BbsIndex,
+ sizeof (Description),
+ Description
+ );
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[BbsData->BbsIndex]) {
+ //
+ // If devices with the same description string are connected,
+ // the BbsIndex of the first device is returned for the other device also.
+ // So, check if the BbsIndex is already being used, before assigning the BbsIndex.
+ //
+ BbsIndexUsed[BbsData->BbsIndex] = TRUE;
+ return BbsData->BbsIndex;
+ }
+ }
+
+ //
+ // BBS table could be changed (entry removed/moved)
+ // find the correct BBS index
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index]) ||
+ (BbsTable[Index].DeviceType != LegacyBmDeviceType (BootOption->FilePath))) {
+ continue;
+ }
+
+ LegacyBmBuildLegacyDevNameString (
+ &BbsTable[Index],
+ Index,
+ sizeof (Description),
+ Description
+ );
+ if ((StrCmp (Description, BootOption->Description) == 0) && !BbsIndexUsed[Index]) {
+ //
+ // If devices with the same description string are connected,
+ // the BbsIndex of the first device is assigned for the other device also.
+ // So, check if the BbsIndex is already being used, before assigning the corrected BbsIndex.
+ //
+ break;
+ }
+ }
+
+ //
+ // Add the corrected BbsIndex in the UsedBbsIndex Buffer
+ //
+ if (Index != BbsCount) {
+ BbsIndexUsed[Index] = TRUE;
+ }
+
+ return Index;
+}
+
+/**
+
+ Update legacy device order base on the input info.
+
+ @param LegacyDevOrder Legacy device order data buffer.
+ @param LegacyDevOrderSize Legacy device order data buffer size.
+ @param DeviceType Device type which need to check.
+ @param OldBbsIndex Old Bds Index.
+ @param NewBbsIndex New Bds Index, if it is -1,means remove this option.
+
+**/
+VOID
+LegacyBmUpdateBbsIndex (
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder,
+ UINTN *LegacyDevOrderSize,
+ UINT16 DeviceType,
+ UINT16 OldBbsIndex,
+ UINT16 NewBbsIndex // Delete entry if -1
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *Entry;
+ UINTN Index;
+
+ ASSERT (((LegacyDevOrder == NULL) && (*LegacyDevOrderSize == 0)) ||
+ ((LegacyDevOrder != NULL) && (*LegacyDevOrderSize != 0))
+ );
+
+ for (Entry = LegacyDevOrder;
+ Entry < (LEGACY_DEV_ORDER_ENTRY *) ((UINT8 *) LegacyDevOrder + *LegacyDevOrderSize);
+ Entry = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) Entry + sizeof (BBS_TYPE) + Entry->Length)
+ ) {
+ if (Entry->BbsType == DeviceType) {
+ for (Index = 0; Index < Entry->Length / sizeof (UINT16) - 1; Index++) {
+ if (Entry->Data[Index] == OldBbsIndex) {
+ if (NewBbsIndex == (UINT16) -1) {
+ //
+ // Delete the old entry
+ //
+ CopyMem (
+ &Entry->Data[Index],
+ &Entry->Data[Index + 1],
+ (UINT8 *) LegacyDevOrder + *LegacyDevOrderSize - (UINT8 *) &Entry->Data[Index + 1]
+ );
+ Entry->Length -= sizeof (UINT16);
+ *LegacyDevOrderSize -= sizeof(UINT16);
+ } else {
+ Entry->Data[Index] = NewBbsIndex;
+ }
+ break;
+ }
+ }
+ break;
+ }
+ }
+}
+
+/**
+ Delete all the legacy boot options.
+
+ @retval EFI_SUCCESS All legacy boot options are deleted.
+**/
+EFI_STATUS
+LegacyBmDeleteAllBootOptions (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if ((DevicePathType (BootOption[Index].FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption[Index].FilePath) == BBS_BBS_DP)) {
+ Status = EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT (Status == EFI_SUCCESS || Status == EFI_NOT_FOUND);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Delete all the invalid legacy boot options.
+
+ @retval EFI_SUCCESS All invalide legacy boot options are deleted.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate necessary memory.
+ @retval EFI_NOT_FOUND Fail to retrive variable of boot order.
+**/
+EFI_STATUS
+LegacyBmDeleteAllInvalidBootOptions (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *HddInfo;
+ BBS_TABLE *BbsTable;
+ UINT16 BbsIndex;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOption;
+ UINTN BootOptionCount;
+ LEGACY_DEV_ORDER_ENTRY *LegacyDevOrder;
+ UINTN LegacyDevOrderSize;
+ BOOLEAN *BbsIndexUsed;
+
+ HddCount = 0;
+ BbsCount = 0;
+ HddInfo = NULL;
+ BbsTable = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &LegacyDevOrder, &LegacyDevOrderSize);
+
+ BootOption = EfiBootManagerGetLoadOptions (&BootOptionCount, LoadOptionTypeBoot);
+
+ BbsIndexUsed = AllocateZeroPool (BbsCount * sizeof (BOOLEAN));
+ ASSERT (BbsIndexUsed != NULL);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ //
+ // Skip non legacy boot option
+ //
+ if ((DevicePathType (BootOption[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (BootOption[Index].FilePath) != BBS_BBS_DP)) {
+ continue;
+ }
+
+ BbsIndex = LegacyBmFuzzyMatch (&BootOption[Index], BbsTable, BbsCount, BbsIndexUsed);
+ if (BbsIndex == BbsCount) {
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Delete Boot Option Boot%04x: %s\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description));
+ //
+ // Delete entry from LegacyDevOrder
+ //
+ LegacyBmUpdateBbsIndex (
+ LegacyDevOrder,
+ &LegacyDevOrderSize,
+ LegacyBmDeviceType (BootOption[Index].FilePath),
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
+ (UINT16) -1
+ );
+ EfiBootManagerDeleteLoadOptionVariable (BootOption[Index].OptionNumber, BootOption[Index].OptionType);
+ } else {
+ if (((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex != BbsIndex) {
+ DEBUG ((EFI_D_INFO, "[LegacyBds] Update Boot Option Boot%04x: %s Bbs0x%04x->Bbs0x%04x\n", (UINTN) BootOption[Index].OptionNumber, BootOption[Index].Description,
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex, (UINTN) BbsIndex));
+ //
+ // Update the BBS index in LegacyDevOrder
+ //
+ LegacyBmUpdateBbsIndex (
+ LegacyDevOrder,
+ &LegacyDevOrderSize,
+ LegacyBmDeviceType (BootOption[Index].FilePath),
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex,
+ BbsIndex
+ );
+
+ //
+ // Update the OptionalData in the Boot#### variable
+ //
+ ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption[Index].OptionalData)->BbsIndex = BbsIndex;
+ EfiBootManagerLoadOptionToVariable (&BootOption[Index]);
+ }
+ }
+ }
+ EfiBootManagerFreeLoadOptions (BootOption, BootOptionCount);
+
+ if (LegacyDevOrder != NULL) {
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ LegacyDevOrderSize,
+ LegacyDevOrder
+ );
+ //
+ // Shrink variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (LegacyDevOrder);
+ }
+ FreePool(BbsIndexUsed);
+ return Status;
+}
+
+/**
+ Create legacy boot option.
+
+ @param BootOption Ponter to the boot option which will be crated.
+ @param BbsEntry The input bbs entry info.
+ @param BbsIndex The BBS index.
+
+ @retval EFI_SUCCESS Create legacy boot option successfully.
+ @retval EFI_INVALID_PARAMETER Invalid input parameter.
+
+**/
+EFI_STATUS
+LegacyBmCreateLegacyBootOption (
+ IN OUT EFI_BOOT_MANAGER_LOAD_OPTION *BootOption,
+ IN BBS_TABLE *BbsEntry,
+ IN UINT16 BbsIndex
+ )
+{
+ EFI_STATUS Status;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 Description[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ CHAR8 HelpString[LEGACY_BM_BOOT_DESCRIPTION_LENGTH + 1];
+ UINTN StringLen;
+ LEGACY_BM_BOOT_OPTION_BBS_DATA *OptionalData;
+ BBS_BBS_DEVICE_PATH *BbsNode;
+
+ if ((BootOption == NULL) || (BbsEntry == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ LegacyBmBuildLegacyDevNameString (BbsEntry, BbsIndex, sizeof (Description), Description);
+
+ //
+ // Create the BBS device path with description string
+ //
+ UnicodeStrToAsciiStrS (Description, HelpString, sizeof (HelpString));
+ StringLen = AsciiStrLen (HelpString);
+ DevicePath = AllocatePool (sizeof (BBS_BBS_DEVICE_PATH) + StringLen + END_DEVICE_PATH_LENGTH);
+ ASSERT (DevicePath != NULL);
+
+ BbsNode = (BBS_BBS_DEVICE_PATH *) DevicePath;
+ SetDevicePathNodeLength (BbsNode, sizeof (BBS_BBS_DEVICE_PATH) + StringLen);
+ BbsNode->Header.Type = BBS_DEVICE_PATH;
+ BbsNode->Header.SubType = BBS_BBS_DP;
+ BbsNode->DeviceType = BbsEntry->DeviceType;
+ CopyMem (&BbsNode->StatusFlag, &BbsEntry->StatusFlags, sizeof (BBS_STATUS_FLAGS));
+ CopyMem (BbsNode->String, HelpString, StringLen + 1);
+
+ SetDevicePathEndNode (NextDevicePathNode (BbsNode));
+
+ //
+ // Create the OptionalData
+ //
+ OptionalData = AllocatePool (sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA));
+ ASSERT (OptionalData != NULL);
+ OptionalData->BbsIndex = BbsIndex;
+
+ //
+ // Create the BootOption
+ //
+ Status = EfiBootManagerInitializeLoadOption (
+ BootOption,
+ LoadOptionNumberUnassigned,
+ LoadOptionTypeBoot,
+ LOAD_OPTION_ACTIVE,
+ Description,
+ DevicePath,
+ (UINT8 *) OptionalData,
+ sizeof (LEGACY_BM_BOOT_OPTION_BBS_DATA)
+ );
+ FreePool (DevicePath);
+ FreePool (OptionalData);
+
+ return Status;
+}
+
+/**
+ Fill the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsType The BBS Type.
+ @param BbsCount The BBS Count.
+ @param Buf device order buffer.
+
+ @return The device order buffer.
+
+**/
+UINT16 *
+LegacyBmFillDevOrderBuf (
+ IN BBS_TABLE *BbsTable,
+ IN BBS_TYPE BbsType,
+ IN UINTN BbsCount,
+ OUT UINT16 *Buf
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ if (BbsTable[Index].DeviceType != BbsType) {
+ continue;
+ }
+
+ *Buf = (UINT16) (Index & 0xFF);
+ Buf++;
+ }
+
+ return Buf;
+}
+
+/**
+ Create the device order buffer.
+
+ @param BbsTable The BBS table.
+ @param BbsCount The BBS Count.
+
+ @retval EFI_SUCCES The buffer is created and the EFI variable named
+ VAR_LEGACY_DEV_ORDER and EfiLegacyDevOrderGuid is
+ set correctly.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the device order into EFI variable fail
+ because of hardware error.
+**/
+EFI_STATUS
+LegacyBmCreateDevOrder (
+ IN BBS_TABLE *BbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINTN Index;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ EFI_STATUS Status;
+
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ DevOrder = NULL;
+ Status = EFI_SUCCESS;
+
+ //
+ // Count all boot devices
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + sizeof (UINT16) * FDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * HDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * CDCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * NETCount);
+ TotalSize += (HeaderSize + sizeof (UINT16) * BEVCount);
+
+ //
+ // Create buffer to hold all boot device order
+ //
+ DevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ DevOrderPtr = DevOrder;
+
+ DevOrderPtr->BbsType = BBS_FLOPPY;
+ DevOrderPtr->Length = (UINT16) (sizeof (DevOrderPtr->Length) + FDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_FLOPPY, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_HARDDISK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_HARDDISK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_CDROM;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_CDROM, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_EMBED_NETWORK;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_EMBED_NETWORK, BbsCount, DevOrderPtr->Data);
+
+ DevOrderPtr->BbsType = BBS_BEV_DEVICE;
+ DevOrderPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) LegacyBmFillDevOrderBuf (BbsTable, BBS_BEV_DEVICE, BbsCount, DevOrderPtr->Data);
+
+ ASSERT (TotalSize == (UINTN) ((UINT8 *) DevOrderPtr - (UINT8 *) DevOrder));
+
+ //
+ // Save device order for legacy boot device to variable.
+ //
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ DevOrder
+ );
+ FreePool (DevOrder);
+
+ return Status;
+}
+
+/**
+ Add the legacy boot devices from BBS table into
+ the legacy device boot order.
+
+ @retval EFI_SUCCESS The boot devices are added successfully.
+ @retval EFI_NOT_FOUND The legacy boot devices are not found.
+ @retval EFI_OUT_OF_RESOURCES Memmory or storage is not enough.
+ @retval EFI_DEVICE_ERROR Fail to add the legacy device boot order into EFI variable
+ because of hardware error.
+**/
+EFI_STATUS
+LegacyBmUpdateDevOrder (
+ VOID
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *NewDevOrder;
+ LEGACY_DEV_ORDER_ENTRY *Ptr;
+ LEGACY_DEV_ORDER_ENTRY *NewPtr;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINTN Index;
+ UINTN Index2;
+ UINTN *Idx;
+ UINTN FDCount;
+ UINTN HDCount;
+ UINTN CDCount;
+ UINTN NETCount;
+ UINTN BEVCount;
+ UINTN TotalSize;
+ UINTN HeaderSize;
+ UINT16 *NewFDPtr;
+ UINT16 *NewHDPtr;
+ UINT16 *NewCDPtr;
+ UINT16 *NewNETPtr;
+ UINT16 *NewBEVPtr;
+ UINT16 *NewDevPtr;
+ UINTN FDIndex;
+ UINTN HDIndex;
+ UINTN CDIndex;
+ UINTN NETIndex;
+ UINTN BEVIndex;
+
+ Idx = NULL;
+ FDCount = 0;
+ HDCount = 0;
+ CDCount = 0;
+ NETCount = 0;
+ BEVCount = 0;
+ TotalSize = 0;
+ HeaderSize = sizeof (BBS_TYPE) + sizeof (UINT16);
+ FDIndex = 0;
+ HDIndex = 0;
+ CDIndex = 0;
+ NETIndex = 0;
+ BEVIndex = 0;
+ NewDevPtr = NULL;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, NULL);
+ if (NULL == DevOrder) {
+ return LegacyBmCreateDevOrder (LocalBbsTable, BbsCount);
+ }
+ //
+ // First we figure out how many boot devices with same device type respectively
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ FDCount++;
+ break;
+
+ case BBS_HARDDISK:
+ HDCount++;
+ break;
+
+ case BBS_CDROM:
+ CDCount++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ NETCount++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ BEVCount++;
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ TotalSize += (HeaderSize + FDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + HDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + CDCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + NETCount * sizeof (UINT16));
+ TotalSize += (HeaderSize + BEVCount * sizeof (UINT16));
+
+ NewDevOrder = AllocateZeroPool (TotalSize);
+ if (NULL == NewDevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // copy FD
+ //
+ Ptr = DevOrder;
+ NewPtr = NewDevOrder;
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + FDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_FLOPPY
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[FDIndex] = Ptr->Data[Index];
+ FDIndex++;
+ }
+ NewFDPtr = NewPtr->Data;
+
+ //
+ // copy HD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + HDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_HARDDISK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[HDIndex] = Ptr->Data[Index];
+ HDIndex++;
+ }
+ NewHDPtr = NewPtr->Data;
+
+ //
+ // copy CD
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + CDCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_CDROM
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[CDIndex] = Ptr->Data[Index];
+ CDIndex++;
+ }
+ NewCDPtr = NewPtr->Data;
+
+ //
+ // copy NET
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + NETCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_EMBED_NETWORK
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[NETIndex] = Ptr->Data[Index];
+ NETIndex++;
+ }
+ NewNETPtr = NewPtr->Data;
+
+ //
+ // copy BEV
+ //
+ Ptr = (LEGACY_DEV_ORDER_ENTRY *) (&Ptr->Data[Ptr->Length / sizeof (UINT16) - 1]);
+ NewPtr = (LEGACY_DEV_ORDER_ENTRY *) (&NewPtr->Data[NewPtr->Length / sizeof (UINT16) -1]);
+ NewPtr->BbsType = Ptr->BbsType;
+ NewPtr->Length = (UINT16) (sizeof (UINT16) + BEVCount * sizeof (UINT16));
+ for (Index = 0; Index < Ptr->Length / sizeof (UINT16) - 1; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Ptr->Data[Index] & 0xFF]) ||
+ LocalBbsTable[Ptr->Data[Index] & 0xFF].DeviceType != BBS_BEV_DEVICE
+ ) {
+ continue;
+ }
+
+ NewPtr->Data[BEVIndex] = Ptr->Data[Index];
+ BEVIndex++;
+ }
+ NewBEVPtr = NewPtr->Data;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ switch (LocalBbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ Idx = &FDIndex;
+ NewDevPtr = NewFDPtr;
+ break;
+
+ case BBS_HARDDISK:
+ Idx = &HDIndex;
+ NewDevPtr = NewHDPtr;
+ break;
+
+ case BBS_CDROM:
+ Idx = &CDIndex;
+ NewDevPtr = NewCDPtr;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ Idx = &NETIndex;
+ NewDevPtr = NewNETPtr;
+ break;
+
+ case BBS_BEV_DEVICE:
+ Idx = &BEVIndex;
+ NewDevPtr = NewBEVPtr;
+ break;
+
+ default:
+ Idx = NULL;
+ break;
+ }
+ //
+ // at this point we have copied those valid indexes to new buffer
+ // and we should check if there is any new appeared boot device
+ //
+ if (Idx != NULL) {
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF) == (UINT16) Index) {
+ break;
+ }
+ }
+
+ if (Index2 == *Idx) {
+ //
+ // Index2 == *Idx means we didn't find Index
+ // so Index is a new appeared device's index in BBS table
+ // insert it before disabled indexes.
+ //
+ for (Index2 = 0; Index2 < *Idx; Index2++) {
+ if ((NewDevPtr[Index2] & 0xFF00) == 0xFF00) {
+ break;
+ }
+ }
+ CopyMem (&NewDevPtr[Index2 + 1], &NewDevPtr[Index2], (*Idx - Index2) * sizeof (UINT16));
+ NewDevPtr[Index2] = (UINT16) (Index & 0xFF);
+ (*Idx)++;
+ }
+ }
+ }
+
+ FreePool (DevOrder);
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ TotalSize,
+ NewDevOrder
+ );
+ FreePool (NewDevOrder);
+
+ return Status;
+}
+
+/**
+ Set Boot Priority for specified device type.
+
+ @param DeviceType The device type.
+ @param BbsIndex The BBS index to set the highest priority. Ignore when -1.
+ @param LocalBbsTable The BBS table.
+ @param Priority The prority table.
+
+ @retval EFI_SUCCESS The function completes successfully.
+ @retval EFI_NOT_FOUND Failed to find device.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the efi variable of device order.
+
+**/
+EFI_STATUS
+LegacyBmSetPriorityForSameTypeDev (
+ IN UINT16 DeviceType,
+ IN UINTN BbsIndex,
+ IN OUT BBS_TABLE *LocalBbsTable,
+ IN OUT UINT16 *Priority
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ LEGACY_DEV_ORDER_ENTRY *DevOrderPtr;
+ UINTN DevOrderSize;
+ UINTN Index;
+
+ GetVariable2 (VAR_LEGACY_DEV_ORDER, &gEfiLegacyDevOrderVariableGuid, (VOID **) &DevOrder, &DevOrderSize);
+ if (NULL == DevOrder) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DevOrderPtr = DevOrder;
+ while ((UINT8 *) DevOrderPtr < (UINT8 *) DevOrder + DevOrderSize) {
+ if (DevOrderPtr->BbsType == DeviceType) {
+ break;
+ }
+
+ DevOrderPtr = (LEGACY_DEV_ORDER_ENTRY *) ((UINTN) DevOrderPtr + sizeof (BBS_TYPE) + DevOrderPtr->Length);
+ }
+
+ if ((UINT8 *) DevOrderPtr >= (UINT8 *) DevOrder + DevOrderSize) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+
+ if (BbsIndex != (UINTN) -1) {
+ //
+ // In case the BBS entry isn't valid because devices were plugged or removed.
+ //
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[BbsIndex]) || (LocalBbsTable[BbsIndex].DeviceType != DeviceType)) {
+ FreePool (DevOrder);
+ return EFI_NOT_FOUND;
+ }
+ LocalBbsTable[BbsIndex].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ //
+ // If the high byte of the DevIndex is 0xFF, it indicates that this device has been disabled.
+ //
+ for (Index = 0; Index < DevOrderPtr->Length / sizeof (UINT16) - 1; Index++) {
+ if ((DevOrderPtr->Data[Index] & 0xFF00) == 0xFF00) {
+ //
+ // LocalBbsTable[DevIndex[Index] & 0xFF].BootPriority = BBS_DISABLED_ENTRY;
+ //
+ } else if (DevOrderPtr->Data[Index] != BbsIndex) {
+ LocalBbsTable[DevOrderPtr->Data[Index]].BootPriority = *Priority;
+ (*Priority)++;
+ }
+ }
+
+ FreePool (DevOrder);
+ return EFI_SUCCESS;
+}
+
+/**
+ Print the BBS Table.
+
+ @param LocalBbsTable The BBS table.
+ @param BbsCount The count of entry in BBS table.
+**/
+VOID
+LegacyBmPrintBbsTable (
+ IN BBS_TABLE *LocalBbsTable,
+ IN UINT16 BbsCount
+ )
+{
+ UINT16 Index;
+
+ DEBUG ((DEBUG_INFO, "\n"));
+ DEBUG ((DEBUG_INFO, " NO Prio bb/dd/ff cl/sc Type Stat segm:offs\n"));
+ DEBUG ((DEBUG_INFO, "=============================================\n"));
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ continue;
+ }
+
+ DEBUG (
+ (DEBUG_INFO,
+ " %02x: %04x %02x/%02x/%02x %02x/%02x %04x %04x %04x:%04x\n",
+ (UINTN) Index,
+ (UINTN) LocalBbsTable[Index].BootPriority,
+ (UINTN) LocalBbsTable[Index].Bus,
+ (UINTN) LocalBbsTable[Index].Device,
+ (UINTN) LocalBbsTable[Index].Function,
+ (UINTN) LocalBbsTable[Index].Class,
+ (UINTN) LocalBbsTable[Index].SubClass,
+ (UINTN) LocalBbsTable[Index].DeviceType,
+ (UINTN) * (UINT16 *) &LocalBbsTable[Index].StatusFlags,
+ (UINTN) LocalBbsTable[Index].BootHandlerSegment,
+ (UINTN) LocalBbsTable[Index].BootHandlerOffset,
+ (UINTN) ((LocalBbsTable[Index].MfgStringSegment << 4) + LocalBbsTable[Index].MfgStringOffset),
+ (UINTN) ((LocalBbsTable[Index].DescStringSegment << 4) + LocalBbsTable[Index].DescStringOffset))
+ );
+ }
+
+ DEBUG ((DEBUG_INFO, "\n"));
+}
+
+/**
+ Set the boot priority for BBS entries based on boot option entry and boot order.
+
+ @param BootOption The boot option is to be checked for refresh BBS table.
+
+ @retval EFI_SUCCESS The boot priority for BBS entries is refreshed successfully.
+ @retval EFI_NOT_FOUND BBS entries can't be found.
+ @retval EFI_OUT_OF_RESOURCES Failed to get the legacy device boot order.
+**/
+EFI_STATUS
+LegacyBmRefreshBbsTableForBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ UINT16 BbsIndex;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *LocalHddInfo;
+ BBS_TABLE *LocalBbsTable;
+ UINT16 DevType;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN Index;
+ UINT16 Priority;
+ UINT16 *DeviceType;
+ UINTN DeviceTypeCount;
+ UINTN DeviceTypeIndex;
+ EFI_BOOT_MANAGER_LOAD_OPTION *Option;
+ UINTN OptionCount;
+
+ HddCount = 0;
+ BbsCount = 0;
+ LocalHddInfo = NULL;
+ LocalBbsTable = NULL;
+ DevType = BBS_UNKNOWN;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &LocalHddInfo,
+ &BbsCount,
+ &LocalBbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // First, set all the present devices' boot priority to BBS_UNPRIORITIZED_ENTRY
+ // We will set them according to the settings setup by user
+ //
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (LegacyBmValidBbsEntry (&LocalBbsTable[Index])) {
+ LocalBbsTable[Index].BootPriority = BBS_UNPRIORITIZED_ENTRY;
+ }
+ }
+ //
+ // boot priority always starts at 0
+ //
+ Priority = 0;
+ if ((DevicePathType (BootOption->FilePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption->FilePath) == BBS_BBS_DP)) {
+ //
+ // If BootOption stands for a legacy boot option, we prioritize the devices with the same type first.
+ //
+ DevType = LegacyBmDeviceType (BootOption->FilePath);
+ BbsIndex = ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOption->OptionalData)->BbsIndex;
+ Status = LegacyBmSetPriorityForSameTypeDev (
+ DevType,
+ BbsIndex,
+ LocalBbsTable,
+ &Priority
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // we have to set the boot priority for other BBS entries with different device types
+ //
+ Option = EfiBootManagerGetLoadOptions (&OptionCount, LoadOptionTypeBoot);
+ DeviceType = AllocatePool (sizeof (UINT16) * OptionCount);
+ ASSERT (DeviceType != NULL);
+ DeviceType[0] = DevType;
+ DeviceTypeCount = 1;
+ for (Index = 0; Index < OptionCount; Index++) {
+ if ((DevicePathType (Option[Index].FilePath) != BBS_DEVICE_PATH) ||
+ (DevicePathSubType (Option[Index].FilePath) != BBS_BBS_DP)) {
+ continue;
+ }
+
+ DevType = LegacyBmDeviceType (Option[Index].FilePath);
+ for (DeviceTypeIndex = 0; DeviceTypeIndex < DeviceTypeCount; DeviceTypeIndex++) {
+ if (DeviceType[DeviceTypeIndex] == DevType) {
+ break;
+ }
+ }
+ if (DeviceTypeIndex < DeviceTypeCount) {
+ //
+ // We don't want to process twice for a device type
+ //
+ continue;
+ }
+
+ DeviceType[DeviceTypeCount] = DevType;
+ DeviceTypeCount++;
+
+ Status = LegacyBmSetPriorityForSameTypeDev (
+ DevType,
+ (UINTN) -1,
+ LocalBbsTable,
+ &Priority
+ );
+ }
+ EfiBootManagerFreeLoadOptions (Option, OptionCount);
+
+ DEBUG_CODE_BEGIN();
+ LegacyBmPrintBbsTable (LocalBbsTable, BbsCount);
+ DEBUG_CODE_END();
+
+ return Status;
+}
+
+
+/**
+ Boot the legacy system with the boot option.
+
+ @param BootOption The legacy boot option which have BBS device path
+ On return, BootOption->Status contains the boot status.
+ EFI_UNSUPPORTED There is no legacybios protocol, do not support
+ legacy boot.
+ EFI_STATUS The status of LegacyBios->LegacyBoot ().
+**/
+VOID
+EFIAPI
+LegacyBmBoot (
+ IN EFI_BOOT_MANAGER_LOAD_OPTION *BootOption
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ //
+ // If no LegacyBios protocol we do not support legacy boot
+ //
+ BootOption->Status = EFI_UNSUPPORTED;
+ return;
+ }
+ //
+ // Notes: if we separate the int 19, then we don't need to refresh BBS
+ //
+ Status = LegacyBmRefreshBbsTableForBoot (BootOption);
+ if (EFI_ERROR (Status)) {
+ BootOption->Status = Status;
+ return;
+ }
+
+ BootOption->Status = LegacyBios->LegacyBoot (
+ LegacyBios,
+ (BBS_BBS_DEVICE_PATH *) BootOption->FilePath,
+ BootOption->OptionalDataSize,
+ BootOption->OptionalData
+ );
+}
+
+/**
+ This function enumerates all the legacy boot options.
+
+ @param BootOptionCount Return the legacy boot option count.
+
+ @retval Pointer to the legacy boot option buffer.
+**/
+EFI_BOOT_MANAGER_LOAD_OPTION *
+LegacyBmEnumerateAllBootOptions (
+ UINTN *BootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HddCount;
+ UINT16 BbsCount;
+ HDD_INFO *HddInfo;
+ BBS_TABLE *BbsTable;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 Index;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+
+ ASSERT (BootOptionCount != NULL);
+
+ BootOptions = NULL;
+ *BootOptionCount = 0;
+ BbsCount = 0;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return NULL;
+ }
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if (!LegacyBmValidBbsEntry (&BbsTable[Index])) {
+ continue;
+ }
+
+ BootOptions = ReallocatePool (
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount),
+ sizeof (EFI_BOOT_MANAGER_LOAD_OPTION) * (*BootOptionCount + 1),
+ BootOptions
+ );
+ ASSERT (BootOptions != NULL);
+
+ Status = LegacyBmCreateLegacyBootOption (&BootOptions[(*BootOptionCount)++], &BbsTable[Index], Index);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return BootOptions;
+}
+
+/**
+ Return the index of the boot option in the boot option array.
+
+ The function compares the Description, FilePath, OptionalData.
+
+ @param Key The input boot option which is compared with.
+ @param Array The input boot option array.
+ @param Count The count of the input boot options.
+
+ @retval The index of the input boot option in the array.
+
+**/
+INTN
+LegacyBmFindBootOption (
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Key,
+ IN CONST EFI_BOOT_MANAGER_LOAD_OPTION *Array,
+ IN UINTN Count
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; Index < Count; Index++) {
+ if ((StrCmp (Key->Description, Array[Index].Description) == 0) &&
+ (CompareMem (Key->FilePath, Array[Index].FilePath, GetDevicePathSize (Key->FilePath)) == 0) &&
+ (Key->OptionalDataSize == Array[Index].OptionalDataSize) &&
+ (CompareMem (Key->OptionalData, Array[Index].OptionalData, Key->OptionalDataSize) == 0)) {
+ return (INTN) Index;
+ }
+ }
+
+ return -1;
+}
+
+/**
+ Refresh all legacy boot options.
+
+**/
+VOID
+EFIAPI
+LegacyBmRefreshAllBootOption (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINTN RootBridgeHandleCount;
+ EFI_HANDLE *RootBridgeHandleBuffer;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ UINTN RootBridgeIndex;
+ UINTN Index;
+ UINTN Flags;
+ EFI_BOOT_MANAGER_LOAD_OPTION *BootOptions;
+ UINTN BootOptionCount;
+ EFI_BOOT_MANAGER_LOAD_OPTION *ExistingBootOptions;
+ UINTN ExistingBootOptionCount;
+
+ Status = gBS->LocateProtocol (&gEfiLegacyBiosProtocolGuid, NULL, (VOID **) &LegacyBios);
+ if (EFI_ERROR (Status)) {
+ LegacyBmDeleteAllBootOptions ();
+ return;
+ }
+ PERF_START (NULL, "LegacyBootOptionEnum", "BDS", 0);
+
+ //
+ // Before enumerating the legacy boot option, we need to dispatch all the legacy option roms
+ // to ensure the GetBbsInfo() counts all the legacy devices.
+ //
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciRootBridgeIoProtocolGuid,
+ NULL,
+ &RootBridgeHandleCount,
+ &RootBridgeHandleBuffer
+ );
+ for (RootBridgeIndex = 0; RootBridgeIndex < RootBridgeHandleCount; RootBridgeIndex++) {
+ gBS->ConnectController (RootBridgeHandleBuffer[RootBridgeIndex], NULL, NULL, FALSE);
+ gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ for (Index = 0; Index < HandleCount; Index++) {
+ //
+ // Start the thunk driver so that the legacy option rom gets dispatched.
+ // Note: We don't directly call InstallPciRom because some thunk drivers
+ // (e.g. BlockIo thunk driver) depend on the immediate result after dispatching
+ //
+ Status = LegacyBios->CheckPciRom (
+ LegacyBios,
+ HandleBuffer[Index],
+ NULL,
+ NULL,
+ &Flags
+ );
+ if (!EFI_ERROR (Status)) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, FALSE);
+ }
+ }
+ }
+
+ //
+ // Same algorithm pattern as the EfiBootManagerRefreshAllBootOption
+ // Firstly delete the invalid legacy boot options,
+ // then enumreate and save the newly appeared legacy boot options
+ // the last step is legacy boot option special action to refresh the LegacyDevOrder variable
+ //
+ LegacyBmDeleteAllInvalidBootOptions ();
+
+ ExistingBootOptions = EfiBootManagerGetLoadOptions (&ExistingBootOptionCount, LoadOptionTypeBoot);
+ BootOptions = LegacyBmEnumerateAllBootOptions (&BootOptionCount);
+
+ for (Index = 0; Index < BootOptionCount; Index++) {
+ if (LegacyBmFindBootOption (&BootOptions[Index], ExistingBootOptions, ExistingBootOptionCount) == -1) {
+ Status = EfiBootManagerAddLoadOptionVariable (&BootOptions[Index], (UINTN) -1);
+ DEBUG ((
+ EFI_D_INFO, "[LegacyBds] New Boot Option: Boot%04x Bbs0x%04x %s %r\n",
+ (UINTN) BootOptions[Index].OptionNumber,
+ (UINTN) ((LEGACY_BM_BOOT_OPTION_BBS_DATA *) BootOptions[Index].OptionalData)->BbsIndex,
+ BootOptions[Index].Description,
+ Status
+ ));
+ //
+ // Continue upon failure to add boot option.
+ //
+ }
+ }
+
+ EfiBootManagerFreeLoadOptions (ExistingBootOptions, ExistingBootOptionCount);
+ EfiBootManagerFreeLoadOptions (BootOptions, BootOptionCount);
+
+ //
+ // Failure to create LegacyDevOrder variable only impacts the boot order.
+ //
+ LegacyBmUpdateDevOrder ();
+
+ PERF_END (NULL, "LegacyBootOptionEnum", "BDS", 0);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
new file mode 100644
index 0000000000..4025c82886
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.inf
@@ -0,0 +1,64 @@
+## @file
+# Legacy Boot Manager module is library for BDS phase.
+#
+# Copyright (c) 2011 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyBootManagerLib
+ MODULE_UNI_FILE = LegacyBootManagerLib.uni
+ FILE_GUID = F1B87BE4-0ACC-409A-A52B-7BFFABCC96A0
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL|DXE_DRIVER UEFI_APPLICATION
+ CONSTRUCTOR = LegacyBootManagerLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ LegacyBm.c
+ InternalLegacyBm.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ BaseMemoryLib
+ UefiBootServicesTableLib
+ UefiRuntimeServicesTableLib
+ DevicePathLib
+ MemoryAllocationLib
+ UefiLib
+ DebugLib
+ PrintLib
+ PerformanceLib
+ UefiBootManagerLib
+
+[Guids]
+ gEfiGlobalVariableGuid ## SOMETIMES_PRODUCES ## Variable:L"Boot####" (Boot option variable)
+ ## SOMETIMES_CONSUMES ## Variable:L"BootOrder" (The boot option array)
+ gEfiLegacyDevOrderVariableGuid
+
+[Protocols]
+ gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+
+[Pcd]
diff --git a/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.uni b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.uni
new file mode 100644
index 0000000000..2585c93496
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LegacyBootManagerLib/LegacyBootManagerLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
new file mode 100644
index 0000000000..ada9a809fa
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/F86GuidedSectionExtraction.c
@@ -0,0 +1,218 @@
+/** @file
+ LZMA Decompress GUIDed Section Extraction Library, which produces LZMA custom
+ decompression algorithm with the converter for the different arch code.
+ It wraps Lzma decompress interfaces to GUIDed Section Extraction interfaces
+ and registers them into GUIDed handler table.
+
+ Copyright (c) 2012, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+#include "Sdk/C/Bra.h"
+
+/**
+ Examines a GUIDed section and returns the size of the decoded buffer and the
+ size of an scratch buffer required to actually decode the data in a GUIDed section.
+
+ Examines a GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports,
+ then RETURN_UNSUPPORTED is returned.
+ If the required information can not be retrieved from InputSection,
+ then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports,
+ then the size required to hold the decoded buffer is returned in OututBufferSize,
+ the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+ from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBufferSize is NULL, then ASSERT().
+ If ScratchBufferSize is NULL, then ASSERT().
+ If SectionAttribute is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required
+ if the buffer specified by InputSection were decoded.
+ @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space
+ if the buffer specified by InputSection were decoded.
+ @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes
+ field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+ @retval RETURN_SUCCESS The information about InputSection was returned.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaArchGuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ ASSERT (InputSection != NULL);
+ ASSERT (OutputBufferSize != NULL);
+ ASSERT (ScratchBufferSize != NULL);
+ ASSERT (SectionAttribute != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaF86CustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaF86CustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a LZAM compressed GUIDed section into a caller allocated output buffer.
+
+ Decodes the GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+ If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+ is decoded into the buffer specified by OutputBuffer and the authentication status of this
+ decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the
+ data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise,
+ the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBuffer is NULL, then ASSERT().
+ If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+ If AuthenticationStatus is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
+ @param[out] ScratchBuffer A caller allocated buffer that may be required by this function
+ as a scratch buffer to perform the decode operation.
+ @param[out] AuthenticationStatus
+ A pointer to the authentication status of the decoded output buffer.
+ See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+ section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+ never be set by this handler.
+
+ @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaArchGuidedSectionExtraction (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_GUID *InputGuid;
+ VOID *Source;
+ UINTN SourceSize;
+ EFI_STATUS Status;
+ UINT32 X86State;
+ UINT32 OutputBufferSize;
+ UINT32 ScratchBufferSize;
+
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (InputSection != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ InputGuid = &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid);
+ Source = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ SourceSize = SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset;
+ } else {
+ InputGuid = &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid);
+ Source = (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ SourceSize = SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset;
+ }
+
+ if (!CompareGuid (&gLzmaF86CustomDecompressGuid, InputGuid)) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ Status = LzmaUefiDecompress (
+ Source,
+ SourceSize,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+
+ //
+ // After decompress, the data need to be converted to the raw data.
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = LzmaUefiDecompressGetInfo (
+ Source,
+ (UINT32) SourceSize,
+ &OutputBufferSize,
+ &ScratchBufferSize
+ );
+
+ if (!EFI_ERROR (Status)) {
+ x86_Convert_Init(X86State);
+ x86_Convert(*OutputBuffer, OutputBufferSize, 0, &X86State, 0);
+ }
+ }
+
+ return Status;
+}
+
+
+/**
+ Register LzmaArchDecompress and LzmaArchDecompressGetInfo handlers with LzmaF86CustomDecompressGuid.
+
+ @retval RETURN_SUCCESS Register successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+EFI_STATUS
+EFIAPI
+LzmaArchDecompressLibConstructor (
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaF86CustomDecompressGuid,
+ LzmaArchGuidedSectionGetInfo,
+ LzmaArchGuidedSectionExtraction
+ );
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
new file mode 100644
index 0000000000..f19e0d28cd
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/GuidedSectionExtraction.c
@@ -0,0 +1,201 @@
+/** @file
+ LZMA Decompress GUIDed Section Extraction Library.
+ It wraps Lzma decompress interfaces to GUIDed Section Extraction interfaces
+ and registers them into GUIDed handler table.
+
+ Copyright (c) 2009 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+
+/**
+ Examines a GUIDed section and returns the size of the decoded buffer and the
+ size of an scratch buffer required to actually decode the data in a GUIDed section.
+
+ Examines a GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports,
+ then RETURN_UNSUPPORTED is returned.
+ If the required information can not be retrieved from InputSection,
+ then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports,
+ then the size required to hold the decoded buffer is returned in OututBufferSize,
+ the size of an optional scratch buffer is returned in ScratchSize, and the Attributes field
+ from EFI_GUID_DEFINED_SECTION header of InputSection is returned in SectionAttribute.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBufferSize is NULL, then ASSERT().
+ If ScratchBufferSize is NULL, then ASSERT().
+ If SectionAttribute is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBufferSize A pointer to the size, in bytes, of an output buffer required
+ if the buffer specified by InputSection were decoded.
+ @param[out] ScratchBufferSize A pointer to the size, in bytes, required as scratch space
+ if the buffer specified by InputSection were decoded.
+ @param[out] SectionAttribute A pointer to the attributes of the GUIDed section. See the Attributes
+ field of EFI_GUID_DEFINED_SECTION in the PI Specification.
+
+ @retval RETURN_SUCCESS The information about InputSection was returned.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The information can not be retrieved from the section specified by InputSection.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionGetInfo (
+ IN CONST VOID *InputSection,
+ OUT UINT32 *OutputBufferSize,
+ OUT UINT32 *ScratchBufferSize,
+ OUT UINT16 *SectionAttribute
+ )
+{
+ ASSERT (InputSection != NULL);
+ ASSERT (OutputBufferSize != NULL);
+ ASSERT (ScratchBufferSize != NULL);
+ ASSERT (SectionAttribute != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ *SectionAttribute = ((EFI_GUID_DEFINED_SECTION *) InputSection)->Attributes;
+
+ return LzmaUefiDecompressGetInfo (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ OutputBufferSize,
+ ScratchBufferSize
+ );
+ }
+}
+
+/**
+ Decompress a LZAM compressed GUIDed section into a caller allocated output buffer.
+
+ Decodes the GUIDed section specified by InputSection.
+ If GUID for InputSection does not match the GUID that this handler supports, then RETURN_UNSUPPORTED is returned.
+ If the data in InputSection can not be decoded, then RETURN_INVALID_PARAMETER is returned.
+ If the GUID of InputSection does match the GUID that this handler supports, then InputSection
+ is decoded into the buffer specified by OutputBuffer and the authentication status of this
+ decode operation is returned in AuthenticationStatus. If the decoded buffer is identical to the
+ data in InputSection, then OutputBuffer is set to point at the data in InputSection. Otherwise,
+ the decoded data will be placed in caller allocated buffer specified by OutputBuffer.
+
+ If InputSection is NULL, then ASSERT().
+ If OutputBuffer is NULL, then ASSERT().
+ If ScratchBuffer is NULL and this decode operation requires a scratch buffer, then ASSERT().
+ If AuthenticationStatus is NULL, then ASSERT().
+
+
+ @param[in] InputSection A pointer to a GUIDed section of an FFS formatted file.
+ @param[out] OutputBuffer A pointer to a buffer that contains the result of a decode operation.
+ @param[out] ScratchBuffer A caller allocated buffer that may be required by this function
+ as a scratch buffer to perform the decode operation.
+ @param[out] AuthenticationStatus
+ A pointer to the authentication status of the decoded output buffer.
+ See the definition of authentication status in the EFI_PEI_GUIDED_SECTION_EXTRACTION_PPI
+ section of the PI Specification. EFI_AUTH_STATUS_PLATFORM_OVERRIDE must
+ never be set by this handler.
+
+ @retval RETURN_SUCCESS The buffer specified by InputSection was decoded.
+ @retval RETURN_UNSUPPORTED The section specified by InputSection does not match the GUID this handler supports.
+ @retval RETURN_INVALID_PARAMETER The section specified by InputSection can not be decoded.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaGuidedSectionExtraction (
+ IN CONST VOID *InputSection,
+ OUT VOID **OutputBuffer,
+ OUT VOID *ScratchBuffer, OPTIONAL
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ ASSERT (OutputBuffer != NULL);
+ ASSERT (InputSection != NULL);
+
+ if (IS_SECTION2 (InputSection)) {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION2 *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return LzmaUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ SECTION2_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION2 *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ } else {
+ if (!CompareGuid (
+ &gLzmaCustomDecompressGuid,
+ &(((EFI_GUID_DEFINED_SECTION *) InputSection)->SectionDefinitionGuid))) {
+ return RETURN_INVALID_PARAMETER;
+ }
+
+ //
+ // Authentication is set to Zero, which may be ignored.
+ //
+ *AuthenticationStatus = 0;
+
+ return LzmaUefiDecompress (
+ (UINT8 *) InputSection + ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ SECTION_SIZE (InputSection) - ((EFI_GUID_DEFINED_SECTION *) InputSection)->DataOffset,
+ *OutputBuffer,
+ ScratchBuffer
+ );
+ }
+}
+
+
+/**
+ Register LzmaDecompress and LzmaDecompressGetInfo handlers with LzmaCustomerDecompressGuid.
+
+ @retval RETURN_SUCCESS Register successfully.
+ @retval RETURN_OUT_OF_RESOURCES No enough memory to store this handler.
+**/
+EFI_STATUS
+EFIAPI
+LzmaDecompressLibConstructor (
+ )
+{
+ return ExtractGuidedSectionRegisterHandlers (
+ &gLzmaCustomDecompressGuid,
+ LzmaGuidedSectionGetInfo,
+ LzmaGuidedSectionExtraction
+ );
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
new file mode 100644
index 0000000000..e05b3bb853
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LZMA-SDK-README.txt
@@ -0,0 +1,4 @@
+LzmaCustomDecompressLib is based on the LZMA SDK 4.65.
+LZMA SDK 4.65 was placed in the public domain on
+2009-02-03. It was released on the
+http://www.7-zip.org/sdk.html website. \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
new file mode 100644
index 0000000000..ec7585d55b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchCustomDecompressLib.inf
@@ -0,0 +1,66 @@
+## @file
+# LzmaArchCustomDecompressLib produces LZMA custom decompression algorithm with the converter for the different arch code.
+#
+# It is based on the LZMA SDK 4.65.
+# LZMA SDK 4.65 was placed in the public domain on 2009-02-03.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2012 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LzmaArchDecompressLib
+ MODULE_UNI_FILE = LzmaArchDecompressLib.uni
+ FILE_GUID = A853C1D2-E003-4cc4-9DD1-8824AD79FE48
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = LzmaArchDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ LzmaDecompress.c
+ Sdk/C/Bra.h
+ Sdk/C/LzFind.c
+ Sdk/C/LzmaDec.c
+ Sdk/C/7zVersion.h
+ Sdk/C/CpuArch.h
+ Sdk/C/LzFind.h
+ Sdk/C/LzHash.h
+ Sdk/C/LzmaDec.h
+ Sdk/C/Types.h
+ UefiLzma.h
+ LzmaDecompressLibInternal.h
+
+[Sources.Ia32, Sources.X64]
+ Sdk/C/Bra86.c
+ F86GuidedSectionExtraction.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids.Ia32, Guids.X64]
+ gLzmaF86CustomDecompressGuid ## PRODUCES ## GUID # specifies LZMA custom decompress algorithm with converter for x86 code.
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
new file mode 100644
index 0000000000..1830dae73c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaArchDecompressLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
new file mode 100644
index 0000000000..f5624fd039
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaCustomDecompressLib.inf
@@ -0,0 +1,62 @@
+## @file
+# LzmaCustomDecompressLib produces LZMA custom decompression algorithm.
+#
+# It is based on the LZMA SDK 4.65.
+# LZMA SDK 4.65 was placed in the public domain on 2009-02-03.
+# It was released on the http://www.7-zip.org/sdk.html website.
+#
+# Copyright (c) 2009 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LzmaDecompressLib
+ MODULE_UNI_FILE = LzmaDecompressLib.uni
+ FILE_GUID = 35194660-7421-44ad-9636-e44885f092d1
+ MODULE_TYPE = BASE
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = NULL
+ CONSTRUCTOR = LzmaDecompressLibConstructor
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ LzmaDecompress.c
+ Sdk/C/LzFind.c
+ Sdk/C/LzmaDec.c
+ Sdk/C/7zVersion.h
+ Sdk/C/CpuArch.h
+ Sdk/C/LzFind.h
+ Sdk/C/LzHash.h
+ Sdk/C/LzmaDec.h
+ Sdk/C/Types.h
+ GuidedSectionExtraction.c
+ UefiLzma.h
+ LzmaDecompressLibInternal.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[Guids]
+ gLzmaCustomDecompressGuid ## PRODUCES ## UNDEFINED # specifies LZMA custom decompress algorithm.
+
+[LibraryClasses]
+ BaseLib
+ DebugLib
+ BaseMemoryLib
+ ExtractGuidedSectionLib
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
new file mode 100644
index 0000000000..e32b6a3025
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompress.c
@@ -0,0 +1,220 @@
+/** @file
+ LZMA Decompress interfaces
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDecompressLibInternal.h"
+#include "Sdk/C/Types.h"
+#include "Sdk/C/7zVersion.h"
+#include "Sdk/C/LzmaDec.h"
+
+#define SCRATCH_BUFFER_REQUEST_SIZE SIZE_64KB
+
+typedef struct
+{
+ ISzAlloc Functions;
+ VOID *Buffer;
+ UINTN BufferSize;
+} ISzAllocWithData;
+
+/**
+ Allocation routine used by LZMA decompression.
+
+ @param P Pointer to the ISzAlloc instance
+ @param Size The size in bytes to be allocated
+
+ @return The allocated pointer address, or NULL on failure
+**/
+VOID *
+SzAlloc (
+ VOID *P,
+ size_t Size
+ )
+{
+ VOID *Addr;
+ ISzAllocWithData *Private;
+
+ Private = (ISzAllocWithData*) P;
+
+ if (Private->BufferSize >= Size) {
+ Addr = Private->Buffer;
+ Private->Buffer = (VOID*) ((UINT8*)Addr + Size);
+ Private->BufferSize -= Size;
+ return Addr;
+ } else {
+ ASSERT (FALSE);
+ return NULL;
+ }
+}
+
+/**
+ Free routine used by LZMA decompression.
+
+ @param P Pointer to the ISzAlloc instance
+ @param Address The address to be freed
+**/
+VOID
+SzFree (
+ VOID *P,
+ VOID *Address
+ )
+{
+ //
+ // We use the 'scratch buffer' for allocations, so there is no free
+ // operation required. The scratch buffer will be freed by the caller
+ // of the decompression code.
+ //
+}
+
+#define LZMA_HEADER_SIZE (LZMA_PROPS_SIZE + 8)
+
+/**
+ Get the size of the uncompressed buffer by parsing EncodeData header.
+
+ @param EncodedData Pointer to the compressed data.
+
+ @return The size of the uncompressed buffer.
+**/
+UINT64
+GetDecodedSizeOfBuf(
+ UINT8 *EncodedData
+ )
+{
+ UINT64 DecodedSize;
+ INTN Index;
+
+ /* Parse header */
+ DecodedSize = 0;
+ for (Index = LZMA_PROPS_SIZE + 7; Index >= LZMA_PROPS_SIZE; Index--)
+ DecodedSize = LShiftU64(DecodedSize, 8) + EncodedData[Index];
+
+ return DecodedSize;
+}
+
+//
+// LZMA functions and data as defined in local LzmaDecompressLibInternal.h
+//
+
+/**
+ Given a Lzma compressed source buffer, this function retrieves the size of
+ the uncompressed buffer and the size of the scratch buffer required
+ to decompress the compressed source buffer.
+
+ Retrieves the size of the uncompressed buffer and the temporary scratch buffer
+ required to decompress the buffer specified by Source and SourceSize.
+ The size of the uncompressed buffer is returned in DestinationSize,
+ the size of the scratch buffer is returned in ScratchSize, and RETURN_SUCCESS is returned.
+ This function does not have scratch buffer available to perform a thorough
+ checking of the validity of the source data. It just retrieves the "Original Size"
+ field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the uncompressed buffer
+ that will be generated when the compressed buffer specified
+ by Source and SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch buffer that
+ is required to decompress the compressed buffer specified
+ by Source and SourceSize.
+
+ @retval RETURN_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ )
+{
+ UInt64 DecodedSize;
+
+ ASSERT(SourceSize >= LZMA_HEADER_SIZE);
+
+ DecodedSize = GetDecodedSizeOfBuf((UINT8*)Source);
+
+ *DestinationSize = (UINT32)DecodedSize;
+ *ScratchSize = SCRATCH_BUFFER_REQUEST_SIZE;
+ return RETURN_SUCCESS;
+}
+
+/**
+ Decompresses a Lzma compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size of source buffer.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompress (
+ IN CONST VOID *Source,
+ IN UINTN SourceSize,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch
+ )
+{
+ SRes LzmaResult;
+ ELzmaStatus Status;
+ SizeT DecodedBufSize;
+ SizeT EncodedDataSize;
+ ISzAllocWithData AllocFuncs;
+
+ AllocFuncs.Functions.Alloc = SzAlloc;
+ AllocFuncs.Functions.Free = SzFree;
+ AllocFuncs.Buffer = Scratch;
+ AllocFuncs.BufferSize = SCRATCH_BUFFER_REQUEST_SIZE;
+
+ DecodedBufSize = (SizeT)GetDecodedSizeOfBuf((UINT8*)Source);
+ EncodedDataSize = (SizeT) (SourceSize - LZMA_HEADER_SIZE);
+
+ LzmaResult = LzmaDecode(
+ Destination,
+ &DecodedBufSize,
+ (Byte*)((UINT8*)Source + LZMA_HEADER_SIZE),
+ &EncodedDataSize,
+ Source,
+ LZMA_PROPS_SIZE,
+ LZMA_FINISH_END,
+ &Status,
+ &(AllocFuncs.Functions)
+ );
+
+ if (LzmaResult == SZ_OK) {
+ return RETURN_SUCCESS;
+ } else {
+ return RETURN_INVALID_PARAMETER;
+ }
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
new file mode 100644
index 0000000000..498e4e1088
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
new file mode 100644
index 0000000000..3096e91dbe
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/LzmaDecompressLibInternal.h
@@ -0,0 +1,96 @@
+/** @file
+ LZMA Decompress Library internal header file declares Lzma decompress interfaces.
+
+ Copyright (c) 2009 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __LZMADECOMPRESSLIB_INTERNAL_H__
+#define __LZMADECOMPRESSLIB_INTERNAL_H__
+
+#include <PiPei.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ExtractGuidedSectionLib.h>
+#include <Guid/LzmaDecompress.h>
+
+/**
+ Given a Lzma compressed source buffer, this function retrieves the size of
+ the uncompressed buffer and the size of the scratch buffer required
+ to decompress the compressed source buffer.
+
+ Retrieves the size of the uncompressed buffer and the temporary scratch buffer
+ required to decompress the buffer specified by Source and SourceSize.
+ The size of the uncompressed buffer is returned in DestinationSize,
+ the size of the scratch buffer is returned in ScratchSize, and RETURN_SUCCESS is returned.
+ This function does not have scratch buffer available to perform a thorough
+ checking of the validity of the source data. It just retrieves the "Original Size"
+ field from the LZMA_HEADER_SIZE beginning bytes of the source data and output it as DestinationSize.
+ And ScratchSize is specific to the decompression implementation.
+
+ If SourceSize is less than LZMA_HEADER_SIZE, then ASSERT().
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size, in bytes, of the source buffer.
+ @param DestinationSize A pointer to the size, in bytes, of the uncompressed buffer
+ that will be generated when the compressed buffer specified
+ by Source and SourceSize is decompressed.
+ @param ScratchSize A pointer to the size, in bytes, of the scratch buffer that
+ is required to decompress the compressed buffer specified
+ by Source and SourceSize.
+
+ @retval RETURN_SUCCESS The size of the uncompressed data was returned
+ in DestinationSize and the size of the scratch
+ buffer was returned in ScratchSize.
+
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompressGetInfo (
+ IN CONST VOID *Source,
+ IN UINT32 SourceSize,
+ OUT UINT32 *DestinationSize,
+ OUT UINT32 *ScratchSize
+ );
+
+/**
+ Decompresses a Lzma compressed source buffer.
+
+ Extracts decompressed data to its original form.
+ If the compressed source data specified by Source is successfully decompressed
+ into Destination, then RETURN_SUCCESS is returned. If the compressed source data
+ specified by Source is not in a valid compressed data format,
+ then RETURN_INVALID_PARAMETER is returned.
+
+ @param Source The source buffer containing the compressed data.
+ @param SourceSize The size of source buffer.
+ @param Destination The destination buffer to store the decompressed data
+ @param Scratch A temporary scratch buffer that is used to perform the decompression.
+ This is an optional parameter that may be NULL if the
+ required scratch buffer size is 0.
+
+ @retval RETURN_SUCCESS Decompression completed successfully, and
+ the uncompressed buffer is returned in Destination.
+ @retval RETURN_INVALID_PARAMETER
+ The source buffer specified by Source is corrupted
+ (not in a valid compressed format).
+**/
+RETURN_STATUS
+EFIAPI
+LzmaUefiDecompress (
+ IN CONST VOID *Source,
+ IN UINTN SourceSize,
+ IN OUT VOID *Destination,
+ IN OUT VOID *Scratch
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
new file mode 100644
index 0000000000..5a6bcadac6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/7zVersion.h
@@ -0,0 +1,7 @@
+#define MY_VER_MAJOR 4
+#define MY_VER_MINOR 65
+#define MY_VER_BUILD 0
+#define MY_VERSION "4.65"
+#define MY_DATE "2009-02-03"
+#define MY_COPYRIGHT ": Igor Pavlov : Public domain"
+#define MY_VERSION_COPYRIGHT_DATE MY_VERSION " " MY_COPYRIGHT " : " MY_DATE
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
new file mode 100644
index 0000000000..b9018eb991
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra.h
@@ -0,0 +1,60 @@
+/* Bra.h -- Branch converters for executables
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __BRA_H
+#define __BRA_H
+
+#include "Types.h"
+
+/*
+These functions convert relative addresses to absolute addresses
+in CALL instructions to increase the compression ratio.
+
+ In:
+ data - data buffer
+ size - size of data
+ ip - current virtual Instruction Pinter (IP) value
+ state - state variable for x86 converter
+ encoding - 0 (for decoding), 1 (for encoding)
+
+ Out:
+ state - state variable for x86 converter
+
+ Returns:
+ The number of processed bytes. If you call these functions with multiple calls,
+ you must start next call with first byte after block of processed bytes.
+
+ Type Endian Alignment LookAhead
+
+ x86 little 1 4
+ ARMT little 2 2
+ ARM little 4 0
+ PPC big 4 0
+ SPARC big 4 0
+ IA64 little 16 0
+
+ size must be >= Alignment + LookAhead, if it's not last block.
+ If (size < Alignment + LookAhead), converter returns 0.
+
+ Example:
+
+ UInt32 ip = 0;
+ for ()
+ {
+ ; size must be >= Alignment + LookAhead, if it's not last block
+ SizeT processed = Convert(data, size, ip, 1);
+ data += processed;
+ size -= processed;
+ ip += processed;
+ }
+*/
+
+#define x86_Convert_Init(state) { state = 0; }
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding);
+SizeT ARM_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT ARMT_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT PPC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT SPARC_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+SizeT IA64_Convert(Byte *data, SizeT size, UInt32 ip, int encoding);
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
new file mode 100644
index 0000000000..93566cb212
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Bra86.c
@@ -0,0 +1,85 @@
+/* Bra86.c -- Converter for x86 code (BCJ)
+2008-10-04 : Igor Pavlov : Public domain */
+
+#include "Bra.h"
+
+#define Test86MSByte(b) ((b) == 0 || (b) == 0xFF)
+
+const Byte kMaskToAllowedStatus[8] = {1, 1, 1, 0, 1, 0, 0, 0};
+const Byte kMaskToBitNumber[8] = {0, 1, 2, 2, 3, 3, 3, 3};
+
+SizeT x86_Convert(Byte *data, SizeT size, UInt32 ip, UInt32 *state, int encoding)
+{
+ SizeT bufferPos = 0, prevPosT;
+ UInt32 prevMask = *state & 0x7;
+ if (size < 5)
+ return 0;
+ ip += 5;
+ prevPosT = (SizeT)0 - 1;
+
+ for (;;)
+ {
+ Byte *p = data + bufferPos;
+ Byte *limit = data + size - 4;
+ for (; p < limit; p++)
+ if ((*p & 0xFE) == 0xE8)
+ break;
+ bufferPos = (SizeT)(p - data);
+ if (p >= limit)
+ break;
+ prevPosT = bufferPos - prevPosT;
+ if (prevPosT > 3)
+ prevMask = 0;
+ else
+ {
+ prevMask = (prevMask << ((int)prevPosT - 1)) & 0x7;
+ if (prevMask != 0)
+ {
+ Byte b = p[4 - kMaskToBitNumber[prevMask]];
+ if (!kMaskToAllowedStatus[prevMask] || Test86MSByte(b))
+ {
+ prevPosT = bufferPos;
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ continue;
+ }
+ }
+ }
+ prevPosT = bufferPos;
+
+ if (Test86MSByte(p[4]))
+ {
+ UInt32 src = ((UInt32)p[4] << 24) | ((UInt32)p[3] << 16) | ((UInt32)p[2] << 8) | ((UInt32)p[1]);
+ UInt32 dest;
+ for (;;)
+ {
+ Byte b;
+ int index;
+ if (encoding)
+ dest = (ip + (UInt32)bufferPos) + src;
+ else
+ dest = src - (ip + (UInt32)bufferPos);
+ if (prevMask == 0)
+ break;
+ index = kMaskToBitNumber[prevMask] * 8;
+ b = (Byte)(dest >> (24 - index));
+ if (!Test86MSByte(b))
+ break;
+ src = dest ^ ((1 << (32 - index)) - 1);
+ }
+ p[4] = (Byte)(~(((dest >> 24) & 1) - 1));
+ p[3] = (Byte)(dest >> 16);
+ p[2] = (Byte)(dest >> 8);
+ p[1] = (Byte)dest;
+ bufferPos += 5;
+ }
+ else
+ {
+ prevMask = ((prevMask << 1) & 0x7) | 1;
+ bufferPos++;
+ }
+ }
+ prevPosT = bufferPos - prevPosT;
+ *state = ((prevPosT > 3) ? 0 : ((prevMask << ((int)prevPosT - 1)) & 0x7));
+ return bufferPos;
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
new file mode 100644
index 0000000000..006361f2f2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/CpuArch.h
@@ -0,0 +1,69 @@
+/* CpuArch.h
+2008-08-05
+Igor Pavlov
+Public domain */
+
+#ifndef __CPUARCH_H
+#define __CPUARCH_H
+
+/*
+LITTLE_ENDIAN_UNALIGN means:
+ 1) CPU is LITTLE_ENDIAN
+ 2) it's allowed to make unaligned memory accesses
+if LITTLE_ENDIAN_UNALIGN is not defined, it means that we don't know
+about these properties of platform.
+*/
+
+#if defined(_M_IX86) || defined(_M_X64) || defined(_M_AMD64) || defined(__i386__) || defined(__x86_64__)
+#define LITTLE_ENDIAN_UNALIGN
+#endif
+
+#ifdef LITTLE_ENDIAN_UNALIGN
+
+#define GetUi16(p) (*(const UInt16 *)(p))
+#define GetUi32(p) (*(const UInt32 *)(p))
+#define GetUi64(p) (*(const UInt64 *)(p))
+#define SetUi32(p, d) *(UInt32 *)(p) = (d);
+
+#else
+
+#define GetUi16(p) (((const Byte *)(p))[0] | ((UInt16)((const Byte *)(p))[1] << 8))
+
+#define GetUi32(p) ( \
+ ((const Byte *)(p))[0] | \
+ ((UInt32)((const Byte *)(p))[1] << 8) | \
+ ((UInt32)((const Byte *)(p))[2] << 16) | \
+ ((UInt32)((const Byte *)(p))[3] << 24))
+
+#define GetUi64(p) (GetUi32(p) | ((UInt64)GetUi32(((const Byte *)(p)) + 4) << 32))
+
+#define SetUi32(p, d) { UInt32 _x_ = (d); \
+ ((Byte *)(p))[0] = (Byte)_x_; \
+ ((Byte *)(p))[1] = (Byte)(_x_ >> 8); \
+ ((Byte *)(p))[2] = (Byte)(_x_ >> 16); \
+ ((Byte *)(p))[3] = (Byte)(_x_ >> 24); }
+
+#endif
+
+#if defined(LITTLE_ENDIAN_UNALIGN) && defined(_WIN64) && (_MSC_VER >= 1300)
+
+#pragma intrinsic(_byteswap_ulong)
+#pragma intrinsic(_byteswap_uint64)
+#define GetBe32(p) _byteswap_ulong(*(const UInt32 *)(const Byte *)(p))
+#define GetBe64(p) _byteswap_uint64(*(const UInt64 *)(const Byte *)(p))
+
+#else
+
+#define GetBe32(p) ( \
+ ((UInt32)((const Byte *)(p))[0] << 24) | \
+ ((UInt32)((const Byte *)(p))[1] << 16) | \
+ ((UInt32)((const Byte *)(p))[2] << 8) | \
+ ((const Byte *)(p))[3] )
+
+#define GetBe64(p) (((UInt64)GetBe32(p) << 32) | GetBe32(((const Byte *)(p)) + 4))
+
+#endif
+
+#define GetBe16(p) (((UInt16)((const Byte *)(p))[0] << 8) | ((const Byte *)(p))[1])
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
new file mode 100644
index 0000000000..492cea2e41
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.c
@@ -0,0 +1,770 @@
+/** @file
+ LzFind.c
+
+ Based on LZMA SDK 4.65:
+ LzFind.c -- Match finder for LZ algorithms
+ 2008-10-04 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef EFIAPI
+
+#include <string.h>
+
+#endif // !EFIAPI
+
+#include "LzFind.h"
+#include "LzHash.h"
+
+#define kEmptyHashValue 0
+#define kMaxValForNormalize ((UInt32)0xFFFFFFFF)
+#define kNormalizeStepMin (1 << 10) /* it must be power of 2 */
+#define kNormalizeMask (~(kNormalizeStepMin - 1))
+#define kMaxHistorySize ((UInt32)3 << 30)
+
+#define kStartMaxLen 3
+
+static void LzInWindow_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ if (!p->directInput)
+ {
+ alloc->Free(alloc, p->bufferBase);
+ p->bufferBase = 0;
+ }
+}
+
+/* keepSizeBefore + keepSizeAfter + keepSizeReserv must be < 4G) */
+
+static int LzInWindow_Create(CMatchFinder *p, UInt32 keepSizeReserv, ISzAlloc *alloc)
+{
+ UInt32 blockSize = p->keepSizeBefore + p->keepSizeAfter + keepSizeReserv;
+ if (p->directInput)
+ {
+ p->blockSize = blockSize;
+ return 1;
+ }
+ if (p->bufferBase == 0 || p->blockSize != blockSize)
+ {
+ LzInWindow_Free(p, alloc);
+ p->blockSize = blockSize;
+ p->bufferBase = (Byte *)alloc->Alloc(alloc, (size_t)blockSize);
+ }
+ return (p->bufferBase != 0);
+}
+
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p) { return p->buffer; }
+Byte MatchFinder_GetIndexByte(CMatchFinder *p, Int32 index) { return p->buffer[index]; }
+
+UInt32 MatchFinder_GetNumAvailableBytes(CMatchFinder *p) { return p->streamPos - p->pos; }
+
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue)
+{
+ p->posLimit -= subValue;
+ p->pos -= subValue;
+ p->streamPos -= subValue;
+}
+
+static void MatchFinder_ReadBlock(CMatchFinder *p)
+{
+ if (p->streamEndWasReached || p->result != SZ_OK)
+ return;
+ for (;;)
+ {
+ Byte *dest = p->buffer + (p->streamPos - p->pos);
+ size_t size = (p->bufferBase + p->blockSize - dest);
+ if (size == 0)
+ return;
+ p->result = p->stream->Read(p->stream, dest, &size);
+ if (p->result != SZ_OK)
+ return;
+ if (size == 0)
+ {
+ p->streamEndWasReached = 1;
+ return;
+ }
+ p->streamPos += (UInt32)size;
+ if (p->streamPos - p->pos > p->keepSizeAfter)
+ return;
+ }
+}
+
+void MatchFinder_MoveBlock(CMatchFinder *p)
+{
+ memmove(p->bufferBase,
+ p->buffer - p->keepSizeBefore,
+ (size_t)(p->streamPos - p->pos + p->keepSizeBefore));
+ p->buffer = p->bufferBase + p->keepSizeBefore;
+}
+
+int MatchFinder_NeedMove(CMatchFinder *p)
+{
+ /* if (p->streamEndWasReached) return 0; */
+ return ((size_t)(p->bufferBase + p->blockSize - p->buffer) <= p->keepSizeAfter);
+}
+
+void MatchFinder_ReadIfRequired(CMatchFinder *p)
+{
+ if (p->streamEndWasReached)
+ return;
+ if (p->keepSizeAfter >= p->streamPos - p->pos)
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_CheckAndMoveAndRead(CMatchFinder *p)
+{
+ if (MatchFinder_NeedMove(p))
+ MatchFinder_MoveBlock(p);
+ MatchFinder_ReadBlock(p);
+}
+
+static void MatchFinder_SetDefaultSettings(CMatchFinder *p)
+{
+ p->cutValue = 32;
+ p->btMode = 1;
+ p->numHashBytes = 4;
+ /* p->skipModeBits = 0; */
+ p->directInput = 0;
+ p->bigHash = 0;
+}
+
+#define kCrcPoly 0xEDB88320
+
+void MatchFinder_Construct(CMatchFinder *p)
+{
+ UInt32 i;
+ p->bufferBase = 0;
+ p->directInput = 0;
+ p->hash = 0;
+ MatchFinder_SetDefaultSettings(p);
+
+ for (i = 0; i < 256; i++)
+ {
+ UInt32 r = i;
+ int j;
+ for (j = 0; j < 8; j++)
+ r = (r >> 1) ^ (kCrcPoly & ~((r & 1) - 1));
+ p->crc[i] = r;
+ }
+}
+
+static void MatchFinder_FreeThisClassMemory(CMatchFinder *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->hash);
+ p->hash = 0;
+}
+
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc)
+{
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ LzInWindow_Free(p, alloc);
+}
+
+static CLzRef* AllocRefs(UInt32 num, ISzAlloc *alloc)
+{
+ size_t sizeInBytes = (size_t)num * sizeof(CLzRef);
+ if (sizeInBytes / sizeof(CLzRef) != num)
+ return 0;
+ return (CLzRef *)alloc->Alloc(alloc, sizeInBytes);
+}
+
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc)
+{
+ UInt32 sizeReserv;
+ if (historySize > kMaxHistorySize)
+ {
+ MatchFinder_Free(p, alloc);
+ return 0;
+ }
+ sizeReserv = historySize >> 1;
+ if (historySize > ((UInt32)2 << 30))
+ sizeReserv = historySize >> 2;
+ sizeReserv += (keepAddBufferBefore + matchMaxLen + keepAddBufferAfter) / 2 + (1 << 19);
+
+ p->keepSizeBefore = historySize + keepAddBufferBefore + 1;
+ p->keepSizeAfter = matchMaxLen + keepAddBufferAfter;
+ /* we need one additional byte, since we use MoveBlock after pos++ and before dictionary using */
+ if (LzInWindow_Create(p, sizeReserv, alloc))
+ {
+ UInt32 newCyclicBufferSize = (historySize /* >> p->skipModeBits */) + 1;
+ UInt32 hs;
+ p->matchMaxLen = matchMaxLen;
+ {
+ p->fixedHashSize = 0;
+ if (p->numHashBytes == 2)
+ hs = (1 << 16) - 1;
+ else
+ {
+ hs = historySize - 1;
+ hs |= (hs >> 1);
+ hs |= (hs >> 2);
+ hs |= (hs >> 4);
+ hs |= (hs >> 8);
+ hs >>= 1;
+ /* hs >>= p->skipModeBits; */
+ hs |= 0xFFFF; /* don't change it! It's required for Deflate */
+ if (hs > (1 << 24))
+ {
+ if (p->numHashBytes == 3)
+ hs = (1 << 24) - 1;
+ else
+ hs >>= 1;
+ }
+ }
+ p->hashMask = hs;
+ hs++;
+ if (p->numHashBytes > 2) p->fixedHashSize += kHash2Size;
+ if (p->numHashBytes > 3) p->fixedHashSize += kHash3Size;
+ if (p->numHashBytes > 4) p->fixedHashSize += kHash4Size;
+ hs += p->fixedHashSize;
+ }
+
+ {
+ UInt32 prevSize = p->hashSizeSum + p->numSons;
+ UInt32 newSize;
+ p->historySize = historySize;
+ p->hashSizeSum = hs;
+ p->cyclicBufferSize = newCyclicBufferSize;
+ p->numSons = (p->btMode ? newCyclicBufferSize * 2 : newCyclicBufferSize);
+ newSize = p->hashSizeSum + p->numSons;
+ if (p->hash != 0 && prevSize == newSize)
+ return 1;
+ MatchFinder_FreeThisClassMemory(p, alloc);
+ p->hash = AllocRefs(newSize, alloc);
+ if (p->hash != 0)
+ {
+ p->son = p->hash + p->hashSizeSum;
+ return 1;
+ }
+ }
+ }
+ MatchFinder_Free(p, alloc);
+ return 0;
+}
+
+static void MatchFinder_SetLimits(CMatchFinder *p)
+{
+ UInt32 limit = kMaxValForNormalize - p->pos;
+ UInt32 limit2 = p->cyclicBufferSize - p->cyclicBufferPos;
+ if (limit2 < limit)
+ limit = limit2;
+ limit2 = p->streamPos - p->pos;
+ if (limit2 <= p->keepSizeAfter)
+ {
+ if (limit2 > 0)
+ limit2 = 1;
+ }
+ else
+ limit2 -= p->keepSizeAfter;
+ if (limit2 < limit)
+ limit = limit2;
+ {
+ UInt32 lenLimit = p->streamPos - p->pos;
+ if (lenLimit > p->matchMaxLen)
+ lenLimit = p->matchMaxLen;
+ p->lenLimit = lenLimit;
+ }
+ p->posLimit = p->pos + limit;
+}
+
+void MatchFinder_Init(CMatchFinder *p)
+{
+ UInt32 i;
+ for (i = 0; i < p->hashSizeSum; i++)
+ p->hash[i] = kEmptyHashValue;
+ p->cyclicBufferPos = 0;
+ p->buffer = p->bufferBase;
+ p->pos = p->streamPos = p->cyclicBufferSize;
+ p->result = SZ_OK;
+ p->streamEndWasReached = 0;
+ MatchFinder_ReadBlock(p);
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 MatchFinder_GetSubValue(CMatchFinder *p)
+{
+ return (p->pos - p->historySize - 1) & kNormalizeMask;
+}
+
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems)
+{
+ UInt32 i;
+ for (i = 0; i < numItems; i++)
+ {
+ UInt32 value = items[i];
+ if (value <= subValue)
+ value = kEmptyHashValue;
+ else
+ value -= subValue;
+ items[i] = value;
+ }
+}
+
+static void MatchFinder_Normalize(CMatchFinder *p)
+{
+ UInt32 subValue = MatchFinder_GetSubValue(p);
+ MatchFinder_Normalize3(subValue, p->hash, p->hashSizeSum + p->numSons);
+ MatchFinder_ReduceOffsets(p, subValue);
+}
+
+static void MatchFinder_CheckLimits(CMatchFinder *p)
+{
+ if (p->pos == kMaxValForNormalize)
+ MatchFinder_Normalize(p);
+ if (!p->streamEndWasReached && p->keepSizeAfter == p->streamPos - p->pos)
+ MatchFinder_CheckAndMoveAndRead(p);
+ if (p->cyclicBufferPos == p->cyclicBufferSize)
+ p->cyclicBufferPos = 0;
+ MatchFinder_SetLimits(p);
+}
+
+static UInt32 * Hc_GetMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ son[_cyclicBufferPos] = curMatch;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ return distances;
+ {
+ const Byte *pb = cur - delta;
+ curMatch = son[_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)];
+ if (pb[maxLen] == cur[maxLen] && *pb == *cur)
+ {
+ UInt32 len = 0;
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ return distances;
+ }
+ }
+ }
+ }
+}
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue,
+ UInt32 *distances, UInt32 maxLen)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return distances;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ if (++len != lenLimit && pb[len] == cur[len])
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ if (maxLen < len)
+ {
+ *distances++ = maxLen = len;
+ *distances++ = delta - 1;
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return distances;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+static void SkipMatchesSpec(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *cur, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 cutValue)
+{
+ CLzRef *ptr0 = son + (_cyclicBufferPos << 1) + 1;
+ CLzRef *ptr1 = son + (_cyclicBufferPos << 1);
+ UInt32 len0 = 0, len1 = 0;
+ for (;;)
+ {
+ UInt32 delta = pos - curMatch;
+ if (cutValue-- == 0 || delta >= _cyclicBufferSize)
+ {
+ *ptr0 = *ptr1 = kEmptyHashValue;
+ return;
+ }
+ {
+ CLzRef *pair = son + ((_cyclicBufferPos - delta + ((delta > _cyclicBufferPos) ? _cyclicBufferSize : 0)) << 1);
+ const Byte *pb = cur - delta;
+ UInt32 len = (len0 < len1 ? len0 : len1);
+ if (pb[len] == cur[len])
+ {
+ while (++len != lenLimit)
+ if (pb[len] != cur[len])
+ break;
+ {
+ if (len == lenLimit)
+ {
+ *ptr1 = pair[0];
+ *ptr0 = pair[1];
+ return;
+ }
+ }
+ }
+ if (pb[len] < cur[len])
+ {
+ *ptr1 = curMatch;
+ ptr1 = pair + 1;
+ curMatch = *ptr1;
+ len1 = len;
+ }
+ else
+ {
+ *ptr0 = curMatch;
+ ptr0 = pair;
+ curMatch = *ptr0;
+ len0 = len;
+ }
+ }
+ }
+}
+
+#define MOVE_POS \
+ ++p->cyclicBufferPos; \
+ p->buffer++; \
+ if (++p->pos == p->posLimit) MatchFinder_CheckLimits(p);
+
+#define MOVE_POS_RET MOVE_POS return offset;
+
+static void MatchFinder_MovePos(CMatchFinder *p) { MOVE_POS; }
+
+#define GET_MATCHES_HEADER2(minLen, ret_op) \
+ UInt32 lenLimit; UInt32 hashValue; const Byte *cur; UInt32 curMatch; \
+ lenLimit = p->lenLimit; { if (lenLimit < minLen) { MatchFinder_MovePos(p); ret_op; }} \
+ cur = p->buffer;
+
+#define GET_MATCHES_HEADER(minLen) GET_MATCHES_HEADER2(minLen, return 0)
+#define SKIP_HEADER(minLen) GET_MATCHES_HEADER2(minLen, continue)
+
+#define MF_PARAMS(p) p->pos, p->buffer, p->son, p->cyclicBufferPos, p->cyclicBufferSize, p->cutValue
+
+#define GET_MATCHES_FOOTER(offset, maxLen) \
+ offset = (UInt32)(GetMatchesSpec1(lenLimit, curMatch, MF_PARAMS(p), \
+ distances + offset, maxLen) - distances); MOVE_POS_RET;
+
+#define SKIP_FOOTER \
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p)); MOVE_POS;
+
+static UInt32 Bt2_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 1)
+}
+
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = 0;
+ GET_MATCHES_FOOTER(offset, 2)
+}
+
+static UInt32 Bt3_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, delta2, maxLen, offset;
+ GET_MATCHES_HEADER(3)
+
+ HASH3_CALC;
+
+ delta2 = p->pos - p->hash[hash2Value];
+ curMatch = p->hash[kFix3HashSize + hashValue];
+
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+
+
+ maxLen = 2;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[0] = maxLen;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Bt4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ SkipMatchesSpec(lenLimit, curMatch, MF_PARAMS(p));
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ GET_MATCHES_FOOTER(offset, maxLen)
+}
+
+static UInt32 Hc4_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 hash2Value, hash3Value, delta2, delta3, maxLen, offset;
+ GET_MATCHES_HEADER(4)
+
+ HASH4_CALC;
+
+ delta2 = p->pos - p->hash[ hash2Value];
+ delta3 = p->pos - p->hash[kFix3HashSize + hash3Value];
+ curMatch = p->hash[kFix4HashSize + hashValue];
+
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+
+ maxLen = 1;
+ offset = 0;
+ if (delta2 < p->cyclicBufferSize && *(cur - delta2) == *cur)
+ {
+ distances[0] = maxLen = 2;
+ distances[1] = delta2 - 1;
+ offset = 2;
+ }
+ if (delta2 != delta3 && delta3 < p->cyclicBufferSize && *(cur - delta3) == *cur)
+ {
+ maxLen = 3;
+ distances[offset + 1] = delta3 - 1;
+ offset += 2;
+ delta2 = delta3;
+ }
+ if (offset != 0)
+ {
+ for (; maxLen != lenLimit; maxLen++)
+ if (cur[(ptrdiff_t)maxLen - delta2] != cur[maxLen])
+ break;
+ distances[offset - 2] = maxLen;
+ if (maxLen == lenLimit)
+ {
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS_RET;
+ }
+ }
+ if (maxLen < 3)
+ maxLen = 3;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances + offset, maxLen) - (distances));
+ MOVE_POS_RET
+}
+
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances)
+{
+ UInt32 offset;
+ GET_MATCHES_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ offset = (UInt32)(Hc_GetMatchesSpec(lenLimit, curMatch, MF_PARAMS(p),
+ distances, 2) - (distances));
+ MOVE_POS_RET
+}
+
+static void Bt2_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(2)
+ HASH2_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt3_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value;
+ SKIP_HEADER(3)
+ HASH3_CALC;
+ curMatch = p->hash[kFix3HashSize + hashValue];
+ p->hash[hash2Value] =
+ p->hash[kFix3HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Bt4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] = p->pos;
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ SKIP_FOOTER
+ }
+ while (--num != 0);
+}
+
+static void Hc4_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ UInt32 hash2Value, hash3Value;
+ SKIP_HEADER(4)
+ HASH4_CALC;
+ curMatch = p->hash[kFix4HashSize + hashValue];
+ p->hash[ hash2Value] =
+ p->hash[kFix3HashSize + hash3Value] =
+ p->hash[kFix4HashSize + hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num)
+{
+ do
+ {
+ SKIP_HEADER(3)
+ HASH_ZIP_CALC;
+ curMatch = p->hash[hashValue];
+ p->hash[hashValue] = p->pos;
+ p->son[p->cyclicBufferPos] = curMatch;
+ MOVE_POS
+ }
+ while (--num != 0);
+}
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable)
+{
+ vTable->Init = (Mf_Init_Func)MatchFinder_Init;
+ vTable->GetIndexByte = (Mf_GetIndexByte_Func)MatchFinder_GetIndexByte;
+ vTable->GetNumAvailableBytes = (Mf_GetNumAvailableBytes_Func)MatchFinder_GetNumAvailableBytes;
+ vTable->GetPointerToCurrentPos = (Mf_GetPointerToCurrentPos_Func)MatchFinder_GetPointerToCurrentPos;
+ if (!p->btMode)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Hc4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Hc4_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 2)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt2_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt2_MatchFinder_Skip;
+ }
+ else if (p->numHashBytes == 3)
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt3_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt3_MatchFinder_Skip;
+ }
+ else
+ {
+ vTable->GetMatches = (Mf_GetMatches_Func)Bt4_MatchFinder_GetMatches;
+ vTable->Skip = (Mf_Skip_Func)Bt4_MatchFinder_Skip;
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
new file mode 100644
index 0000000000..423d67e0c3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzFind.h
@@ -0,0 +1,107 @@
+/* LzFind.h -- Match finder for LZ algorithms
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZFIND_H
+#define __LZFIND_H
+
+#include "Types.h"
+
+typedef UInt32 CLzRef;
+
+typedef struct _CMatchFinder
+{
+ Byte *buffer;
+ UInt32 pos;
+ UInt32 posLimit;
+ UInt32 streamPos;
+ UInt32 lenLimit;
+
+ UInt32 cyclicBufferPos;
+ UInt32 cyclicBufferSize; /* it must be = (historySize + 1) */
+
+ UInt32 matchMaxLen;
+ CLzRef *hash;
+ CLzRef *son;
+ UInt32 hashMask;
+ UInt32 cutValue;
+
+ Byte *bufferBase;
+ ISeqInStream *stream;
+ int streamEndWasReached;
+
+ UInt32 blockSize;
+ UInt32 keepSizeBefore;
+ UInt32 keepSizeAfter;
+
+ UInt32 numHashBytes;
+ int directInput;
+ int btMode;
+ /* int skipModeBits; */
+ int bigHash;
+ UInt32 historySize;
+ UInt32 fixedHashSize;
+ UInt32 hashSizeSum;
+ UInt32 numSons;
+ SRes result;
+ UInt32 crc[256];
+} CMatchFinder;
+
+#define Inline_MatchFinder_GetPointerToCurrentPos(p) ((p)->buffer)
+#define Inline_MatchFinder_GetIndexByte(p, index) ((p)->buffer[(Int32)(index)])
+
+#define Inline_MatchFinder_GetNumAvailableBytes(p) ((p)->streamPos - (p)->pos)
+
+int MatchFinder_NeedMove(CMatchFinder *p);
+Byte *MatchFinder_GetPointerToCurrentPos(CMatchFinder *p);
+void MatchFinder_MoveBlock(CMatchFinder *p);
+void MatchFinder_ReadIfRequired(CMatchFinder *p);
+
+void MatchFinder_Construct(CMatchFinder *p);
+
+/* Conditions:
+ historySize <= 3 GB
+ keepAddBufferBefore + matchMaxLen + keepAddBufferAfter < 511MB
+*/
+int MatchFinder_Create(CMatchFinder *p, UInt32 historySize,
+ UInt32 keepAddBufferBefore, UInt32 matchMaxLen, UInt32 keepAddBufferAfter,
+ ISzAlloc *alloc);
+void MatchFinder_Free(CMatchFinder *p, ISzAlloc *alloc);
+void MatchFinder_Normalize3(UInt32 subValue, CLzRef *items, UInt32 numItems);
+void MatchFinder_ReduceOffsets(CMatchFinder *p, UInt32 subValue);
+
+UInt32 * GetMatchesSpec1(UInt32 lenLimit, UInt32 curMatch, UInt32 pos, const Byte *buffer, CLzRef *son,
+ UInt32 _cyclicBufferPos, UInt32 _cyclicBufferSize, UInt32 _cutValue,
+ UInt32 *distances, UInt32 maxLen);
+
+/*
+Conditions:
+ Mf_GetNumAvailableBytes_Func must be called before each Mf_GetMatchLen_Func.
+ Mf_GetPointerToCurrentPos_Func's result must be used only before any other function
+*/
+
+typedef void (*Mf_Init_Func)(void *object);
+typedef Byte (*Mf_GetIndexByte_Func)(void *object, Int32 index);
+typedef UInt32 (*Mf_GetNumAvailableBytes_Func)(void *object);
+typedef const Byte * (*Mf_GetPointerToCurrentPos_Func)(void *object);
+typedef UInt32 (*Mf_GetMatches_Func)(void *object, UInt32 *distances);
+typedef void (*Mf_Skip_Func)(void *object, UInt32);
+
+typedef struct _IMatchFinder
+{
+ Mf_Init_Func Init;
+ Mf_GetIndexByte_Func GetIndexByte;
+ Mf_GetNumAvailableBytes_Func GetNumAvailableBytes;
+ Mf_GetPointerToCurrentPos_Func GetPointerToCurrentPos;
+ Mf_GetMatches_Func GetMatches;
+ Mf_Skip_Func Skip;
+} IMatchFinder;
+
+void MatchFinder_CreateVTable(CMatchFinder *p, IMatchFinder *vTable);
+
+void MatchFinder_Init(CMatchFinder *p);
+UInt32 Bt3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+UInt32 Hc3Zip_MatchFinder_GetMatches(CMatchFinder *p, UInt32 *distances);
+void Bt3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+void Hc3Zip_MatchFinder_Skip(CMatchFinder *p, UInt32 num);
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
new file mode 100644
index 0000000000..c923417501
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzHash.h
@@ -0,0 +1,54 @@
+/* LzHash.h -- HASH functions for LZ algorithms
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZHASH_H
+#define __LZHASH_H
+
+#define kHash2Size (1 << 10)
+#define kHash3Size (1 << 16)
+#define kHash4Size (1 << 20)
+
+#define kFix3HashSize (kHash2Size)
+#define kFix4HashSize (kHash2Size + kHash3Size)
+#define kFix5HashSize (kHash2Size + kHash3Size + kHash4Size)
+
+#define HASH2_CALC hashValue = cur[0] | ((UInt32)cur[1] << 8);
+
+#define HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8)) & p->hashMask; }
+
+#define HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hashValue = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & p->hashMask; }
+
+#define HASH5_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)); \
+ hashValue = (hash4Value ^ (p->crc[cur[4]] << 3)) & p->hashMask; \
+ hash4Value &= (kHash4Size - 1); }
+
+/* #define HASH_ZIP_CALC hashValue = ((cur[0] | ((UInt32)cur[1] << 8)) ^ p->crc[cur[2]]) & 0xFFFF; */
+#define HASH_ZIP_CALC hashValue = ((cur[2] | ((UInt32)cur[0] << 8)) ^ p->crc[cur[1]]) & 0xFFFF;
+
+
+#define MT_HASH2_CALC \
+ hash2Value = (p->crc[cur[0]] ^ cur[1]) & (kHash2Size - 1);
+
+#define MT_HASH3_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); }
+
+#define MT_HASH4_CALC { \
+ UInt32 temp = p->crc[cur[0]] ^ cur[1]; \
+ hash2Value = temp & (kHash2Size - 1); \
+ hash3Value = (temp ^ ((UInt32)cur[2] << 8)) & (kHash3Size - 1); \
+ hash4Value = (temp ^ ((UInt32)cur[2] << 8) ^ (p->crc[cur[3]] << 5)) & (kHash4Size - 1); }
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
new file mode 100644
index 0000000000..e3db4edbb4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.c
@@ -0,0 +1,1026 @@
+/** @file
+ LzmaDec.c
+
+ Based on LZMA SDK 4.65:
+ LzmaDec.c -- LZMA Decoder
+ 2008-11-06 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "LzmaDec.h"
+
+#ifndef EFIAPI
+
+#include <string.h>
+
+#endif // !EFIAPI
+
+#define kNumTopBits 24
+#define kTopValue ((UInt32)1 << kNumTopBits)
+
+#define kNumBitModelTotalBits 11
+#define kBitModelTotal (1 << kNumBitModelTotalBits)
+#define kNumMoveBits 5
+
+#define RC_INIT_SIZE 5
+
+#define NORMALIZE if (range < kTopValue) { range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0(p) ttt = *(p); NORMALIZE; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0(p) range = bound; *(p) = (CLzmaProb)(ttt + ((kBitModelTotal - ttt) >> kNumMoveBits));
+#define UPDATE_1(p) range -= bound; code -= bound; *(p) = (CLzmaProb)(ttt - (ttt >> kNumMoveBits));
+#define GET_BIT2(p, i, A0, A1) IF_BIT_0(p) \
+ { UPDATE_0(p); i = (i + i); A0; } else \
+ { UPDATE_1(p); i = (i + i) + 1; A1; }
+#define GET_BIT(p, i) GET_BIT2(p, i, ; , ;)
+
+#define TREE_GET_BIT(probs, i) { GET_BIT((probs + i), i); }
+#define TREE_DECODE(probs, limit, i) \
+ { i = 1; do { TREE_GET_BIT(probs, i); } while (i < limit); i -= limit; }
+
+/* #define _LZMA_SIZE_OPT */
+
+#ifdef _LZMA_SIZE_OPT
+#define TREE_6_DECODE(probs, i) TREE_DECODE(probs, (1 << 6), i)
+#else
+#define TREE_6_DECODE(probs, i) \
+ { i = 1; \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ TREE_GET_BIT(probs, i); \
+ i -= 0x40; }
+#endif
+
+#define NORMALIZE_CHECK if (range < kTopValue) { if (buf >= bufLimit) return DUMMY_ERROR; range <<= 8; code = (code << 8) | (*buf++); }
+
+#define IF_BIT_0_CHECK(p) ttt = *(p); NORMALIZE_CHECK; bound = (range >> kNumBitModelTotalBits) * ttt; if (code < bound)
+#define UPDATE_0_CHECK range = bound;
+#define UPDATE_1_CHECK range -= bound; code -= bound;
+#define GET_BIT2_CHECK(p, i, A0, A1) IF_BIT_0_CHECK(p) \
+ { UPDATE_0_CHECK; i = (i + i); A0; } else \
+ { UPDATE_1_CHECK; i = (i + i) + 1; A1; }
+#define GET_BIT_CHECK(p, i) GET_BIT2_CHECK(p, i, ; , ;)
+#define TREE_DECODE_CHECK(probs, limit, i) \
+ { i = 1; do { GET_BIT_CHECK(probs + i, i) } while (i < limit); i -= limit; }
+
+
+#define kNumPosBitsMax 4
+#define kNumPosStatesMax (1 << kNumPosBitsMax)
+
+#define kLenNumLowBits 3
+#define kLenNumLowSymbols (1 << kLenNumLowBits)
+#define kLenNumMidBits 3
+#define kLenNumMidSymbols (1 << kLenNumMidBits)
+#define kLenNumHighBits 8
+#define kLenNumHighSymbols (1 << kLenNumHighBits)
+
+#define LenChoice 0
+#define LenChoice2 (LenChoice + 1)
+#define LenLow (LenChoice2 + 1)
+#define LenMid (LenLow + (kNumPosStatesMax << kLenNumLowBits))
+#define LenHigh (LenMid + (kNumPosStatesMax << kLenNumMidBits))
+#define kNumLenProbs (LenHigh + kLenNumHighSymbols)
+
+
+#define kNumStates 12
+#define kNumLitStates 7
+
+#define kStartPosModelIndex 4
+#define kEndPosModelIndex 14
+#define kNumFullDistances (1 << (kEndPosModelIndex >> 1))
+
+#define kNumPosSlotBits 6
+#define kNumLenToPosStates 4
+
+#define kNumAlignBits 4
+#define kAlignTableSize (1 << kNumAlignBits)
+
+#define kMatchMinLen 2
+#define kMatchSpecLenStart (kMatchMinLen + kLenNumLowSymbols + kLenNumMidSymbols + kLenNumHighSymbols)
+
+#define IsMatch 0
+#define IsRep (IsMatch + (kNumStates << kNumPosBitsMax))
+#define IsRepG0 (IsRep + kNumStates)
+#define IsRepG1 (IsRepG0 + kNumStates)
+#define IsRepG2 (IsRepG1 + kNumStates)
+#define IsRep0Long (IsRepG2 + kNumStates)
+#define PosSlot (IsRep0Long + (kNumStates << kNumPosBitsMax))
+#define SpecPos (PosSlot + (kNumLenToPosStates << kNumPosSlotBits))
+#define Align (SpecPos + kNumFullDistances - kEndPosModelIndex)
+#define LenCoder (Align + kAlignTableSize)
+#define RepLenCoder (LenCoder + kNumLenProbs)
+#define Literal (RepLenCoder + kNumLenProbs)
+
+#define LZMA_BASE_SIZE 1846
+#define LZMA_LIT_SIZE 768
+
+#define LzmaProps_GetNumProbs(p) ((UInt32)LZMA_BASE_SIZE + (LZMA_LIT_SIZE << ((p)->lc + (p)->lp)))
+
+#if Literal != LZMA_BASE_SIZE
+StopCompilingDueBUG
+#endif
+
+static const Byte kLiteralNextStates[kNumStates * 2] =
+{
+ 0, 0, 0, 0, 1, 2, 3, 4, 5, 6, 4, 5,
+ 7, 7, 7, 7, 7, 7, 7, 10, 10, 10, 10, 10
+};
+
+#define LZMA_DIC_MIN (1 << 12)
+
+/* First LZMA-symbol is always decoded.
+And it decodes new LZMA-symbols while (buf < bufLimit), but "buf" is without last normalization
+Out:
+ Result:
+ SZ_OK - OK
+ SZ_ERROR_DATA - Error
+ p->remainLen:
+ < kMatchSpecLenStart : normal remain
+ = kMatchSpecLenStart : finished
+ = kMatchSpecLenStart + 1 : Flush marker
+ = kMatchSpecLenStart + 2 : State Init Marker
+*/
+
+static int MY_FAST_CALL LzmaDec_DecodeReal(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ CLzmaProb *probs = p->probs;
+
+ unsigned state = p->state;
+ UInt32 rep0 = p->reps[0], rep1 = p->reps[1], rep2 = p->reps[2], rep3 = p->reps[3];
+ unsigned pbMask = ((unsigned)1 << (p->prop.pb)) - 1;
+ unsigned lpMask = ((unsigned)1 << (p->prop.lp)) - 1;
+ unsigned lc = p->prop.lc;
+
+ Byte *dic = p->dic;
+ SizeT dicBufSize = p->dicBufSize;
+ SizeT dicPos = p->dicPos;
+
+ UInt32 processedPos = p->processedPos;
+ UInt32 checkDicSize = p->checkDicSize;
+ unsigned len = 0;
+
+ const Byte *buf = p->buf;
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+
+ do
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = processedPos & pbMask;
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ unsigned symbol;
+ UPDATE_0(prob);
+ prob = probs + Literal;
+ if (checkDicSize != 0 || processedPos != 0)
+ prob += (LZMA_LIT_SIZE * (((processedPos & lpMask) << lc) +
+ (dic[(dicPos == 0 ? dicBufSize : dicPos) - 1] >> (8 - lc))));
+
+ if (state < kNumLitStates)
+ {
+ symbol = 1;
+ do { GET_BIT(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ unsigned offs = 0x100;
+ symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ dic[dicPos++] = (Byte)symbol;
+ processedPos++;
+
+ state = kLiteralNextStates[state];
+ /* if (state < 4) state = 0; else if (state < 10) state -= 3; else state -= 6; */
+ continue;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRep + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ state += kNumStates;
+ prob = probs + LenCoder;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ if (checkDicSize == 0 && processedPos == 0)
+ return SZ_ERROR_DATA;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ processedPos++;
+ state = state < kNumLitStates ? 9 : 11;
+ continue;
+ }
+ UPDATE_1(prob);
+ }
+ else
+ {
+ UInt32 distance;
+ UPDATE_1(prob);
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep1;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0(prob)
+ {
+ UPDATE_0(prob);
+ distance = rep2;
+ }
+ else
+ {
+ UPDATE_1(prob);
+ distance = rep3;
+ rep3 = rep2;
+ }
+ rep2 = rep1;
+ }
+ rep1 = rep0;
+ rep0 = distance;
+ }
+ state = state < kNumLitStates ? 8 : 11;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit2, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit2 = (1 << kLenNumLowBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenChoice2;
+ IF_BIT_0(probLen)
+ {
+ UPDATE_0(probLen);
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit2 = (1 << kLenNumMidBits);
+ }
+ else
+ {
+ UPDATE_1(probLen);
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit2 = (1 << kLenNumHighBits);
+ }
+ }
+ TREE_DECODE(probLen, limit2, len);
+ len += offset;
+ }
+
+ if (state >= kNumStates)
+ {
+ UInt32 distance;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) << kNumPosSlotBits);
+ TREE_6_DECODE(prob, distance);
+ if (distance >= kStartPosModelIndex)
+ {
+ unsigned posSlot = (unsigned)distance;
+ int numDirectBits = (int)(((distance >> 1) - 1));
+ distance = (2 | (distance & 1));
+ if (posSlot < kEndPosModelIndex)
+ {
+ distance <<= numDirectBits;
+ prob = probs + SpecPos + distance - posSlot - 1;
+ {
+ UInt32 mask = 1;
+ unsigned i = 1;
+ do
+ {
+ GET_BIT2(prob + i, i, ; , distance |= mask);
+ mask <<= 1;
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE
+ range >>= 1;
+
+ {
+ UInt32 t;
+ code -= range;
+ t = (0 - ((UInt32)code >> 31)); /* (UInt32)((Int32)code >> 31) */
+ distance = (distance << 1) + (t + 1);
+ code += range & t;
+ }
+ /*
+ distance <<= 1;
+ if (code >= range)
+ {
+ code -= range;
+ distance |= 1;
+ }
+ */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ distance <<= kNumAlignBits;
+ {
+ unsigned i = 1;
+ GET_BIT2(prob + i, i, ; , distance |= 1);
+ GET_BIT2(prob + i, i, ; , distance |= 2);
+ GET_BIT2(prob + i, i, ; , distance |= 4);
+ GET_BIT2(prob + i, i, ; , distance |= 8);
+ }
+ if (distance == (UInt32)0xFFFFFFFF)
+ {
+ len += kMatchSpecLenStart;
+ state -= kNumStates;
+ break;
+ }
+ }
+ }
+ rep3 = rep2;
+ rep2 = rep1;
+ rep1 = rep0;
+ rep0 = distance + 1;
+ if (checkDicSize == 0)
+ {
+ if (distance >= processedPos)
+ return SZ_ERROR_DATA;
+ }
+ else if (distance >= checkDicSize)
+ return SZ_ERROR_DATA;
+ state = (state < kNumStates + kNumLitStates) ? kNumLitStates : kNumLitStates + 3;
+ /* state = kLiteralNextStates[state]; */
+ }
+
+ len += kMatchMinLen;
+
+ if (limit == dicPos)
+ return SZ_ERROR_DATA;
+ {
+ SizeT rem = limit - dicPos;
+ unsigned curLen = ((rem < len) ? (unsigned)rem : len);
+ SizeT pos = (dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0);
+
+ processedPos += curLen;
+
+ len -= curLen;
+ if (pos + curLen <= dicBufSize)
+ {
+ Byte *dest = dic + dicPos;
+ ptrdiff_t src = (ptrdiff_t)pos - (ptrdiff_t)dicPos;
+ const Byte *lim = dest + curLen;
+ dicPos += curLen;
+ do
+ *((volatile Byte *)dest) = (Byte)*(dest + src);
+ while (++dest != lim);
+ }
+ else
+ {
+ do
+ {
+ dic[dicPos++] = dic[pos];
+ if (++pos == dicBufSize)
+ pos = 0;
+ }
+ while (--curLen != 0);
+ }
+ }
+ }
+ }
+ while (dicPos < limit && buf < bufLimit);
+ NORMALIZE;
+ p->buf = buf;
+ p->range = range;
+ p->code = code;
+ p->remainLen = len;
+ p->dicPos = dicPos;
+ p->processedPos = processedPos;
+ p->reps[0] = rep0;
+ p->reps[1] = rep1;
+ p->reps[2] = rep2;
+ p->reps[3] = rep3;
+ p->state = state;
+
+ return SZ_OK;
+}
+
+static void MY_FAST_CALL LzmaDec_WriteRem(CLzmaDec *p, SizeT limit)
+{
+ if (p->remainLen != 0 && p->remainLen < kMatchSpecLenStart)
+ {
+ Byte *dic = p->dic;
+ SizeT dicPos = p->dicPos;
+ SizeT dicBufSize = p->dicBufSize;
+ unsigned len = p->remainLen;
+ UInt32 rep0 = p->reps[0];
+ if (limit - dicPos < len)
+ len = (unsigned)(limit - dicPos);
+
+ if (p->checkDicSize == 0 && p->prop.dicSize - p->processedPos <= len)
+ p->checkDicSize = p->prop.dicSize;
+
+ p->processedPos += len;
+ p->remainLen -= len;
+ while (len-- != 0)
+ {
+ dic[dicPos] = dic[(dicPos - rep0) + ((dicPos < rep0) ? dicBufSize : 0)];
+ dicPos++;
+ }
+ p->dicPos = dicPos;
+ }
+}
+
+static int MY_FAST_CALL LzmaDec_DecodeReal2(CLzmaDec *p, SizeT limit, const Byte *bufLimit)
+{
+ do
+ {
+ SizeT limit2 = limit;
+ if (p->checkDicSize == 0)
+ {
+ UInt32 rem = p->prop.dicSize - p->processedPos;
+ if (limit - p->dicPos > rem)
+ limit2 = p->dicPos + rem;
+ }
+ RINOK(LzmaDec_DecodeReal(p, limit2, bufLimit));
+ if (p->processedPos >= p->prop.dicSize)
+ p->checkDicSize = p->prop.dicSize;
+ LzmaDec_WriteRem(p, limit);
+ }
+ while (p->dicPos < limit && p->buf < bufLimit && p->remainLen < kMatchSpecLenStart);
+
+ if (p->remainLen > kMatchSpecLenStart)
+ {
+ p->remainLen = kMatchSpecLenStart;
+ }
+ return 0;
+}
+
+typedef enum
+{
+ DUMMY_ERROR, /* unexpected end of input stream */
+ DUMMY_LIT,
+ DUMMY_MATCH,
+ DUMMY_REP
+} ELzmaDummy;
+
+static ELzmaDummy LzmaDec_TryDummy(const CLzmaDec *p, const Byte *buf, SizeT inSize)
+{
+ UInt32 range = p->range;
+ UInt32 code = p->code;
+ const Byte *bufLimit = buf + inSize;
+ CLzmaProb *probs = p->probs;
+ unsigned state = p->state;
+ ELzmaDummy res;
+
+ {
+ CLzmaProb *prob;
+ UInt32 bound;
+ unsigned ttt;
+ unsigned posState = (p->processedPos) & ((1 << p->prop.pb) - 1);
+
+ prob = probs + IsMatch + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK
+
+ /* if (bufLimit - buf >= 7) return DUMMY_LIT; */
+
+ prob = probs + Literal;
+ if (p->checkDicSize != 0 || p->processedPos != 0)
+ prob += (LZMA_LIT_SIZE *
+ ((((p->processedPos) & ((1 << (p->prop.lp)) - 1)) << p->prop.lc) +
+ (p->dic[(p->dicPos == 0 ? p->dicBufSize : p->dicPos) - 1] >> (8 - p->prop.lc))));
+
+ if (state < kNumLitStates)
+ {
+ unsigned symbol = 1;
+ do { GET_BIT_CHECK(prob + symbol, symbol) } while (symbol < 0x100);
+ }
+ else
+ {
+ unsigned matchByte = p->dic[p->dicPos - p->reps[0] +
+ ((p->dicPos < p->reps[0]) ? p->dicBufSize : 0)];
+ unsigned offs = 0x100;
+ unsigned symbol = 1;
+ do
+ {
+ unsigned bit;
+ CLzmaProb *probLit;
+ matchByte <<= 1;
+ bit = (matchByte & offs);
+ probLit = prob + offs + bit + symbol;
+ GET_BIT2_CHECK(probLit, symbol, offs &= ~bit, offs &= bit)
+ }
+ while (symbol < 0x100);
+ }
+ res = DUMMY_LIT;
+ }
+ else
+ {
+ unsigned len;
+ UPDATE_1_CHECK;
+
+ prob = probs + IsRep + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ state = 0;
+ prob = probs + LenCoder;
+ res = DUMMY_MATCH;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ res = DUMMY_REP;
+ prob = probs + IsRepG0 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ prob = probs + IsRep0Long + (state << kNumPosBitsMax) + posState;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ NORMALIZE_CHECK;
+ return DUMMY_REP;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG1 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ prob = probs + IsRepG2 + state;
+ IF_BIT_0_CHECK(prob)
+ {
+ UPDATE_0_CHECK;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ }
+ }
+ }
+ state = kNumStates;
+ prob = probs + RepLenCoder;
+ }
+ {
+ unsigned limit, offset;
+ CLzmaProb *probLen = prob + LenChoice;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenLow + (posState << kLenNumLowBits);
+ offset = 0;
+ limit = 1 << kLenNumLowBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenChoice2;
+ IF_BIT_0_CHECK(probLen)
+ {
+ UPDATE_0_CHECK;
+ probLen = prob + LenMid + (posState << kLenNumMidBits);
+ offset = kLenNumLowSymbols;
+ limit = 1 << kLenNumMidBits;
+ }
+ else
+ {
+ UPDATE_1_CHECK;
+ probLen = prob + LenHigh;
+ offset = kLenNumLowSymbols + kLenNumMidSymbols;
+ limit = 1 << kLenNumHighBits;
+ }
+ }
+ TREE_DECODE_CHECK(probLen, limit, len);
+ len += offset;
+ }
+
+ if (state < 4)
+ {
+ unsigned posSlot;
+ prob = probs + PosSlot +
+ ((len < kNumLenToPosStates ? len : kNumLenToPosStates - 1) <<
+ kNumPosSlotBits);
+ TREE_DECODE_CHECK(prob, 1 << kNumPosSlotBits, posSlot);
+ if (posSlot >= kStartPosModelIndex)
+ {
+ int numDirectBits = ((posSlot >> 1) - 1);
+
+ /* if (bufLimit - buf >= 8) return DUMMY_MATCH; */
+
+ if (posSlot < kEndPosModelIndex)
+ {
+ prob = probs + SpecPos + ((2 | (posSlot & 1)) << numDirectBits) - posSlot - 1;
+ }
+ else
+ {
+ numDirectBits -= kNumAlignBits;
+ do
+ {
+ NORMALIZE_CHECK
+ range >>= 1;
+ code -= range & (((code - range) >> 31) - 1);
+ /* if (code >= range) code -= range; */
+ }
+ while (--numDirectBits != 0);
+ prob = probs + Align;
+ numDirectBits = kNumAlignBits;
+ }
+ {
+ unsigned i = 1;
+ do
+ {
+ GET_BIT_CHECK(prob + i, i);
+ }
+ while (--numDirectBits != 0);
+ }
+ }
+ }
+ }
+ }
+ NORMALIZE_CHECK;
+ return res;
+}
+
+static void LzmaDec_InitRc(CLzmaDec *p, const Byte *data)
+{
+ p->code = ((UInt32)data[1] << 24) | ((UInt32)data[2] << 16) | ((UInt32)data[3] << 8) | ((UInt32)data[4]);
+ p->range = 0xFFFFFFFF;
+ p->needFlush = 0;
+}
+
+void LzmaDec_InitDicAndState(CLzmaDec *p, Bool initDic, Bool initState)
+{
+ p->needFlush = 1;
+ p->remainLen = 0;
+ p->tempBufSize = 0;
+
+ if (initDic)
+ {
+ p->processedPos = 0;
+ p->checkDicSize = 0;
+ p->needInitState = 1;
+ }
+ if (initState)
+ p->needInitState = 1;
+}
+
+void LzmaDec_Init(CLzmaDec *p)
+{
+ p->dicPos = 0;
+ LzmaDec_InitDicAndState(p, True, True);
+}
+
+static void LzmaDec_InitStateReal(CLzmaDec *p)
+{
+ UInt32 numProbs = Literal + ((UInt32)LZMA_LIT_SIZE << (p->prop.lc + p->prop.lp));
+ UInt32 i;
+ CLzmaProb *probs = p->probs;
+ for (i = 0; i < numProbs; i++)
+ probs[i] = kBitModelTotal >> 1;
+ p->reps[0] = p->reps[1] = p->reps[2] = p->reps[3] = 1;
+ p->state = 0;
+ p->needInitState = 0;
+}
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit, const Byte *src, SizeT *srcLen,
+ ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT inSize = *srcLen;
+ (*srcLen) = 0;
+ LzmaDec_WriteRem(p, dicLimit);
+
+ *status = LZMA_STATUS_NOT_SPECIFIED;
+
+ while (p->remainLen != kMatchSpecLenStart)
+ {
+ int checkEndMarkNow;
+
+ if (p->needFlush != 0)
+ {
+ for (; inSize > 0 && p->tempBufSize < RC_INIT_SIZE; (*srcLen)++, inSize--)
+ p->tempBuf[p->tempBufSize++] = *src++;
+ if (p->tempBufSize < RC_INIT_SIZE)
+ {
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (p->tempBuf[0] != 0)
+ return SZ_ERROR_DATA;
+
+ LzmaDec_InitRc(p, p->tempBuf);
+ p->tempBufSize = 0;
+ }
+
+ checkEndMarkNow = 0;
+ if (p->dicPos >= dicLimit)
+ {
+ if (p->remainLen == 0 && p->code == 0)
+ {
+ *status = LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK;
+ return SZ_OK;
+ }
+ if (finishMode == LZMA_FINISH_ANY)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_OK;
+ }
+ if (p->remainLen != 0)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ checkEndMarkNow = 1;
+ }
+
+ if (p->needInitState)
+ LzmaDec_InitStateReal(p);
+
+ if (p->tempBufSize == 0)
+ {
+ SizeT processed;
+ const Byte *bufLimit;
+ if (inSize < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, src, inSize);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ memcpy(p->tempBuf, src, inSize);
+ p->tempBufSize = (unsigned)inSize;
+ (*srcLen) += inSize;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ bufLimit = src;
+ }
+ else
+ bufLimit = src + inSize - LZMA_REQUIRED_INPUT_MAX;
+ p->buf = src;
+ if (LzmaDec_DecodeReal2(p, dicLimit, bufLimit) != 0)
+ return SZ_ERROR_DATA;
+ processed = (SizeT)(p->buf - src);
+ (*srcLen) += processed;
+ src += processed;
+ inSize -= processed;
+ }
+ else
+ {
+ unsigned rem = p->tempBufSize, lookAhead = 0;
+ while (rem < LZMA_REQUIRED_INPUT_MAX && lookAhead < inSize)
+ p->tempBuf[rem++] = src[lookAhead++];
+ p->tempBufSize = rem;
+ if (rem < LZMA_REQUIRED_INPUT_MAX || checkEndMarkNow)
+ {
+ int dummyRes = LzmaDec_TryDummy(p, p->tempBuf, rem);
+ if (dummyRes == DUMMY_ERROR)
+ {
+ (*srcLen) += lookAhead;
+ *status = LZMA_STATUS_NEEDS_MORE_INPUT;
+ return SZ_OK;
+ }
+ if (checkEndMarkNow && dummyRes != DUMMY_MATCH)
+ {
+ *status = LZMA_STATUS_NOT_FINISHED;
+ return SZ_ERROR_DATA;
+ }
+ }
+ p->buf = p->tempBuf;
+ if (LzmaDec_DecodeReal2(p, dicLimit, p->buf) != 0)
+ return SZ_ERROR_DATA;
+ lookAhead -= (rem - (unsigned)(p->buf - p->tempBuf));
+ (*srcLen) += lookAhead;
+ src += lookAhead;
+ inSize -= lookAhead;
+ p->tempBufSize = 0;
+ }
+ }
+ if (p->code == 0)
+ *status = LZMA_STATUS_FINISHED_WITH_MARK;
+ return (p->code == 0) ? SZ_OK : SZ_ERROR_DATA;
+}
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status)
+{
+ SizeT outSize = *destLen;
+ SizeT inSize = *srcLen;
+ *srcLen = *destLen = 0;
+ for (;;)
+ {
+ SizeT inSizeCur = inSize, outSizeCur, dicPos;
+ ELzmaFinishMode curFinishMode;
+ SRes res;
+ if (p->dicPos == p->dicBufSize)
+ p->dicPos = 0;
+ dicPos = p->dicPos;
+ if (outSize > p->dicBufSize - dicPos)
+ {
+ outSizeCur = p->dicBufSize;
+ curFinishMode = LZMA_FINISH_ANY;
+ }
+ else
+ {
+ outSizeCur = dicPos + outSize;
+ curFinishMode = finishMode;
+ }
+
+ res = LzmaDec_DecodeToDic(p, outSizeCur, src, &inSizeCur, curFinishMode, status);
+ src += inSizeCur;
+ inSize -= inSizeCur;
+ *srcLen += inSizeCur;
+ outSizeCur = p->dicPos - dicPos;
+ memcpy(dest, p->dic + dicPos, outSizeCur);
+ dest += outSizeCur;
+ outSize -= outSizeCur;
+ *destLen += outSizeCur;
+ if (res != 0)
+ return res;
+ if (outSizeCur == 0 || outSize == 0)
+ return SZ_OK;
+ }
+}
+
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->probs);
+ p->probs = 0;
+}
+
+static void LzmaDec_FreeDict(CLzmaDec *p, ISzAlloc *alloc)
+{
+ alloc->Free(alloc, p->dic);
+ p->dic = 0;
+}
+
+void LzmaDec_Free(CLzmaDec *p, ISzAlloc *alloc)
+{
+ LzmaDec_FreeProbs(p, alloc);
+ LzmaDec_FreeDict(p, alloc);
+}
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size)
+{
+ UInt32 dicSize;
+ Byte d;
+
+ if (size < LZMA_PROPS_SIZE)
+ return SZ_ERROR_UNSUPPORTED;
+ else
+ dicSize = data[1] | ((UInt32)data[2] << 8) | ((UInt32)data[3] << 16) | ((UInt32)data[4] << 24);
+
+ if (dicSize < LZMA_DIC_MIN)
+ dicSize = LZMA_DIC_MIN;
+ p->dicSize = dicSize;
+
+ d = data[0];
+ if (d >= (9 * 5 * 5))
+ return SZ_ERROR_UNSUPPORTED;
+
+ p->lc = d % 9;
+ d /= 9;
+ p->pb = d / 5;
+ p->lp = d % 5;
+
+ return SZ_OK;
+}
+
+static SRes LzmaDec_AllocateProbs2(CLzmaDec *p, const CLzmaProps *propNew, ISzAlloc *alloc)
+{
+ UInt32 numProbs = LzmaProps_GetNumProbs(propNew);
+ if (p->probs == 0 || numProbs != p->numProbs)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ p->probs = (CLzmaProb *)alloc->Alloc(alloc, numProbs * sizeof(CLzmaProb));
+ p->numProbs = numProbs;
+ if (p->probs == 0)
+ return SZ_ERROR_MEM;
+ }
+ return SZ_OK;
+}
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDec_Allocate(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc)
+{
+ CLzmaProps propNew;
+ SizeT dicBufSize;
+ RINOK(LzmaProps_Decode(&propNew, props, propsSize));
+ RINOK(LzmaDec_AllocateProbs2(p, &propNew, alloc));
+ dicBufSize = propNew.dicSize;
+ if (p->dic == 0 || dicBufSize != p->dicBufSize)
+ {
+ LzmaDec_FreeDict(p, alloc);
+ p->dic = (Byte *)alloc->Alloc(alloc, dicBufSize);
+ if (p->dic == 0)
+ {
+ LzmaDec_FreeProbs(p, alloc);
+ return SZ_ERROR_MEM;
+ }
+ }
+ p->dicBufSize = dicBufSize;
+ p->prop = propNew;
+ return SZ_OK;
+}
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc)
+{
+ CLzmaDec p;
+ SRes res;
+ SizeT inSize = *srcLen;
+ SizeT outSize = *destLen;
+ *srcLen = *destLen = 0;
+ if (inSize < RC_INIT_SIZE)
+ return SZ_ERROR_INPUT_EOF;
+
+ LzmaDec_Construct(&p);
+ res = LzmaDec_AllocateProbs(&p, propData, propSize, alloc);
+ if (res != 0)
+ return res;
+ p.dic = dest;
+ p.dicBufSize = outSize;
+
+ LzmaDec_Init(&p);
+
+ *srcLen = inSize;
+ res = LzmaDec_DecodeToDic(&p, outSize, src, srcLen, finishMode, status);
+
+ if (res == SZ_OK && *status == LZMA_STATUS_NEEDS_MORE_INPUT)
+ res = SZ_ERROR_INPUT_EOF;
+
+ (*destLen) = p.dicPos;
+ LzmaDec_FreeProbs(&p, alloc);
+ return res;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
new file mode 100644
index 0000000000..ad7d7057a4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/LzmaDec.h
@@ -0,0 +1,223 @@
+/* LzmaDec.h -- LZMA Decoder
+2008-10-04 : Igor Pavlov : Public domain */
+
+#ifndef __LZMADEC_H
+#define __LZMADEC_H
+
+#include "Types.h"
+
+/* #define _LZMA_PROB32 */
+/* _LZMA_PROB32 can increase the speed on some CPUs,
+ but memory usage for CLzmaDec::probs will be doubled in that case */
+
+#ifdef _LZMA_PROB32
+#define CLzmaProb UInt32
+#else
+#define CLzmaProb UInt16
+#endif
+
+
+/* ---------- LZMA Properties ---------- */
+
+#define LZMA_PROPS_SIZE 5
+
+typedef struct _CLzmaProps
+{
+ unsigned lc, lp, pb;
+ UInt32 dicSize;
+} CLzmaProps;
+
+/* LzmaProps_Decode - decodes properties
+Returns:
+ SZ_OK
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaProps_Decode(CLzmaProps *p, const Byte *data, unsigned size);
+
+
+/* ---------- LZMA Decoder state ---------- */
+
+/* LZMA_REQUIRED_INPUT_MAX = number of required input bytes for worst case.
+ Num bits = log2((2^11 / 31) ^ 22) + 26 < 134 + 26 = 160; */
+
+#define LZMA_REQUIRED_INPUT_MAX 20
+
+typedef struct
+{
+ CLzmaProps prop;
+ CLzmaProb *probs;
+ Byte *dic;
+ const Byte *buf;
+ UInt32 range, code;
+ SizeT dicPos;
+ SizeT dicBufSize;
+ UInt32 processedPos;
+ UInt32 checkDicSize;
+ unsigned state;
+ UInt32 reps[4];
+ unsigned remainLen;
+ int needFlush;
+ int needInitState;
+ UInt32 numProbs;
+ unsigned tempBufSize;
+ Byte tempBuf[LZMA_REQUIRED_INPUT_MAX];
+} CLzmaDec;
+
+#define LzmaDec_Construct(p) { (p)->dic = 0; (p)->probs = 0; }
+
+void LzmaDec_Init(CLzmaDec *p);
+
+/* There are two types of LZMA streams:
+ 0) Stream with end mark. That end mark adds about 6 bytes to compressed size.
+ 1) Stream without end mark. You must know exact uncompressed size to decompress such stream. */
+
+typedef enum
+{
+ LZMA_FINISH_ANY, /* finish at any point */
+ LZMA_FINISH_END /* block must be finished at the end */
+} ELzmaFinishMode;
+
+/* ELzmaFinishMode has meaning only if the decoding reaches output limit !!!
+
+ You must use LZMA_FINISH_END, when you know that current output buffer
+ covers last bytes of block. In other cases you must use LZMA_FINISH_ANY.
+
+ If LZMA decoder sees end marker before reaching output limit, it returns SZ_OK,
+ and output value of destLen will be less than output buffer size limit.
+ You can check status result also.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+typedef enum
+{
+ LZMA_STATUS_NOT_SPECIFIED, /* use main error code instead */
+ LZMA_STATUS_FINISHED_WITH_MARK, /* stream was finished with end mark. */
+ LZMA_STATUS_NOT_FINISHED, /* stream was not finished */
+ LZMA_STATUS_NEEDS_MORE_INPUT, /* you must provide more input bytes */
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK /* there is probability that stream was finished without end mark */
+} ELzmaStatus;
+
+/* ELzmaStatus is used only as output value for function call */
+
+
+/* ---------- Interfaces ---------- */
+
+/* There are 3 levels of interfaces:
+ 1) Dictionary Interface
+ 2) Buffer Interface
+ 3) One Call Interface
+ You can select any of these interfaces, but don't mix functions from different
+ groups for same object. */
+
+
+/* There are two variants to allocate state for Dictionary Interface:
+ 1) LzmaDec_Allocate / LzmaDec_Free
+ 2) LzmaDec_AllocateProbs / LzmaDec_FreeProbs
+ You can use variant 2, if you set dictionary buffer manually.
+ For Buffer Interface you must always use variant 1.
+
+LzmaDec_Allocate* can return:
+ SZ_OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+*/
+
+SRes LzmaDec_AllocateProbs(CLzmaDec *p, const Byte *props, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_FreeProbs(CLzmaDec *p, ISzAlloc *alloc);
+
+SRes LzmaDec_Allocate(CLzmaDec *state, const Byte *prop, unsigned propsSize, ISzAlloc *alloc);
+void LzmaDec_Free(CLzmaDec *state, ISzAlloc *alloc);
+
+/* ---------- Dictionary Interface ---------- */
+
+/* You can use it, if you want to eliminate the overhead for data copying from
+ dictionary to some other external buffer.
+ You must work with CLzmaDec variables directly in this interface.
+
+ STEPS:
+ LzmaDec_Constr()
+ LzmaDec_Allocate()
+ for (each new stream)
+ {
+ LzmaDec_Init()
+ while (it needs more decompression)
+ {
+ LzmaDec_DecodeToDic()
+ use data from CLzmaDec::dic and update CLzmaDec::dicPos
+ }
+ }
+ LzmaDec_Free()
+*/
+
+/* LzmaDec_DecodeToDic
+
+ The decoding to internal dictionary buffer (CLzmaDec::dic).
+ You must manually update CLzmaDec::dicPos, if it reaches CLzmaDec::dicBufSize !!!
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (dicLimit).
+ LZMA_FINISH_ANY - Decode just dicLimit bytes.
+ LZMA_FINISH_END - Stream must be finished after dicLimit.
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_NEEDS_MORE_INPUT
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+*/
+
+SRes LzmaDec_DecodeToDic(CLzmaDec *p, SizeT dicLimit,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- Buffer Interface ---------- */
+
+/* It's zlib-like interface.
+ See LzmaDec_DecodeToDic description for information about STEPS and return results,
+ but you must use LzmaDec_DecodeToBuf instead of LzmaDec_DecodeToDic and you don't need
+ to work with CLzmaDec variables manually.
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+*/
+
+SRes LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode, ELzmaStatus *status);
+
+
+/* ---------- One Call Interface ---------- */
+
+/* LzmaDecode
+
+finishMode:
+ It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+
+Returns:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+*/
+
+SRes LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h
new file mode 100644
index 0000000000..30b16e3bb0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/C/Types.h
@@ -0,0 +1,231 @@
+/** @file
+ Types.h
+
+ Based on LZMA SDK 4.65:
+ Types.h -- Basic types
+ 2008-11-23 : Igor Pavlov : Public domain
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __7Z_TYPES_H
+#define __7Z_TYPES_H
+
+#ifdef EFIAPI
+
+#include "UefiLzma.h"
+
+#else
+
+#include <stddef.h>
+
+#ifdef _WIN32
+#include <windows.h>
+#endif
+
+#endif
+
+#define SZ_OK 0
+
+#define SZ_ERROR_DATA 1
+#define SZ_ERROR_MEM 2
+#define SZ_ERROR_CRC 3
+#define SZ_ERROR_UNSUPPORTED 4
+#define SZ_ERROR_PARAM 5
+#define SZ_ERROR_INPUT_EOF 6
+#define SZ_ERROR_OUTPUT_EOF 7
+#define SZ_ERROR_READ 8
+#define SZ_ERROR_WRITE 9
+#define SZ_ERROR_PROGRESS 10
+#define SZ_ERROR_FAIL 11
+#define SZ_ERROR_THREAD 12
+
+#define SZ_ERROR_ARCHIVE 16
+#define SZ_ERROR_NO_ARCHIVE 17
+
+typedef int SRes;
+
+#ifdef _WIN32
+typedef DWORD WRes;
+#else
+typedef int WRes;
+#endif
+
+#ifndef RINOK
+#define RINOK(x) { int __result__ = (x); if (__result__ != 0) return __result__; }
+#endif
+
+typedef unsigned char Byte;
+typedef short Int16;
+typedef unsigned short UInt16;
+
+#ifdef _LZMA_UINT32_IS_ULONG
+typedef long Int32;
+typedef unsigned long UInt32;
+#else
+typedef int Int32;
+typedef unsigned int UInt32;
+#endif
+
+#ifdef _SZ_NO_INT_64
+
+/* define _SZ_NO_INT_64, if your compiler doesn't support 64-bit integers.
+ NOTES: Some code will work incorrectly in that case! */
+
+typedef long Int64;
+typedef unsigned long UInt64;
+
+#else
+
+#if defined(_MSC_VER) || defined(__BORLANDC__)
+typedef __int64 Int64;
+typedef unsigned __int64 UInt64;
+#else
+typedef long long int Int64;
+typedef unsigned long long int UInt64;
+#endif
+
+#endif
+
+#ifdef _LZMA_NO_SYSTEM_SIZE_T
+typedef UInt32 SizeT;
+#else
+typedef size_t SizeT;
+#endif
+
+typedef int Bool;
+#define True 1
+#define False 0
+
+
+#ifdef _MSC_VER
+
+#if _MSC_VER >= 1300
+#define MY_NO_INLINE __declspec(noinline)
+#else
+#define MY_NO_INLINE
+#endif
+
+#define MY_CDECL __cdecl
+#define MY_STD_CALL __stdcall
+#define MY_FAST_CALL MY_NO_INLINE __fastcall
+
+#else
+
+#define MY_CDECL
+#define MY_STD_CALL
+#define MY_FAST_CALL
+
+#endif
+
+
+/* The following interfaces use first parameter as pointer to structure */
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) < input(*size)) is allowed */
+} ISeqInStream;
+
+/* it can return SZ_ERROR_INPUT_EOF */
+SRes SeqInStream_Read(ISeqInStream *stream, void *buf, size_t size);
+SRes SeqInStream_Read2(ISeqInStream *stream, void *buf, size_t size, SRes errorType);
+SRes SeqInStream_ReadByte(ISeqInStream *stream, Byte *buf);
+
+typedef struct
+{
+ size_t (*Write)(void *p, const void *buf, size_t size);
+ /* Returns: result - the number of actually written bytes.
+ (result < size) means error */
+} ISeqOutStream;
+
+typedef enum
+{
+ SZ_SEEK_SET = 0,
+ SZ_SEEK_CUR = 1,
+ SZ_SEEK_END = 2
+} ESzSeek;
+
+typedef struct
+{
+ SRes (*Read)(void *p, void *buf, size_t *size); /* same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ISeekInStream;
+
+typedef struct
+{
+ SRes (*Look)(void *p, void **buf, size_t *size);
+ /* if (input(*size) != 0 && output(*size) == 0) means end_of_stream.
+ (output(*size) > input(*size)) is not allowed
+ (output(*size) < input(*size)) is allowed */
+ SRes (*Skip)(void *p, size_t offset);
+ /* offset must be <= output(*size) of Look */
+
+ SRes (*Read)(void *p, void *buf, size_t *size);
+ /* reads directly (without buffer). It's same as ISeqInStream::Read */
+ SRes (*Seek)(void *p, Int64 *pos, ESzSeek origin);
+} ILookInStream;
+
+SRes LookInStream_LookRead(ILookInStream *stream, void *buf, size_t *size);
+SRes LookInStream_SeekTo(ILookInStream *stream, UInt64 offset);
+
+/* reads via ILookInStream::Read */
+SRes LookInStream_Read2(ILookInStream *stream, void *buf, size_t size, SRes errorType);
+SRes LookInStream_Read(ILookInStream *stream, void *buf, size_t size);
+
+#define LookToRead_BUF_SIZE (1 << 14)
+
+typedef struct
+{
+ ILookInStream s;
+ ISeekInStream *realStream;
+ size_t pos;
+ size_t size;
+ Byte buf[LookToRead_BUF_SIZE];
+} CLookToRead;
+
+void LookToRead_CreateVTable(CLookToRead *p, int lookahead);
+void LookToRead_Init(CLookToRead *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToLook;
+
+void SecToLook_CreateVTable(CSecToLook *p);
+
+typedef struct
+{
+ ISeqInStream s;
+ ILookInStream *realStream;
+} CSecToRead;
+
+void SecToRead_CreateVTable(CSecToRead *p);
+
+typedef struct
+{
+ SRes (*Progress)(void *p, UInt64 inSize, UInt64 outSize);
+ /* Returns: result. (result != SZ_OK) means break.
+ Value (UInt64)(Int64)-1 for size means unknown value. */
+} ICompressProgress;
+
+typedef struct
+{
+ void *(*Alloc)(void *p, size_t size);
+ void (*Free)(void *p, void *address); /* address can be 0 */
+} ISzAlloc;
+
+#define IAlloc_Alloc(p, size) (p)->Alloc((p), size)
+#define IAlloc_Free(p, a) (p)->Free((p), a)
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt
new file mode 100644
index 0000000000..9bed5ebbef
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/history.txt
@@ -0,0 +1,236 @@
+HISTORY of the LZMA SDK
+-----------------------
+
+4.65 2009-02-03
+-------------------------
+- Some minor fixes
+
+
+4.63 2008-12-31
+-------------------------
+- Some minor fixes
+
+
+4.61 beta 2008-11-23
+-------------------------
+- The bug in ANSI-C LZMA Decoder was fixed:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+- Some changes in ANSI-C 7z Decoder interfaces.
+- LZMA SDK is placed in the public domain.
+
+
+4.60 beta 2008-08-19
+-------------------------
+- Some minor fixes.
+
+
+4.59 beta 2008-08-13
+-------------------------
+- The bug was fixed:
+ LZMA Encoder in fast compression mode could access memory outside of
+ allocated range in some rare cases.
+
+
+4.58 beta 2008-05-05
+-------------------------
+- ANSI-C LZMA Decoder was rewritten for speed optimizations.
+- ANSI-C LZMA Encoder was included to LZMA SDK.
+- C++ LZMA code now is just wrapper over ANSI-C code.
+
+
+4.57 2007-12-12
+-------------------------
+- Speed optimizations in Ñ++ LZMA Decoder.
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.49 beta 2007-07-05
+-------------------------
+- .7z ANSI-C Decoder:
+ - now it supports BCJ and BCJ2 filters
+ - now it supports files larger than 4 GB.
+ - now it supports "Last Write Time" field for files.
+- C++ code for .7z archives compressing/decompressing from 7-zip
+ was included to LZMA SDK.
+
+
+4.43 2006-06-04
+-------------------------
+- Small changes for more compatibility with some C/C++ compilers.
+
+
+4.42 2006-05-15
+-------------------------
+- Small changes in .h files in ANSI-C version.
+
+
+4.39 beta 2006-04-14
+-------------------------
+- The bug in versions 4.33b:4.38b was fixed:
+ C++ version of LZMA encoder could not correctly compress
+ files larger than 2 GB with HC4 match finder (-mfhc4).
+
+
+4.37 beta 2005-04-06
+-------------------------
+- Fixes in C++ code: code could no be compiled if _NO_EXCEPTIONS was defined.
+
+
+4.35 beta 2005-03-02
+-------------------------
+- The bug was fixed in C++ version of LZMA Decoder:
+ If encoded stream was corrupted, decoder could access memory
+ outside of allocated range.
+
+
+4.34 beta 2006-02-27
+-------------------------
+- Compressing speed and memory requirements for compressing were increased
+- LZMA now can use only these match finders: HC4, BT2, BT3, BT4
+
+
+4.32 2005-12-09
+-------------------------
+- Java version of LZMA SDK was included
+
+
+4.30 2005-11-20
+-------------------------
+- Compression ratio was improved in -a2 mode
+- Speed optimizations for compressing in -a2 mode
+- -fb switch now supports values up to 273
+- The bug in 7z_C (7zIn.c) was fixed:
+ It used Alloc/Free functions from different memory pools.
+ So if program used two memory pools, it worked incorrectly.
+- 7z_C: .7z format supporting was improved
+- LZMA# SDK (C#.NET version) was included
+
+
+4.27 (Updated) 2005-09-21
+-------------------------
+- Some GUIDs/interfaces in C++ were changed.
+ IStream.h:
+ ISequentialInStream::Read now works as old ReadPart
+ ISequentialOutStream::Write now works as old WritePart
+
+
+4.27 2005-08-07
+-------------------------
+- The bug in LzmaDecodeSize.c was fixed:
+ if _LZMA_IN_CB and _LZMA_OUT_READ were defined,
+ decompressing worked incorrectly.
+
+
+4.26 2005-08-05
+-------------------------
+- Fixes in 7z_C code and LzmaTest.c:
+ previous versions could work incorrectly,
+ if malloc(0) returns 0
+
+
+4.23 2005-06-29
+-------------------------
+- Small fixes in C++ code
+
+
+4.22 2005-06-10
+-------------------------
+- Small fixes
+
+
+4.21 2005-06-08
+-------------------------
+- Interfaces for ANSI-C LZMA Decoder (LzmaDecode.c) were changed
+- New additional version of ANSI-C LZMA Decoder with zlib-like interface:
+ - LzmaStateDecode.h
+ - LzmaStateDecode.c
+ - LzmaStateTest.c
+- ANSI-C LZMA Decoder now can decompress files larger than 4 GB
+
+
+4.17 2005-04-18
+-------------------------
+- New example for RAM->RAM compressing/decompressing:
+ LZMA + BCJ (filter for x86 code):
+ - LzmaRam.h
+ - LzmaRam.cpp
+ - LzmaRamDecode.h
+ - LzmaRamDecode.c
+ - -f86 switch for lzma.exe
+
+
+4.16 2005-03-29
+-------------------------
+- The bug was fixed in LzmaDecode.c (ANSI-C LZMA Decoder):
+ If _LZMA_OUT_READ was defined, and if encoded stream was corrupted,
+ decoder could access memory outside of allocated range.
+- Speed optimization of ANSI-C LZMA Decoder (now it's about 20% faster).
+ Old version of LZMA Decoder now is in file LzmaDecodeSize.c.
+ LzmaDecodeSize.c can provide slightly smaller code than LzmaDecode.c
+- Small speed optimization in LZMA C++ code
+- filter for SPARC's code was added
+- Simplified version of .7z ANSI-C Decoder was included
+
+
+4.06 2004-09-05
+-------------------------
+- The bug in v4.05 was fixed:
+ LZMA-Encoder didn't release output stream in some cases.
+
+
+4.05 2004-08-25
+-------------------------
+- Source code of filters for x86, IA-64, ARM, ARM-Thumb
+ and PowerPC code was included to SDK
+- Some internal minor changes
+
+
+4.04 2004-07-28
+-------------------------
+- More compatibility with some C++ compilers
+
+
+4.03 2004-06-18
+-------------------------
+- "Benchmark" command was added. It measures compressing
+ and decompressing speed and shows rating values.
+ Also it checks hardware errors.
+
+
+4.02 2004-06-10
+-------------------------
+- C++ LZMA Encoder/Decoder code now is more portable
+ and it can be compiled by GCC on Linux.
+
+
+4.01 2004-02-15
+-------------------------
+- Some detection of data corruption was enabled.
+ LzmaDecode.c / RangeDecoderReadByte
+ .....
+ {
+ rd->ExtraBytes = 1;
+ return 0xFF;
+ }
+
+
+4.00 2004-02-13
+-------------------------
+- Original version of LZMA SDK
+
+
+
+HISTORY of the LZMA
+-------------------
+ 2001-2008: Improvements to LZMA compressing/decompressing code,
+ keeping compatibility with original LZMA format
+ 1996-2001: Development of LZMA compression format
+
+ Some milestones:
+
+ 2001-08-30: LZMA compression was added to 7-Zip
+ 1999-01-02: First version of 7-Zip was released
+
+
+End of document
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt
new file mode 100644
index 0000000000..d4f4af929a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/Sdk/lzma.txt
@@ -0,0 +1,594 @@
+LZMA SDK 4.65
+-------------
+
+LZMA SDK provides the documentation, samples, header files, libraries,
+and tools you need to develop applications that use LZMA compression.
+
+LZMA is default and general compression method of 7z format
+in 7-Zip compression program (www.7-zip.org). LZMA provides high
+compression ratio and very fast decompression.
+
+LZMA is an improved version of famous LZ77 compression algorithm.
+It was improved in way of maximum increasing of compression ratio,
+keeping high decompression speed and low memory requirements for
+decompressing.
+
+
+
+LICENSE
+-------
+
+LZMA SDK is written and placed in the public domain by Igor Pavlov.
+
+
+LZMA SDK Contents
+-----------------
+
+LZMA SDK includes:
+
+ - ANSI-C/C++/C#/Java source code for LZMA compressing and decompressing
+ - Compiled file->file LZMA compressing/decompressing program for Windows system
+
+
+UNIX/Linux version
+------------------
+To compile C++ version of file->file LZMA encoding, go to directory
+C++/7zip/Compress/LZMA_Alone
+and call make to recompile it:
+ make -f makefile.gcc clean all
+
+In some UNIX/Linux versions you must compile LZMA with static libraries.
+To compile with static libraries, you can use
+LIB = -lm -static
+
+
+Files
+---------------------
+lzma.txt - LZMA SDK description (this file)
+7zFormat.txt - 7z Format description
+7zC.txt - 7z ANSI-C Decoder description
+methods.txt - Compression method IDs for .7z
+lzma.exe - Compiled file->file LZMA encoder/decoder for Windows
+history.txt - history of the LZMA SDK
+
+
+Source code structure
+---------------------
+
+C/ - C files
+ 7zCrc*.* - CRC code
+ Alloc.* - Memory allocation functions
+ Bra*.* - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+ LzFind.* - Match finder for LZ (LZMA) encoders
+ LzFindMt.* - Match finder for LZ (LZMA) encoders for multithreading encoding
+ LzHash.h - Additional file for LZ match finder
+ LzmaDec.* - LZMA decoding
+ LzmaEnc.* - LZMA encoding
+ LzmaLib.* - LZMA Library for DLL calling
+ Types.h - Basic types for another .c files
+ Threads.* - The code for multithreading.
+
+ LzmaLib - LZMA Library (.DLL for Windows)
+
+ LzmaUtil - LZMA Utility (file->file LZMA encoder/decoder).
+
+ Archive - files related to archiving
+ 7z - 7z ANSI-C Decoder
+
+CPP/ -- CPP files
+
+ Common - common files for C++ projects
+ Windows - common files for Windows related code
+
+ 7zip - files related to 7-Zip Project
+
+ Common - common files for 7-Zip
+
+ Compress - files related to compression/decompression
+
+ Copy - Copy coder
+ RangeCoder - Range Coder (special code of compression/decompression)
+ LZMA - LZMA compression/decompression on C++
+ LZMA_Alone - file->file LZMA compression/decompression
+ Branch - Filters for x86, IA-64, ARM, ARM-Thumb, PowerPC and SPARC code
+
+ Archive - files related to archiving
+
+ Common - common files for archive handling
+ 7z - 7z C++ Encoder/Decoder
+
+ Bundles - Modules that are bundles of other modules
+
+ Alone7z - 7zr.exe: Standalone version of 7z.exe that supports only 7z/LZMA/BCJ/BCJ2
+ Format7zR - 7zr.dll: Reduced version of 7za.dll: extracting/compressing to 7z/LZMA/BCJ/BCJ2
+ Format7zExtractR - 7zxr.dll: Reduced version of 7zxa.dll: extracting from 7z/LZMA/BCJ/BCJ2.
+
+ UI - User Interface files
+
+ Client7z - Test application for 7za.dll, 7zr.dll, 7zxr.dll
+ Common - Common UI files
+ Console - Code for console archiver
+
+
+
+CS/ - C# files
+ 7zip
+ Common - some common files for 7-Zip
+ Compress - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ LzmaAlone - file->file LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+Java/ - Java files
+ SevenZip
+ Compression - files related to compression/decompression
+ LZ - files related to LZ (Lempel-Ziv) compression algorithm
+ LZMA - LZMA compression/decompression
+ RangeCoder - Range Coder (special code of compression/decompression)
+
+
+C/C++ source code of LZMA SDK is part of 7-Zip project.
+7-Zip source code can be downloaded from 7-Zip's SourceForge page:
+
+ http://sourceforge.net/projects/sevenzip/
+
+
+
+LZMA features
+-------------
+ - Variable dictionary size (up to 1 GB)
+ - Estimated compressing speed: about 2 MB/s on 2 GHz CPU
+ - Estimated decompressing speed:
+ - 20-30 MB/s on 2 GHz Core 2 or AMD Athlon 64
+ - 1-2 MB/s on 200 MHz ARM, MIPS, PowerPC or other simple RISC
+ - Small memory requirements for decompressing (16 KB + DictionarySize)
+ - Small code size for decompressing: 5-8 KB
+
+LZMA decoder uses only integer operations and can be
+implemented in any modern 32-bit CPU (or on 16-bit CPU with some conditions).
+
+Some critical operations that affect the speed of LZMA decompression:
+ 1) 32*16 bit integer multiply
+ 2) Misspredicted branches (penalty mostly depends from pipeline length)
+ 3) 32-bit shift and arithmetic operations
+
+The speed of LZMA decompressing mostly depends from CPU speed.
+Memory speed has no big meaning. But if your CPU has small data cache,
+overall weight of memory speed will slightly increase.
+
+
+How To Use
+----------
+
+Using LZMA encoder/decoder executable
+--------------------------------------
+
+Usage: LZMA <e|d> inputFile outputFile [<switches>...]
+
+ e: encode file
+
+ d: decode file
+
+ b: Benchmark. There are two tests: compressing and decompressing
+ with LZMA method. Benchmark shows rating in MIPS (million
+ instructions per second). Rating value is calculated from
+ measured speed and it is normalized with Intel's Core 2 results.
+ Also Benchmark checks possible hardware errors (RAM
+ errors in most cases). Benchmark uses these settings:
+ (-a1, -d21, -fb32, -mfbt4). You can change only -d parameter.
+ Also you can change the number of iterations. Example for 30 iterations:
+ LZMA b 30
+ Default number of iterations is 10.
+
+<Switches>
+
+
+ -a{N}: set compression mode 0 = fast, 1 = normal
+ default: 1 (normal)
+
+ d{N}: Sets Dictionary size - [0, 30], default: 23 (8MB)
+ The maximum value for dictionary size is 1 GB = 2^30 bytes.
+ Dictionary size is calculated as DictionarySize = 2^N bytes.
+ For decompressing file compressed by LZMA method with dictionary
+ size D = 2^N you need about D bytes of memory (RAM).
+
+ -fb{N}: set number of fast bytes - [5, 273], default: 128
+ Usually big number gives a little bit better compression ratio
+ and slower compression process.
+
+ -lc{N}: set number of literal context bits - [0, 8], default: 3
+ Sometimes lc=4 gives gain for big files.
+
+ -lp{N}: set number of literal pos bits - [0, 4], default: 0
+ lp switch is intended for periodical data when period is
+ equal 2^N. For example, for 32-bit (4 bytes)
+ periodical data you can use lp=2. Often it's better to set lc0,
+ if you change lp switch.
+
+ -pb{N}: set number of pos bits - [0, 4], default: 2
+ pb switch is intended for periodical data
+ when period is equal 2^N.
+
+ -mf{MF_ID}: set Match Finder. Default: bt4.
+ Algorithms from hc* group doesn't provide good compression
+ ratio, but they often works pretty fast in combination with
+ fast mode (-a0).
+
+ Memory requirements depend from dictionary size
+ (parameter "d" in table below).
+
+ MF_ID Memory Description
+
+ bt2 d * 9.5 + 4MB Binary Tree with 2 bytes hashing.
+ bt3 d * 11.5 + 4MB Binary Tree with 3 bytes hashing.
+ bt4 d * 11.5 + 4MB Binary Tree with 4 bytes hashing.
+ hc4 d * 7.5 + 4MB Hash Chain with 4 bytes hashing.
+
+ -eos: write End Of Stream marker. By default LZMA doesn't write
+ eos marker, since LZMA decoder knows uncompressed size
+ stored in .lzma file header.
+
+ -si: Read data from stdin (it will write End Of Stream marker).
+ -so: Write data to stdout
+
+
+Examples:
+
+1) LZMA e file.bin file.lzma -d16 -lc0
+
+compresses file.bin to file.lzma with 64 KB dictionary (2^16=64K)
+and 0 literal context bits. -lc0 allows to reduce memory requirements
+for decompression.
+
+
+2) LZMA e file.bin file.lzma -lc0 -lp2
+
+compresses file.bin to file.lzma with settings suitable
+for 32-bit periodical data (for example, ARM or MIPS code).
+
+3) LZMA d file.lzma file.bin
+
+decompresses file.lzma to file.bin.
+
+
+Compression ratio hints
+-----------------------
+
+Recommendations
+---------------
+
+To increase the compression ratio for LZMA compressing it's desirable
+to have aligned data (if it's possible) and also it's desirable to locate
+data in such order, where code is grouped in one place and data is
+grouped in other place (it's better than such mixing: code, data, code,
+data, ...).
+
+
+Filters
+-------
+You can increase the compression ratio for some data types, using
+special filters before compressing. For example, it's possible to
+increase the compression ratio on 5-10% for code for those CPU ISAs:
+x86, IA-64, ARM, ARM-Thumb, PowerPC, SPARC.
+
+You can find C source code of such filters in C/Bra*.* files
+
+You can check the compression ratio gain of these filters with such
+7-Zip commands (example for ARM code):
+No filter:
+ 7z a a1.7z a.bin -m0=lzma
+
+With filter for little-endian ARM code:
+ 7z a a2.7z a.bin -m0=arm -m1=lzma
+
+It works in such manner:
+Compressing = Filter_encoding + LZMA_encoding
+Decompressing = LZMA_decoding + Filter_decoding
+
+Compressing and decompressing speed of such filters is very high,
+so it will not increase decompressing time too much.
+Moreover, it reduces decompression time for LZMA_decoding,
+since compression ratio with filtering is higher.
+
+These filters convert CALL (calling procedure) instructions
+from relative offsets to absolute addresses, so such data becomes more
+compressible.
+
+For some ISAs (for example, for MIPS) it's impossible to get gain from such filter.
+
+
+LZMA compressed file format
+---------------------------
+Offset Size Description
+ 0 1 Special LZMA properties (lc,lp, pb in encoded form)
+ 1 4 Dictionary size (little endian)
+ 5 8 Uncompressed size (little endian). -1 means unknown size
+ 13 Compressed data
+
+
+ANSI-C LZMA Decoder
+~~~~~~~~~~~~~~~~~~~
+
+Please note that interfaces for ANSI-C code were changed in LZMA SDK 4.58.
+If you want to use old interfaces you can download previous version of LZMA SDK
+from sourceforge.net site.
+
+To use ANSI-C LZMA Decoder you need the following files:
+1) LzmaDec.h + LzmaDec.c + Types.h
+LzmaUtil/LzmaUtil.c is example application that uses these files.
+
+
+Memory requirements for LZMA decoding
+-------------------------------------
+
+Stack usage of LZMA decoding function for local variables is not
+larger than 200-400 bytes.
+
+LZMA Decoder uses dictionary buffer and internal state structure.
+Internal state structure consumes
+ state_size = (4 + (1.5 << (lc + lp))) KB
+by default (lc=3, lp=0), state_size = 16 KB.
+
+
+How To decompress data
+----------------------
+
+LZMA Decoder (ANSI-C version) now supports 2 interfaces:
+1) Single-call Decompressing
+2) Multi-call State Decompressing (zlib-like interface)
+
+You must use external allocator:
+Example:
+void *SzAlloc(void *p, size_t size) { p = p; return malloc(size); }
+void SzFree(void *p, void *address) { p = p; free(address); }
+ISzAlloc alloc = { SzAlloc, SzFree };
+
+You can use p = p; operator to disable compiler warnings.
+
+
+Single-call Decompressing
+-------------------------
+When to use: RAM->RAM decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+Compile defines: no defines
+Memory Requirements:
+ - Input buffer: compressed size
+ - Output buffer: uncompressed size
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+
+Interface:
+ int LzmaDecode(Byte *dest, SizeT *destLen, const Byte *src, SizeT *srcLen,
+ const Byte *propData, unsigned propSize, ELzmaFinishMode finishMode,
+ ELzmaStatus *status, ISzAlloc *alloc);
+ In:
+ dest - output data
+ destLen - output data size
+ src - input data
+ srcLen - input data size
+ propData - LZMA properties (5 bytes)
+ propSize - size of propData buffer (5 bytes)
+ finishMode - It has meaning only if the decoding reaches output limit (*destLen).
+ LZMA_FINISH_ANY - Decode just destLen bytes.
+ LZMA_FINISH_END - Stream must be finished after (*destLen).
+ You can use LZMA_FINISH_END, when you know that
+ current output buffer covers last bytes of stream.
+ alloc - Memory allocator.
+
+ Out:
+ destLen - processed output size
+ srcLen - processed input size
+
+ Output:
+ SZ_OK
+ status:
+ LZMA_STATUS_FINISHED_WITH_MARK
+ LZMA_STATUS_NOT_FINISHED
+ LZMA_STATUS_MAYBE_FINISHED_WITHOUT_MARK
+ SZ_ERROR_DATA - Data error
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_UNSUPPORTED - Unsupported properties
+ SZ_ERROR_INPUT_EOF - It needs more bytes in input buffer (src).
+
+ If LZMA decoder sees end_marker before reaching output limit, it returns OK result,
+ and output value of destLen will be less than output buffer size limit.
+
+ You can use multiple checks to test data integrity after full decompression:
+ 1) Check Result and "status" variable.
+ 2) Check that output(destLen) = uncompressedSize, if you know real uncompressedSize.
+ 3) Check that output(srcLen) = compressedSize, if you know real compressedSize.
+ You must use correct finish mode in that case. */
+
+
+Multi-call State Decompressing (zlib-like interface)
+----------------------------------------------------
+
+When to use: file->file decompressing
+Compile files: LzmaDec.h + LzmaDec.c + Types.h
+
+Memory Requirements:
+ - Buffer for input stream: any size (for example, 16 KB)
+ - Buffer for output stream: any size (for example, 16 KB)
+ - LZMA Internal Structures: state_size (16 KB for default settings)
+ - LZMA dictionary (dictionary size is encoded in LZMA properties header)
+
+1) read LZMA properties (5 bytes) and uncompressed size (8 bytes, little-endian) to header:
+ unsigned char header[LZMA_PROPS_SIZE + 8];
+ ReadFile(inFile, header, sizeof(header)
+
+2) Allocate CLzmaDec structures (state + dictionary) using LZMA properties
+
+ CLzmaDec state;
+ LzmaDec_Constr(&state);
+ res = LzmaDec_Allocate(&state, header, LZMA_PROPS_SIZE, &g_Alloc);
+ if (res != SZ_OK)
+ return res;
+
+3) Init LzmaDec structure before any new LZMA stream. And call LzmaDec_DecodeToBuf in loop
+
+ LzmaDec_Init(&state);
+ for (;;)
+ {
+ ...
+ int res = LzmaDec_DecodeToBuf(CLzmaDec *p, Byte *dest, SizeT *destLen,
+ const Byte *src, SizeT *srcLen, ELzmaFinishMode finishMode);
+ ...
+ }
+
+
+4) Free all allocated structures
+ LzmaDec_Free(&state, &g_Alloc);
+
+For full code example, look at C/LzmaUtil/LzmaUtil.c code.
+
+
+How To compress data
+--------------------
+
+Compile files: LzmaEnc.h + LzmaEnc.c + Types.h +
+LzFind.c + LzFind.h + LzFindMt.c + LzFindMt.h + LzHash.h
+
+Memory Requirements:
+ - (dictSize * 11.5 + 6 MB) + state_size
+
+Lzma Encoder can use two memory allocators:
+1) alloc - for small arrays.
+2) allocBig - for big arrays.
+
+For example, you can use Large RAM Pages (2 MB) in allocBig allocator for
+better compression speed. Note that Windows has bad implementation for
+Large RAM Pages.
+It's OK to use same allocator for alloc and allocBig.
+
+
+Single-call Compression with callbacks
+--------------------------------------
+
+Check C/LzmaUtil/LzmaUtil.c as example,
+
+When to use: file->file decompressing
+
+1) you must implement callback structures for interfaces:
+ISeqInStream
+ISeqOutStream
+ICompressProgress
+ISzAlloc
+
+static void *SzAlloc(void *p, size_t size) { p = p; return MyAlloc(size); }
+static void SzFree(void *p, void *address) { p = p; MyFree(address); }
+static ISzAlloc g_Alloc = { SzAlloc, SzFree };
+
+ CFileSeqInStream inStream;
+ CFileSeqOutStream outStream;
+
+ inStream.funcTable.Read = MyRead;
+ inStream.file = inFile;
+ outStream.funcTable.Write = MyWrite;
+ outStream.file = outFile;
+
+
+2) Create CLzmaEncHandle object;
+
+ CLzmaEncHandle enc;
+
+ enc = LzmaEnc_Create(&g_Alloc);
+ if (enc == 0)
+ return SZ_ERROR_MEM;
+
+
+3) initialize CLzmaEncProps properties;
+
+ LzmaEncProps_Init(&props);
+
+ Then you can change some properties in that structure.
+
+4) Send LZMA properties to LZMA Encoder
+
+ res = LzmaEnc_SetProps(enc, &props);
+
+5) Write encoded properties to header
+
+ Byte header[LZMA_PROPS_SIZE + 8];
+ size_t headerSize = LZMA_PROPS_SIZE;
+ UInt64 fileSize;
+ int i;
+
+ res = LzmaEnc_WriteProperties(enc, header, &headerSize);
+ fileSize = MyGetFileLength(inFile);
+ for (i = 0; i < 8; i++)
+ header[headerSize++] = (Byte)(fileSize >> (8 * i));
+ MyWriteFileAndCheck(outFile, header, headerSize)
+
+6) Call encoding function:
+ res = LzmaEnc_Encode(enc, &outStream.funcTable, &inStream.funcTable,
+ NULL, &g_Alloc, &g_Alloc);
+
+7) Destroy LZMA Encoder Object
+ LzmaEnc_Destroy(enc, &g_Alloc, &g_Alloc);
+
+
+If callback function return some error code, LzmaEnc_Encode also returns that code.
+
+
+Single-call RAM->RAM Compression
+--------------------------------
+
+Single-call RAM->RAM Compression is similar to Compression with callbacks,
+but you provide pointers to buffers instead of pointers to stream callbacks:
+
+HRes LzmaEncode(Byte *dest, SizeT *destLen, const Byte *src, SizeT srcLen,
+ CLzmaEncProps *props, Byte *propsEncoded, SizeT *propsSize, int writeEndMark,
+ ICompressProgress *progress, ISzAlloc *alloc, ISzAlloc *allocBig);
+
+Return code:
+ SZ_OK - OK
+ SZ_ERROR_MEM - Memory allocation error
+ SZ_ERROR_PARAM - Incorrect paramater
+ SZ_ERROR_OUTPUT_EOF - output buffer overflow
+ SZ_ERROR_THREAD - errors in multithreading functions (only for Mt version)
+
+
+
+LZMA Defines
+------------
+
+_LZMA_SIZE_OPT - Enable some optimizations in LZMA Decoder to get smaller executable code.
+
+_LZMA_PROB32 - It can increase the speed on some 32-bit CPUs, but memory usage for
+ some structures will be doubled in that case.
+
+_LZMA_UINT32_IS_ULONG - Define it if int is 16-bit on your compiler and long is 32-bit.
+
+_LZMA_NO_SYSTEM_SIZE_T - Define it if you don't want to use size_t type.
+
+
+C++ LZMA Encoder/Decoder
+~~~~~~~~~~~~~~~~~~~~~~~~
+C++ LZMA code use COM-like interfaces. So if you want to use it,
+you can study basics of COM/OLE.
+C++ LZMA code is just wrapper over ANSI-C code.
+
+
+C++ Notes
+~~~~~~~~~~~~~~~~~~~~~~~~
+If you use some C++ code folders in 7-Zip (for example, C++ code for .7z handling),
+you must check that you correctly work with "new" operator.
+7-Zip can be compiled with MSVC 6.0 that doesn't throw "exception" from "new" operator.
+So 7-Zip uses "CPP\Common\NewHandler.cpp" that redefines "new" operator:
+operator new(size_t size)
+{
+ void *p = ::malloc(size);
+ if (p == 0)
+ throw CNewException();
+ return p;
+}
+If you use MSCV that throws exception for "new" operator, you can compile without
+"NewHandler.cpp". So standard exception will be used. Actually some code of
+7-Zip catches any exception in internal code and converts it to HRESULT code.
+So you don't need to catch CNewException, if you call COM interfaces of 7-Zip.
+
+---
+
+http://www.7-zip.org
+http://www.7-zip.org/sdk.html
+http://www.7-zip.org/support.html
diff --git a/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
new file mode 100644
index 0000000000..863b3ef66b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/LzmaCustomDecompressLib/UefiLzma.h
@@ -0,0 +1,47 @@
+/** @file
+ LZMA UEFI header file
+
+ Allows LZMA code to build under UEFI (edk2) build environment
+
+ Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __UEFILZMA_H__
+#define __UEFILZMA_H__
+
+#include <Uefi.h>
+#include <Library/BaseMemoryLib.h>
+
+#ifdef _WIN32
+#undef _WIN32
+#endif
+
+#ifndef _SIZE_T_DEFINED
+#if !defined(_WIN64) || defined(__GNUC__)
+typedef unsigned int size_t;
+#endif
+#endif
+
+#ifdef _WIN64
+#undef _WIN64
+#endif
+
+#ifndef _PTRDIFF_T_DEFINED
+typedef int ptrdiff_t;
+#endif
+
+#define memcpy CopyMem
+#define memmove CopyMem
+
+#define _LZMA_SIZE_OPT
+
+#endif // __UEFILZMA_H__
+
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
new file mode 100644
index 0000000000..cfdd2f50d5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/DebugLib.c
@@ -0,0 +1,468 @@
+/** @file
+ Debug Library based on report status code library.
+
+ Note that if the debug message length is larger than the maximum allowable
+ record length, then the debug message will be ignored directly.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugPrintErrorLevelLib.h>
+
+/**
+ Prints a debug message to the debug output device if the specified error level is enabled.
+
+ If any bit in ErrorLevel is also set in DebugPrintErrorLevelLib function
+ GetDebugPrintErrorLevel (), then print the message specified by Format and the
+ associated variable argument list to the debug output device.
+
+ If Format is NULL, then ASSERT().
+
+ If the length of the message string specificed by Format is larger than the maximum allowable
+ record length, then directly return and not print it.
+
+ @param ErrorLevel The error level of the debug message.
+ @param Format Format string for the debug message to print.
+ @param ... Variable argument list whose contents are accessed
+ based on the format string specified by Format.
+
+**/
+VOID
+EFIAPI
+DebugPrint (
+ IN UINTN ErrorLevel,
+ IN CONST CHAR8 *Format,
+ ...
+ )
+{
+ UINT64 Buffer[(EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof (UINT64)) + 1];
+ EFI_DEBUG_INFO *DebugInfo;
+ UINTN TotalSize;
+ UINTN DestBufferSize;
+ VA_LIST VaListMarker;
+ BASE_LIST BaseListMarker;
+ CHAR8 *FormatString;
+ BOOLEAN Long;
+
+ //
+ // If Format is NULL, then ASSERT().
+ //
+ ASSERT (Format != NULL);
+
+ //
+ // Check driver Debug Level value and global debug level
+ //
+ if ((ErrorLevel & GetDebugPrintErrorLevel ()) == 0) {
+ return;
+ }
+
+ //
+ // Compute the total size of the record.
+ // Note that the passing-in format string and variable parameters will be constructed to
+ // the following layout:
+ //
+ // Buffer->|------------------------|
+ // | Padding | 4 bytes
+ // DebugInfo->|------------------------|
+ // | EFI_DEBUG_INFO | sizeof(EFI_DEBUG_INFO)
+ // BaseListMarker->|------------------------|
+ // | ... |
+ // | variable arguments | 12 * sizeof (UINT64)
+ // | ... |
+ // |------------------------|
+ // | Format String |
+ // |------------------------|<- (UINT8 *)Buffer + sizeof(Buffer)
+ //
+ TotalSize = 4 + sizeof (EFI_DEBUG_INFO) + 12 * sizeof (UINT64) + AsciiStrSize (Format);
+
+ //
+ // If the TotalSize is larger than the maximum record size, then return
+ //
+ if (TotalSize > sizeof (Buffer)) {
+ return;
+ }
+
+ //
+ // Fill in EFI_DEBUG_INFO
+ //
+ // Here we skip the first 4 bytes of Buffer, because we must ensure BaseListMarker is
+ // 64-bit aligned, otherwise retrieving 64-bit parameter from BaseListMarker will cause
+ // exception on IPF. Buffer starts at 64-bit aligned address, so skipping 4 types (sizeof(EFI_DEBUG_INFO))
+ // just makes address of BaseListMarker, which follows DebugInfo, 64-bit aligned.
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Buffer) + 1;
+ DebugInfo->ErrorLevel = (UINT32)ErrorLevel;
+ BaseListMarker = (BASE_LIST)(DebugInfo + 1);
+ FormatString = (CHAR8 *)((UINT64 *)(DebugInfo + 1) + 12);
+
+ //
+ // Copy the Format string into the record
+ //
+ // According to the content structure of Buffer shown above, the size of
+ // the FormatString buffer is the size of Buffer minus the Padding
+ // (4 bytes), minus the size of EFI_DEBUG_INFO, minus the size of
+ // variable arguments (12 * sizeof (UINT64)).
+ //
+ DestBufferSize = sizeof (Buffer) - 4 - sizeof (EFI_DEBUG_INFO) - 12 * sizeof (UINT64);
+ AsciiStrCpyS (FormatString, DestBufferSize / sizeof (CHAR8), Format);
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string, which is followed by the DEBUG format string.
+ // Here we will process the variable arguments and pack them in this area.
+ //
+ VA_START (VaListMarker, Format);
+ for (; *Format != '\0'; Format++) {
+ //
+ // Only format with prefix % is processed.
+ //
+ if (*Format != '%') {
+ continue;
+ }
+ Long = FALSE;
+ //
+ // Parse Flags and Width
+ //
+ for (Format++; TRUE; Format++) {
+ if (*Format == '.' || *Format == '-' || *Format == '+' || *Format == ' ') {
+ //
+ // These characters in format field are omitted.
+ //
+ continue;
+ }
+ if (*Format >= '0' && *Format <= '9') {
+ //
+ // These characters in format field are omitted.
+ //
+ continue;
+ }
+ if (*Format == 'L' || *Format == 'l') {
+ //
+ // 'L" or "l" in format field means the number being printed is a UINT64
+ //
+ Long = TRUE;
+ continue;
+ }
+ if (*Format == '*') {
+ //
+ // '*' in format field means the precision of the field is specified by
+ // a UINTN argument in the argument list.
+ //
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ continue;
+ }
+ if (*Format == '\0') {
+ //
+ // Make no output if Format string terminates unexpectedly when
+ // looking up for flag, width, precision and type.
+ //
+ Format--;
+ }
+ //
+ // When valid argument type detected or format string terminates unexpectedly,
+ // the inner loop is done.
+ //
+ break;
+ }
+
+ //
+ // Pack variable arguments into the storage area following EFI_DEBUG_INFO.
+ //
+ if ((*Format == 'p') && (sizeof (VOID *) > 4)) {
+ Long = TRUE;
+ }
+ if (*Format == 'p' || *Format == 'X' || *Format == 'x' || *Format == 'd' || *Format == 'u') {
+ if (Long) {
+ BASE_ARG (BaseListMarker, INT64) = VA_ARG (VaListMarker, INT64);
+ } else {
+ BASE_ARG (BaseListMarker, int) = VA_ARG (VaListMarker, int);
+ }
+ } else if (*Format == 's' || *Format == 'S' || *Format == 'a' || *Format == 'g' || *Format == 't') {
+ BASE_ARG (BaseListMarker, VOID *) = VA_ARG (VaListMarker, VOID *);
+ } else if (*Format == 'c') {
+ BASE_ARG (BaseListMarker, UINTN) = VA_ARG (VaListMarker, UINTN);
+ } else if (*Format == 'r') {
+ BASE_ARG (BaseListMarker, RETURN_STATUS) = VA_ARG (VaListMarker, RETURN_STATUS);
+ }
+
+ //
+ // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then ASSERT()
+ // This indicates that the DEBUG() macro is passing in more argument than can be handled by
+ // the EFI_DEBUG_INFO record
+ //
+ ASSERT ((CHAR8 *)BaseListMarker <= FormatString);
+
+ //
+ // If the converted BASE_LIST is larger than the 12 * sizeof (UINT64) allocated bytes, then return
+ //
+ if ((CHAR8 *)BaseListMarker > FormatString) {
+ VA_END (VaListMarker);
+ return;
+ }
+ }
+ VA_END (VaListMarker);
+
+ //
+ // Send the DebugInfo record
+ //
+ REPORT_STATUS_CODE_EX (
+ EFI_DEBUG_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_DC_UNSPECIFIED),
+ 0,
+ NULL,
+ &gEfiStatusCodeDataTypeDebugGuid,
+ DebugInfo,
+ TotalSize
+ );
+}
+
+/**
+ Prints an assert message containing a filename, line number, and description.
+ This may be followed by a breakpoint or a dead loop.
+
+ Print a message of the form "ASSERT <FileName>(<LineNumber>): <Description>\n"
+ to the debug output device. If DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED bit of
+ PcdDebugProperyMask is set then CpuBreakpoint() is called. Otherwise, if
+ DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED bit of PcdDebugProperyMask is set then
+ CpuDeadLoop() is called. If neither of these bits are set, then this function
+ returns immediately after the message is printed to the debug output device.
+ DebugAssert() must actively prevent recursion. If DebugAssert() is called while
+ processing another DebugAssert(), then DebugAssert() must return immediately.
+
+ If FileName is NULL, then a <FileName> string of "(NULL) Filename" is printed.
+ If Description is NULL, then a <Description> string of "(NULL) Description" is printed.
+
+ @param FileName Pointer to the name of the source file that generated the assert condition.
+ @param LineNumber The line number in the source file that generated the assert condition
+ @param Description Pointer to the description of the assert condition.
+
+**/
+VOID
+EFIAPI
+DebugAssert (
+ IN CONST CHAR8 *FileName,
+ IN UINTN LineNumber,
+ IN CONST CHAR8 *Description
+ )
+{
+ UINT64 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE / sizeof(UINT64)];
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+ UINTN HeaderSize;
+ UINTN TotalSize;
+ CHAR8 *Temp;
+ UINTN FileNameSize;
+ UINTN DescriptionSize;
+
+ //
+ // Get string size
+ //
+ HeaderSize = sizeof (EFI_DEBUG_ASSERT_DATA);
+ FileNameSize = AsciiStrSize (FileName);
+ DescriptionSize = AsciiStrSize (Description);
+
+ //
+ // Make sure it will all fit in the passed in buffer.
+ //
+ if (HeaderSize + FileNameSize + DescriptionSize > sizeof (Buffer)) {
+ //
+ // FileName + Description is too long to be filled into buffer.
+ //
+ if (HeaderSize + FileNameSize < sizeof (Buffer)) {
+ //
+ // Description has enough buffer to be truncated.
+ //
+ DescriptionSize = sizeof (Buffer) - HeaderSize - FileNameSize;
+ } else {
+ //
+ // FileName is too long to be filled into buffer.
+ // FileName will be truncated. Reserved one byte for Description NULL terminator.
+ //
+ DescriptionSize = 1;
+ FileNameSize = sizeof (Buffer) - HeaderSize - DescriptionSize;
+ }
+ }
+
+ //
+ // Fill in EFI_DEBUG_ASSERT_DATA
+ //
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)Buffer;
+ AssertData->LineNumber = (UINT32)LineNumber;
+ TotalSize = sizeof (EFI_DEBUG_ASSERT_DATA);
+
+ //
+ // Copy Ascii FileName including NULL terminator.
+ //
+ Temp = CopyMem (AssertData + 1, FileName, FileNameSize);
+ Temp[FileNameSize - 1] = 0;
+ TotalSize += FileNameSize;
+
+ //
+ // Copy Ascii Description include NULL terminator.
+ //
+ Temp = CopyMem (Temp + FileNameSize, Description, DescriptionSize);
+ Temp[DescriptionSize - 1] = 0;
+ TotalSize += DescriptionSize;
+
+ REPORT_STATUS_CODE_EX (
+ (EFI_ERROR_CODE | EFI_ERROR_UNRECOVERED),
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_EC_ILLEGAL_SOFTWARE_STATE),
+ 0,
+ NULL,
+ NULL,
+ AssertData,
+ TotalSize
+ );
+
+ //
+ // Generate a Breakpoint, DeadLoop, or NOP based on PCD settings
+ //
+ if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_BREAKPOINT_ENABLED) != 0) {
+ CpuBreakpoint ();
+ } else if ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_ASSERT_DEADLOOP_ENABLED) != 0) {
+ CpuDeadLoop ();
+ }
+}
+
+
+/**
+ Fills a target buffer with PcdDebugClearMemoryValue, and returns the target buffer.
+
+ This function fills Length bytes of Buffer with the value specified by
+ PcdDebugClearMemoryValue, and returns Buffer.
+
+ If Buffer is NULL, then ASSERT().
+ If Length is greater than (MAX_ADDRESS - Buffer + 1), then ASSERT().
+
+ @param Buffer Pointer to the target buffer to be filled with PcdDebugClearMemoryValue.
+ @param Length Number of bytes in Buffer to fill with zeros PcdDebugClearMemoryValue.
+
+ @return Buffer Pointer to the target buffer filled with PcdDebugClearMemoryValue.
+
+**/
+VOID *
+EFIAPI
+DebugClearMemory (
+ OUT VOID *Buffer,
+ IN UINTN Length
+ )
+{
+ ASSERT (Buffer != NULL);
+
+ return SetMem (Buffer, Length, PcdGet8 (PcdDebugClearMemoryValue));
+}
+
+
+/**
+ Returns TRUE if ASSERT() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugAssertEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_ASSERT_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_PRINT_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_PRINT_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG_CODE() macros are enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_DEBUG_CODE_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if DEBUG_CLEAR_MEMORY() macro is enabled.
+
+ This function returns TRUE if the DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of
+ PcdDebugProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is set.
+ @retval FALSE The DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED bit of PcdDebugProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+DebugClearMemoryEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdDebugPropertyMask) & DEBUG_PROPERTY_CLEAR_MEMORY_ENABLED) != 0);
+}
+
+/**
+ Returns TRUE if any one of the bit is set both in ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+ This function compares the bit mask of ErrorLevel and PcdFixedDebugPrintErrorLevel.
+
+ @retval TRUE Current ErrorLevel is supported.
+ @retval FALSE Current ErrorLevel is not supported.
+
+**/
+BOOLEAN
+EFIAPI
+DebugPrintLevelEnabled (
+ IN CONST UINTN ErrorLevel
+ )
+{
+ return (BOOLEAN) ((ErrorLevel & PcdGet32(PcdFixedDebugPrintErrorLevel)) != 0);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
new file mode 100644
index 0000000000..55446672d7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.inf
@@ -0,0 +1,54 @@
+## @file
+# Debug Library based on report status code library
+#
+# Debug Library for PEIMs and DXE drivers that sends debug messages to ReportStatusCode
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiDxeDebugLibReportStatusCode
+ MODULE_UNI_FILE = PeiDxeDebugLibReportStatusCode.uni
+ FILE_GUID = bda39d3a-451b-4350-8266-81ab10fa0523
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = DebugLib|DXE_CORE DXE_DRIVER DXE_RUNTIME_DRIVER DXE_SAL_DRIVER DXE_SMM_DRIVER SMM_CORE PEIM SEC PEI_CORE UEFI_APPLICATION UEFI_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DebugLib.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ ReportStatusCodeLib
+ BaseMemoryLib
+ BaseLib
+ DebugPrintErrorLevelLib
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdDebugClearMemoryValue ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdDebugPropertyMask ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdFixedDebugPrintErrorLevel ## CONSUMES
+
+[Guids]
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## GUID
+
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
new file mode 100644
index 0000000000..fe2abee431
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiDxeDebugLibReportStatusCode/PeiDxeDebugLibReportStatusCode.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.c b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.c
new file mode 100644
index 0000000000..fc729a899c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.c
@@ -0,0 +1,50 @@
+/** @file
+ This Library uses Framework RecoveryModule PPI to do system recovery.
+
+ This library instance is no longer used and module using this library
+ class should update to directly locate EFI_PEI_RECOVERY_MODULE_PPI defined
+ in PI 1.2 specification.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/DebugLib.h>
+
+#include <Ppi/RecoveryModule.h>
+
+/**
+ Calling this function causes the system do recovery.
+
+ @retval EFI_SUCESS Sucess to do recovery.
+ @retval Others Fail to do recovery.
+**/
+EFI_STATUS
+EFIAPI
+PeiRecoverFirmware (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_RECOVERY_MODULE_PPI *PeiRecovery;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiRecoveryModulePpiGuid,
+ 0,
+ NULL,
+ (VOID **)&PeiRecovery
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return PeiRecovery->LoadRecoveryCapsule ((EFI_PEI_SERVICES **) GetPeiServicesTablePointer(), PeiRecovery);
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.inf b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.inf
new file mode 100644
index 0000000000..9bd321e178
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.inf
@@ -0,0 +1,50 @@
+## @file
+# PEIM Recovery Library supports system recovery boot.
+#
+# This library instance is no longer used and module using this library
+# class should update to directly locate EFI_PEI_RECOVERY_MODULE_PPI defined
+# in PI 1.2 specification.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiRecoveryLib
+ MODULE_UNI_FILE = PeiRecoveryLib.uni
+ FILE_GUID = C0227547-0811-4cbb-ABEA-DECD22829122
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = RecoveryLib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PeiRecoveryLib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PeiServicesTablePointerLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiRecoveryModulePpiGuid ## CONSUMES
+
+ \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.uni b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.uni
new file mode 100644
index 0000000000..11891e58e0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiRecoveryLib/PeiRecoveryLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.c b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.c
new file mode 100644
index 0000000000..d16e3cac24
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.c
@@ -0,0 +1,51 @@
+/** @file
+ This library provides API to invoke the S3 resume vector in the APCI Table in S3 resume mode.
+
+ This library instance is no longer used and module using this library
+ class should update to directly locate EFI_PEI_S3_RESUME_PPI defined
+ in PI 1.2 specification.
+
+Copyright (c) 2006 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiPei.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/PeiServicesTablePointerLib.h>
+#include <Library/DebugLib.h>
+
+#include <Ppi/S3Resume.h>
+
+/**
+ This function is responsible for calling the S3 resume vector in the ACPI Tables.
+
+ @retval EFI_SUCESS Success to restore config from S3.
+ @retval Others Fail to restore config from S3.
+**/
+EFI_STATUS
+EFIAPI
+AcpiS3ResumeOs (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_S3_RESUME_PPI *S3Resume;
+
+ Status = PeiServicesLocatePpi (
+ &gEfiPeiS3ResumePpiGuid,
+ 0,
+ NULL,
+ (VOID **)&S3Resume
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return S3Resume->S3RestoreConfig ((EFI_PEI_SERVICES **) GetPeiServicesTablePointer());
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.inf b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.inf
new file mode 100644
index 0000000000..b01e1860f4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.inf
@@ -0,0 +1,49 @@
+## @file
+# This library provides API to invoke the S3 resume vector in the ACPI Table in S3 resume mode.
+#
+# This library instance is no longer used and module using this library
+# class should update to directly locate EFI_PEI_S3_RESUME_PPI defined
+# in PI 1.2 specification.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PeiS3Lib
+ MODULE_UNI_FILE = PeiS3Lib.uni
+ FILE_GUID = EFB7D3A8-DEB9-4bed-B6D6-3B09BEEB835A
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = S3Lib|PEIM
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ PeiS3Lib.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ PeiServicesTablePointerLib
+ DebugLib
+
+[Ppis]
+ gEfiPeiS3ResumePpiGuid ## CONSUMES
+
diff --git a/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.uni b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.uni
new file mode 100644
index 0000000000..dceb0011c9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PeiS3Lib/PeiS3Lib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c
new file mode 100644
index 0000000000..9fb3b23282
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.c
@@ -0,0 +1,187 @@
+/** @file
+ This file include all platform action which can be customized by IBV/OEM.
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BdsPlatform.h"
+
+//
+// BDS Platform Functions
+//
+/**
+ Platform Bds init. Include the platform firmware vendor, revision
+ and so crc check.
+
+**/
+VOID
+EFIAPI
+PlatformBdsInit (
+ VOID
+ )
+{
+}
+
+/**
+ Connect the predefined platform default console device. Always try to find
+ and enable the vga device if have.
+
+ @param PlatformConsole Predefined platform default console device array.
+
+ @retval EFI_SUCCESS Success connect at least one ConIn and ConOut
+ device, there must have one ConOut device is
+ active vga device.
+ @return Return the status of BdsLibConnectAllDefaultConsoles ()
+
+**/
+EFI_STATUS
+PlatformBdsConnectConsole (
+ IN BDS_CONSOLE_CONNECT_ENTRY *PlatformConsole
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Connect with predefined platform connect sequence,
+ the OEM/IBV can customize with their own connect sequence.
+**/
+VOID
+PlatformBdsConnectSequence (
+ VOID
+ )
+{
+}
+
+/**
+ Load the predefined driver option, OEM/IBV can customize this
+ to load their own drivers
+
+ @param BdsDriverLists - The header of the driver option link list.
+
+**/
+VOID
+PlatformBdsGetDriverOption (
+ IN OUT LIST_ENTRY *BdsDriverLists
+ )
+{
+}
+
+/**
+ Perform the platform diagnostic, such like test memory. OEM/IBV also
+ can customize this function to support specific platform diagnostic.
+
+ @param MemoryTestLevel The memory test intensive level
+ @param QuietBoot Indicate if need to enable the quiet boot
+ @param BaseMemoryTest A pointer to BdsMemoryTest()
+
+**/
+VOID
+PlatformBdsDiagnostics (
+ IN EXTENDMEM_COVERAGE_LEVEL MemoryTestLevel,
+ IN BOOLEAN QuietBoot,
+ IN BASEM_MEMORY_TEST BaseMemoryTest
+ )
+{
+}
+
+/**
+ The function will execute with as the platform policy, current policy
+ is driven by boot mode. IBV/OEM can customize this code for their specific
+ policy action.
+
+ @param DriverOptionList The header of the driver option link list
+ @param BootOptionList The header of the boot option link list
+ @param ProcessCapsules A pointer to ProcessCapsules()
+ @param BaseMemoryTest A pointer to BaseMemoryTest()
+
+**/
+VOID
+EFIAPI
+PlatformBdsPolicyBehavior (
+ IN LIST_ENTRY *DriverOptionList,
+ IN LIST_ENTRY *BootOptionList,
+ IN PROCESS_CAPSULES ProcessCapsules,
+ IN BASEM_MEMORY_TEST BaseMemoryTest
+ )
+{
+}
+
+/**
+ Hook point after a boot attempt succeeds. We don't expect a boot option to
+ return, so the UEFI 2.0 specification defines that you will default to an
+ interactive mode and stop processing the BootOrder list in this case. This
+ is also a platform implementation and can be customized by IBV/OEM.
+
+ @param Option Pointer to Boot Option that succeeded to boot.
+
+**/
+VOID
+EFIAPI
+PlatformBdsBootSuccess (
+ IN BDS_COMMON_OPTION *Option
+ )
+{
+}
+
+/**
+ Hook point after a boot attempt fails.
+
+ @param Option Pointer to Boot Option that failed to boot.
+ @param Status Status returned from failed boot.
+ @param ExitData Exit data returned from failed boot.
+ @param ExitDataSize Exit data size returned from failed boot.
+
+**/
+VOID
+EFIAPI
+PlatformBdsBootFail (
+ IN BDS_COMMON_OPTION *Option,
+ IN EFI_STATUS Status,
+ IN CHAR16 *ExitData,
+ IN UINTN ExitDataSize
+ )
+{
+}
+
+/**
+ This function locks platform flash that is not allowed to be updated during normal boot path.
+ The flash layout is platform specific.
+**/
+VOID
+EFIAPI
+PlatformBdsLockNonUpdatableFlash (
+ VOID
+ )
+{
+ return ;
+}
+
+
+/**
+ Lock the ConsoleIn device in system table. All key
+ presses will be ignored until the Password is typed in. The only way to
+ disable the password is to type it in to a ConIn device.
+
+ @param Password Password used to lock ConIn device.
+
+ @retval EFI_SUCCESS lock the Console In Spliter virtual handle successfully.
+ @retval EFI_UNSUPPORTED Password not found
+
+**/
+EFI_STATUS
+EFIAPI
+LockKeyboards (
+ IN CHAR16 *Password
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h
new file mode 100644
index 0000000000..38ea72ee6c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/BdsPlatform.h
@@ -0,0 +1,28 @@
+/** @file
+ Head file for BDS Platform specific code
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BDS_PLATFORM_H_
+#define _BDS_PLATFORM_H_
+
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseLib.h>
+#include <Library/PcdLib.h>
+#include <Library/GenericBdsLib.h>
+#include <Library/PlatformBdsLib.h>
+
+
+#endif // _BDS_PLATFORM_H
diff --git a/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLib.uni b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLib.uni
new file mode 100644
index 0000000000..3ec1a92f63
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLib.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
new file mode 100644
index 0000000000..37c98cff00
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformBdsLibNull.inf
@@ -0,0 +1,47 @@
+## @file
+# NULL implementation for PlatformBdsLib library class interfaces.
+#
+# Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = PlatformBdsLib
+ MODULE_UNI_FILE = PlatformBdsLib.uni
+ FILE_GUID = 143B5044-7C1B-4904-9778-EA16F1F3D554
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = PlatformBdsLib|DXE_DRIVER
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ BdsPlatform.c
+ PlatformData.c
+ BdsPlatform.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PcdLib
+ GenericBdsLib \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformData.c b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformData.c
new file mode 100644
index 0000000000..131efab4d9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/PlatformBdsLibNull/PlatformData.c
@@ -0,0 +1,21 @@
+/** @file
+ Defined the platform specific device path which will be used by
+ platform Bbd to perform the platform policy connect.
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BdsPlatform.h"
+
+///
+/// Predefined platform default time out value
+///
+UINT16 gPlatformBootTimeOutDefault = 10;
diff --git a/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLib.c b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLib.c
new file mode 100644
index 0000000000..c49dacaeb1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLib.c
@@ -0,0 +1,493 @@
+/** @file
+ API implementation for instance of Report Status Code Library.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "ReportStatusCodeLibInternal.h"
+
+/**
+ Converts a status code to an 8-bit POST code value.
+
+ Converts the status code specified by CodeType and Value to an 8-bit POST code
+ and returns the 8-bit POST code in PostCode. If CodeType is an
+ EFI_PROGRESS_CODE or CodeType is an EFI_ERROR_CODE, then bits 0..4 of PostCode
+ are set to bits 16..20 of Value, and bits 5..7 of PostCode are set to bits
+ 24..26 of Value., and TRUE is returned. Otherwise, FALSE is returned.
+
+ If PostCode is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param PostCode A pointer to the 8-bit POST code value to return.
+
+ @retval TRUE The status code specified by CodeType and Value was converted
+ to an 8-bit POST code and returned in PostCode.
+ @retval FALSE The status code specified by CodeType and Value could not be
+ converted to an 8-bit POST code value.
+
+**/
+BOOLEAN
+EFIAPI
+CodeTypeToPostCode (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ OUT UINT8 *PostCode
+ )
+{
+ //
+ // If PostCode is NULL, then ASSERT()
+ //
+ ASSERT (PostCode != NULL);
+
+ //
+ // Convert Value to an 8 bit post code
+ //
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ) {
+ *PostCode = (UINT8) ((((Value & EFI_STATUS_CODE_CLASS_MASK) >> 24) << 5) |
+ (((Value & EFI_STATUS_CODE_SUBCLASS_MASK) >> 16) & 0x1f));
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts ASSERT() information from a status code structure.
+
+ Converts the status code specified by CodeType, Value, and Data to the ASSERT()
+ arguments specified by Filename, Description, and LineNumber. If CodeType is
+ an EFI_ERROR_CODE, and CodeType has a severity of EFI_ERROR_UNRECOVERED, and
+ Value has an operation mask of EFI_SW_EC_ILLEGAL_SOFTWARE_STATE, extract
+ Filename, Description, and LineNumber from the optional data area of the
+ status code buffer specified by Data. The optional data area of Data contains
+ a Null-terminated ASCII string for the FileName, followed by a Null-terminated
+ ASCII string for the Description, followed by a 32-bit LineNumber. If the
+ ASSERT() information could be extracted from Data, then return TRUE.
+ Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If Filename is NULL, then ASSERT().
+ If Description is NULL, then ASSERT().
+ If LineNumber is NULL, then ASSERT().
+
+ @param CodeType The type of status code being converted.
+ @param Value The status code value being converted.
+ @param Data Pointer to status code data buffer.
+ @param Filename Pointer to the source file name that generated the ASSERT().
+ @param Description Pointer to the description of the ASSERT().
+ @param LineNumber Pointer to source line number that generated the ASSERT().
+
+ @retval TRUE The status code specified by CodeType, Value, and Data was
+ converted ASSERT() arguments specified by Filename, Description,
+ and LineNumber.
+ @retval FALSE The status code specified by CodeType, Value, and Data could
+ not be converted to ASSERT() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractAssertInfo (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT CHAR8 **Filename,
+ OUT CHAR8 **Description,
+ OUT UINT32 *LineNumber
+ )
+{
+ EFI_DEBUG_ASSERT_DATA *AssertData;
+
+ ASSERT (Data != NULL);
+ ASSERT (Filename != NULL);
+ ASSERT (Description != NULL);
+ ASSERT (LineNumber != NULL);
+
+ if (((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) &&
+ ((CodeType & EFI_STATUS_CODE_SEVERITY_MASK) == EFI_ERROR_UNRECOVERED) &&
+ ((Value & EFI_STATUS_CODE_OPERATION_MASK) == EFI_SW_EC_ILLEGAL_SOFTWARE_STATE)) {
+ AssertData = (EFI_DEBUG_ASSERT_DATA *)(Data + 1);
+ *Filename = (CHAR8 *)(AssertData + 1);
+ *Description = *Filename + AsciiStrLen (*Filename) + 1;
+ *LineNumber = AssertData->LineNumber;
+ return TRUE;
+ }
+ return FALSE;
+}
+
+
+/**
+ Extracts DEBUG() information from a status code structure.
+
+ Converts the status code specified by Data to the DEBUG() arguments specified
+ by ErrorLevel, Marker, and Format. If type GUID in Data is
+ EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID, then extract ErrorLevel, Marker, and
+ Format from the optional data area of the status code buffer specified by Data.
+ The optional data area of Data contains a 32-bit ErrorLevel followed by Marker
+ which is 12 UINTN parameters, followed by a Null-terminated ASCII string for
+ the Format. If the DEBUG() information could be extracted from Data, then
+ return TRUE. Otherwise, FALSE is returned.
+
+ If Data is NULL, then ASSERT().
+ If ErrorLevel is NULL, then ASSERT().
+ If Marker is NULL, then ASSERT().
+ If Format is NULL, then ASSERT().
+
+ @param Data Pointer to status code data buffer.
+ @param ErrorLevel Pointer to error level mask for a debug message.
+ @param Marker Pointer to the variable argument list associated with Format.
+ @param Format Pointer to a Null-terminated ASCII format string of a
+ debug message.
+
+ @retval TRUE The status code specified by Data was converted DEBUG() arguments
+ specified by ErrorLevel, Marker, and Format.
+ @retval FALSE The status code specified by Data could not be converted to
+ DEBUG() arguments.
+
+**/
+BOOLEAN
+EFIAPI
+ReportStatusCodeExtractDebugInfo (
+ IN CONST EFI_STATUS_CODE_DATA *Data,
+ OUT UINT32 *ErrorLevel,
+ OUT BASE_LIST *Marker,
+ OUT CHAR8 **Format
+ )
+{
+ EFI_DEBUG_INFO *DebugInfo;
+
+ ASSERT (Data != NULL);
+ ASSERT (ErrorLevel != NULL);
+ ASSERT (Marker != NULL);
+ ASSERT (Format != NULL);
+
+ //
+ // If the GUID type is not EFI_STATUS_CODE_DATA_TYPE_DEBUG_GUID then return FALSE
+ //
+ if (!CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the debug information from the status code record
+ //
+ DebugInfo = (EFI_DEBUG_INFO *)(Data + 1);
+
+ *ErrorLevel = DebugInfo->ErrorLevel;
+
+ //
+ // The first 12 * sizeof (UINT64) bytes following EFI_DEBUG_INFO are for variable arguments
+ // of format in DEBUG string. Its address is returned in Marker and has to be 64-bit aligned.
+ // It must be noticed that EFI_DEBUG_INFO follows EFI_STATUS_CODE_DATA, whose size is
+ // 20 bytes. The size of EFI_DEBUG_INFO is 4 bytes, so we can ensure that Marker
+ // returned is 64-bit aligned.
+ // 64-bit aligned is a must, otherwise retrieving 64-bit parameter from BASE_LIST will
+ // cause unalignment exception.
+ //
+ *Marker = (BASE_LIST) (DebugInfo + 1);
+ *Format = (CHAR8 *)(((UINT64 *)*Marker) + 12);
+
+ return TRUE;
+}
+
+
+/**
+ Reports a status code.
+
+ Reports the status code specified by the parameters Type and Value. Status
+ code also require an instance, caller ID, and extended data. This function
+ passed in a zero instance, NULL extended data, and a caller ID of
+ gEfiCallerIdGuid, which is the GUID for the module.
+
+ ReportStatusCode()must actively prevent recusrsion. If ReportStatusCode()
+ is called while processing another any other Report Status Code Library function,
+ then ReportStatusCode() must return immediately.
+
+ @param Type Status code type.
+ @param Value Status code value.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_DEVICE_ERROR There status code could not be reported due to a
+ device error.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value
+ )
+{
+ return InternalReportStatusCode (Type, Value, 0, &gEfiCallerIdGuid, NULL);
+}
+
+
+/**
+ Reports a status code with a Device Path Protocol as the extended data.
+
+ Allocates and fills in the extended data section of a status code with the
+ Device Path Protocol specified by DevicePath. This function is responsible
+ for allocating a buffer large enough for the standard header and the device
+ path. The standard header is filled in with a GUID of
+ gEfiStatusCodeSpecificDataGuid. The status code is reported with a zero
+ instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithDevicePath()must actively prevent recursion. If
+ ReportStatusCodeWithDevicePath() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithDevicePath()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If DevicePath is NULL, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param DevicePath Pointer to the Device Path Protocol to be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by DevicePath.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithDevicePath (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ ASSERT (DevicePath != NULL);
+ return ReportStatusCodeWithExtendedData (
+ Type,
+ Value,
+ (VOID *)DevicePath,
+ GetDevicePathSize (DevicePath)
+ );
+}
+
+
+/**
+ Reports a status code with an extended data buffer.
+
+ Allocates and fills in the extended data section of a status code with the
+ extended data specified by ExtendedData and ExtendedDataSize. ExtendedData
+ is assumed to be one of the data structures specified in Related Definitions.
+ These data structure do not have the standard header, so this function is
+ responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled
+ in with a GUID of gEfiStatusCodeSpecificDataGuid. The status code is reported
+ with a zero instance and a caller ID of gEfiCallerIdGuid.
+
+ ReportStatusCodeWithExtendedData()must actively prevent recursion. If
+ ReportStatusCodeWithExtendedData() is called while processing another any other
+ Report Status Code Library function, then ReportStatusCodeWithExtendedData()
+ must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL, then ASSERT().
+ If ExtendedDataSize is 0, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param ExtendedData Pointer to the extended data buffer to be reported.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer to
+ be reported.
+
+ @retval EFI_SUCCESS The status code was reported with the extended
+ data specified by ExtendedData and ExtendedDataSize.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate the
+ extended data section.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeWithExtendedData (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN CONST VOID *ExtendedData,
+ IN UINTN ExtendedDataSize
+ )
+{
+ ASSERT (ExtendedData != NULL);
+ ASSERT (ExtendedDataSize != 0);
+ return ReportStatusCodeEx (
+ Type,
+ Value,
+ 0,
+ NULL,
+ NULL,
+ ExtendedData,
+ ExtendedDataSize
+ );
+}
+
+
+/**
+ Reports a status code with full parameters.
+
+ The function reports a status code. If ExtendedData is NULL and ExtendedDataSize
+ is 0, then an extended data buffer is not reported. If ExtendedData is not
+ NULL and ExtendedDataSize is not 0, then an extended data buffer is allocated.
+ ExtendedData is assumed not have the standard status code header, so this function
+ is responsible for allocating a buffer large enough for the standard header and
+ the extended data passed into this function. The standard header is filled in
+ with a GUID specified by ExtendedDataGuid. If ExtendedDataGuid is NULL, then a
+ GUID of gEfiStatusCodeSpecificDataGuid is used. The status code is reported with
+ an instance specified by Instance and a caller ID specified by CallerId. If
+ CallerId is NULL, then a caller ID of gEfiCallerIdGuid is used.
+
+ ReportStatusCodeEx()must actively prevent recursion. If
+ ReportStatusCodeEx() is called while processing another any
+ other Report Status Code Library function, then
+ ReportStatusCodeEx() must return EFI_DEVICE_ERROR immediately.
+
+ If ExtendedData is NULL and ExtendedDataSize is not zero, then ASSERT().
+ If ExtendedData is not NULL and ExtendedDataSize is zero, then ASSERT().
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. If this parameter is NULL, then a caller
+ ID of gEfiCallerIdGuid is used.
+ @param ExtendedDataGuid Pointer to the GUID for the extended data buffer.
+ If this parameter is NULL, then a the status code
+ standard header is filled in with
+ gEfiStatusCodeSpecificDataGuid.
+ @param ExtendedData Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+ @param ExtendedDataSize The size, in bytes, of the extended data buffer.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_OUT_OF_RESOURCES There were not enough resources to allocate
+ the extended data section if it was specified.
+ @retval EFI_UNSUPPORTED Report status code is not supported
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeEx (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_GUID *ExtendedDataGuid OPTIONAL,
+ IN CONST VOID *ExtendedData OPTIONAL,
+ IN UINTN ExtendedDataSize
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT (!((ExtendedData == NULL) && (ExtendedDataSize != 0)));
+ ASSERT (!((ExtendedData != NULL) && (ExtendedDataSize == 0)));
+
+ if (ExtendedDataSize > EFI_STATUS_CODE_DATA_MAX_SIZE) {
+ DEBUG ((EFI_D_ERROR, "Status code extended data is too large to be reported!\n"));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in the extended data header
+ //
+ mStatusCodeData->HeaderSize = (UINT16) sizeof (EFI_STATUS_CODE_DATA);
+ mStatusCodeData->Size = (UINT16)ExtendedDataSize;
+ if (ExtendedDataGuid == NULL) {
+ ExtendedDataGuid = &gEfiStatusCodeSpecificDataGuid;
+ }
+ CopyGuid (&mStatusCodeData->Type, ExtendedDataGuid);
+
+ //
+ // Fill in the extended data buffer
+ //
+ if (ExtendedData != NULL) {
+ CopyMem (mStatusCodeData + 1, ExtendedData, ExtendedDataSize);
+ }
+
+ //
+ // Report the status code
+ //
+ if (CallerId == NULL) {
+ CallerId = &gEfiCallerIdGuid;
+ }
+ Status = InternalReportStatusCode (Type, Value, Instance, CallerId, mStatusCodeData);
+
+ return Status;
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_PROGRESS_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportProgressCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_PROGRESS_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_ERROR_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportErrorCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_ERROR_CODE_ENABLED) != 0);
+}
+
+
+/**
+ Returns TRUE if status codes of type EFI_DEBUG_CODE are enabled
+
+ This function returns TRUE if the REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED
+ bit of PcdReportStatusCodeProperyMask is set. Otherwise FALSE is returned.
+
+ @retval TRUE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is set.
+ @retval FALSE The REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED bit of
+ PcdReportStatusCodeProperyMask is clear.
+
+**/
+BOOLEAN
+EFIAPI
+ReportDebugCodeEnabled (
+ VOID
+ )
+{
+ return (BOOLEAN) ((PcdGet8 (PcdReportStatusCodePropertyMask) & REPORT_STATUS_CODE_PROPERTY_DEBUG_CODE_ENABLED) != 0);
+}
diff --git a/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLibInternal.h b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLibInternal.h
new file mode 100644
index 0000000000..1f9a0c7e1d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/ReportStatusCodeLibInternal.h
@@ -0,0 +1,73 @@
+/** @file
+ Internal Header file of Report Status Code Library for RUNTIME
+ DXE Phase.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef __REPORT_STATUS_CODE_LIB_INTERNAL__H__
+#define __REPORT_STATUS_CODE_LIB_INTERNAL__H__
+
+#include <FrameworkSmm.h>
+
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/EventGroup.h>
+
+#include <Protocol/SmmStatusCode.h>
+#include <Protocol/StatusCode.h>
+#include <Protocol/SmmBase.h>
+
+
+extern EFI_STATUS_CODE_DATA *mStatusCodeData;
+
+/**
+ Internal worker function that reports a status code through the status code service.
+
+ If status code service is not cached, then this function checks if status code service is
+ available in system. If status code service is not available, then EFI_UNSUPPORTED is
+ returned. If status code service is present, then it is cached in mReportStatusCode.
+ Finally this function reports status code through the status code service.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Status code service is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.inf b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.inf
new file mode 100644
index 0000000000..6964e44f34
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.inf
@@ -0,0 +1,73 @@
+## @file
+# Framework Report status code library instance which supports logging message in SMM, as well as DXE & runtime phase.
+#
+# This library instance supports status code report in SMM, as well as DXE & runtime phase.
+# In SMM, it logs message via SMM Status Code Protocol.
+# Otherwise, it logs message to ReportStatusCode() in framework runtime services table or runtime report status code protocol.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SmmRuntimeDxeReportStatusCodeLibFramework
+ MODULE_UNI_FILE = SmmRuntimeDxeReportStatusCodeLibFramework.uni
+ FILE_GUID = D65D9F72-7BCE-4f73-A673-47AF446A1A31
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ LIBRARY_CLASS = ReportStatusCodeLib|DXE_RUNTIME_DRIVER DXE_SMM_DRIVER
+
+ CONSTRUCTOR = ReportStatusCodeLibConstruct
+ DESTRUCTOR = ReportStatusCodeLibDestruct
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+
+[Sources]
+ ReportStatusCodeLib.c
+ SmmRuntimeDxeSupport.c
+ ReportStatusCodeLibInternal.h
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ BaseMemoryLib
+ BaseLib
+ DebugLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ DevicePathLib
+ MemoryAllocationLib
+
+[Guids]
+ gEfiStatusCodeSpecificDataGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmBaseProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiSmmStatusCodeProtocolGuid ## SOMETIMES_CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdReportStatusCodePropertyMask ## CONSUMES
+
diff --git a/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.uni b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.uni
new file mode 100644
index 0000000000..2268a3c094
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeReportStatusCodeLibFramework.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeSupport.c b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeSupport.c
new file mode 100644
index 0000000000..554be152b3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Library/SmmRuntimeDxeReportStatusCodeLibFramework/SmmRuntimeDxeSupport.c
@@ -0,0 +1,335 @@
+/** @file
+ Library constructor & destructor, event handlers, and other internal worker functions.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "ReportStatusCodeLibInternal.h"
+
+EFI_EVENT mVirtualAddressChangeEvent;
+EFI_EVENT mExitBootServicesEvent;
+EFI_STATUS_CODE_DATA *mStatusCodeData;
+BOOLEAN mInSmm;
+EFI_SMM_BASE_PROTOCOL *mSmmBase;
+EFI_RUNTIME_SERVICES *mInternalRT;
+BOOLEAN mHaveExitedBootServices = FALSE;
+EFI_REPORT_STATUS_CODE mReportStatusCode = NULL;
+EFI_SMM_STATUS_CODE_PROTOCOL *mSmmStatusCodeProtocol;
+
+/**
+ Locates and caches SMM Status Code Protocol.
+
+**/
+VOID
+SmmStatusCodeInitialize (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (&gEfiSmmStatusCodeProtocolGuid, NULL, (VOID **) &mSmmStatusCodeProtocol);
+ if (EFI_ERROR (Status)) {
+ mSmmStatusCodeProtocol = NULL;
+ }
+}
+
+/**
+ Report status code via SMM Status Code Protocol.
+
+ @param Type Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to classify the entity
+ as well as an operation. For progress codes, the operation is the current activity.
+ For error codes, it is the exception. For debug codes, it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within the system.
+ A system may contain multiple entities that match a class/subclass pairing.
+ The instance differentiates between them. An instance of 0 indicates that instance information is unavailable,
+ not meaningful, or not relevant. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to different callers.
+ @param Data This optional parameter may be used to pass additional data
+
+ @retval EFI_SUCCESS Always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+SmmStatusCodeReport (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if (mSmmStatusCodeProtocol != NULL) {
+ (mSmmStatusCodeProtocol->ReportStatusCode) (mSmmStatusCodeProtocol, Type, Value, Instance, CallerId, Data);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Locate the report status code service.
+
+ In SMM, it tries to retrieve SMM Status Code Protocol.
+ Otherwise, it first tries to retrieve ReportStatusCode() in Runtime Services Table.
+ If not found, it then tries to retrieve ReportStatusCode() API of Report Status Code Protocol.
+
+ @return Function pointer to the report status code service.
+ NULL is returned if no status code service is available.
+
+**/
+EFI_REPORT_STATUS_CODE
+InternalGetReportStatusCode (
+ VOID
+ )
+{
+ EFI_STATUS_CODE_PROTOCOL *StatusCodeProtocol;
+ EFI_STATUS Status;
+
+ if (mInSmm) {
+ return (EFI_REPORT_STATUS_CODE) SmmStatusCodeReport;
+ } else if (mInternalRT != NULL && mInternalRT->Hdr.Revision < 0x20000) {
+ return ((FRAMEWORK_EFI_RUNTIME_SERVICES*)mInternalRT)->ReportStatusCode;
+ } else if (!mHaveExitedBootServices) {
+ //
+ // Check gBS just in case. ReportStatusCode is called before gBS is initialized.
+ //
+ if (gBS != NULL) {
+ Status = gBS->LocateProtocol (&gEfiStatusCodeRuntimeProtocolGuid, NULL, (VOID**)&StatusCodeProtocol);
+ if (!EFI_ERROR (Status) && StatusCodeProtocol != NULL) {
+ return StatusCodeProtocol->ReportStatusCode;
+ }
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ Internal worker function that reports a status code through the status code service.
+
+ If status code service is not cached, then this function checks if status code service is
+ available in system. If status code service is not available, then EFI_UNSUPPORTED is
+ returned. If status code service is present, then it is cached in mReportStatusCode.
+ Finally this function reports status code through the status code service.
+
+ @param Type Status code type.
+ @param Value Status code value.
+ @param Instance Status code instance number.
+ @param CallerId Pointer to a GUID that identifies the caller of this
+ function. This is an optional parameter that may be
+ NULL.
+ @param Data Pointer to the extended data buffer. This is an
+ optional parameter that may be NULL.
+
+ @retval EFI_SUCCESS The status code was reported.
+ @retval EFI_UNSUPPORTED Status code service is not available.
+ @retval EFI_UNSUPPORTED Status code type is not supported.
+
+**/
+EFI_STATUS
+InternalReportStatusCode (
+ IN EFI_STATUS_CODE_TYPE Type,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if ((ReportProgressCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) ||
+ (ReportErrorCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) ||
+ (ReportDebugCodeEnabled() && ((Type) & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE)) {
+ //
+ // If mReportStatusCode is NULL, then check if status code service is available in system.
+ //
+ if (mReportStatusCode == NULL) {
+ mReportStatusCode = InternalGetReportStatusCode ();
+ if (mReportStatusCode == NULL) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // A status code service is present in system, so pass in all the parameters to the service.
+ //
+ return (*mReportStatusCode) (Type, Value, Instance, (EFI_GUID *)CallerId, Data);
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Notification function of EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+ReportStatusCodeLibVirtualAddressChange (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ if (mReportStatusCode != NULL) {
+ mInternalRT->ConvertPointer (0, (VOID **) &mReportStatusCode);
+ }
+ mInternalRT->ConvertPointer (0, (VOID **) &mStatusCodeData);
+ mInternalRT->ConvertPointer (0, (VOID **) &mInternalRT);
+}
+
+/**
+ Notification function of EVT_SIGNAL_EXIT_BOOT_SERVICES.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context
+
+**/
+VOID
+EFIAPI
+ReportStatusCodeLibExitBootServices (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // If mReportStatusCode is NULL, then see if a Status Code Protocol instance is present
+ // in the handle database.
+ //
+ if (mReportStatusCode == NULL) {
+ mReportStatusCode = InternalGetReportStatusCode ();
+ }
+
+ mHaveExitedBootServices = TRUE;
+}
+
+/**
+ The constructor function of SMM Runtime DXE Report Status Code Lib.
+
+ This function allocates memory for extended status code data, caches
+ the report status code service, and registers events.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeLibConstruct (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // If in SMM mode, then allocates memory from SMRAM for extended status code data.
+ //
+ Status = gBS->LocateProtocol (&gEfiSmmBaseProtocolGuid, NULL, (VOID **) &mSmmBase);
+ if (!EFI_ERROR (Status)) {
+ mSmmBase->InSmm (mSmmBase, &mInSmm);
+ if (mInSmm) {
+ Status = mSmmBase->SmmAllocatePool (
+ mSmmBase,
+ EfiRuntimeServicesData,
+ sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE,
+ (VOID **) &mStatusCodeData
+ );
+ ASSERT_EFI_ERROR (Status);
+ SmmStatusCodeInitialize ();
+ return EFI_SUCCESS;
+ }
+ }
+
+
+ //
+ // If not in SMM mode, then allocate runtime memory for extended status code data.
+ //
+ // Library should not use the gRT directly, for it may be converted by other library instance.
+ //
+ mInternalRT = gRT;
+ mInSmm = FALSE;
+
+ mStatusCodeData = AllocateRuntimePool (sizeof (EFI_STATUS_CODE_DATA) + EFI_STATUS_CODE_DATA_MAX_SIZE);
+ ASSERT (mStatusCodeData != NULL);
+ //
+ // Cache the report status code service
+ //
+ mReportStatusCode = InternalGetReportStatusCode ();
+
+ //
+ // Register notify function for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibVirtualAddressChange,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register notify function for EVT_SIGNAL_EXIT_BOOT_SERVICES
+ //
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ ReportStatusCodeLibExitBootServices,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The destructor function of SMM Runtime DXE Report Status Code Lib.
+
+ The destructor function frees memory allocated by constructor, and closes related events.
+ It will ASSERT() if that related operation fails and it will always return EFI_SUCCESS.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The constructor always returns EFI_SUCCESS.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportStatusCodeLibDestruct (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (!mInSmm) {
+ ASSERT (gBS != NULL);
+ Status = gBS->CloseEvent (mVirtualAddressChangeEvent);
+ ASSERT_EFI_ERROR (Status);
+ Status = gBS->CloseEvent (mExitBootServicesEvent);
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (mStatusCodeData);
+ } else {
+ mSmmBase->SmmFreePool (mSmmBase, mStatusCodeData);
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/License.txt b/Core/IntelFrameworkModulePkg/License.txt
new file mode 100644
index 0000000000..be68999be6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/License.txt
@@ -0,0 +1,25 @@
+Copyright (c) 2012, Intel Corporation. All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+
+* Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+* Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in
+ the documentation and/or other materials provided with the
+ distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+"AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGE.
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c
new file mode 100644
index 0000000000..177a73bc78
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.c
@@ -0,0 +1,643 @@
+/** @file
+ This is an implementation of the ACPI S3 Save protocol. This is defined in
+ S3 boot path specification 0.9.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/LockBoxLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Guid/AcpiVariableCompatibility.h>
+#include <Guid/AcpiS3Context.h>
+#include <Guid/Acpi.h>
+#include <Protocol/AcpiS3Save.h>
+#include <IndustryStandard/Acpi.h>
+
+#include "AcpiS3Save.h"
+
+//
+// 8 extra pages for PF handler.
+//
+#define EXTRA_PAGE_TABLE_PAGES 8
+
+/**
+ Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
+**/
+VOID
+InstallAcpiS3SaveThunk (
+ VOID
+ );
+
+/**
+ Hook point for AcpiVariableThunkPlatform for S3Ready.
+
+ @param AcpiS3Context ACPI s3 context
+**/
+VOID
+S3ReadyThunkPlatform (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ );
+
+UINTN mLegacyRegionSize;
+
+EFI_ACPI_S3_SAVE_PROTOCOL mS3Save = {
+ LegacyGetS3MemorySize,
+ S3Ready,
+};
+
+EFI_GUID mAcpiS3IdtrProfileGuid = {
+ 0xdea652b0, 0xd587, 0x4c54, { 0xb5, 0xb4, 0xc6, 0x82, 0xe7, 0xa0, 0xaa, 0x3d }
+};
+
+/**
+ Allocate memory below 4G memory address.
+
+ This function allocates memory below 4G memory address.
+
+ @param MemoryType Memory type of memory to allocate.
+ @param Size Size of memory to allocate.
+
+ @return Allocated address for output.
+
+**/
+VOID*
+AllocateMemoryBelow4G (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size
+ )
+{
+ UINTN Pages;
+ EFI_PHYSICAL_ADDRESS Address;
+ EFI_STATUS Status;
+ VOID* Buffer;
+
+ Pages = EFI_SIZE_TO_PAGES (Size);
+ Address = 0xffffffff;
+
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ MemoryType,
+ Pages,
+ &Address
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Buffer = (VOID *) (UINTN) Address;
+ ZeroMem (Buffer, Size);
+
+ return Buffer;
+}
+
+/**
+
+ This function scan ACPI table in RSDT.
+
+ @param Rsdt ACPI RSDT
+ @param Signature ACPI table signature
+
+ @return ACPI table
+
+**/
+VOID *
+ScanTableInRSDT (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Rsdt,
+ IN UINT32 Signature
+ )
+{
+ UINTN Index;
+ UINT32 EntryCount;
+ UINT32 *EntryPtr;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+
+ if (Rsdt == NULL) {
+ return NULL;
+ }
+
+ EntryCount = (Rsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT32);
+
+ EntryPtr = (UINT32 *)(Rsdt + 1);
+ for (Index = 0; Index < EntryCount; Index ++, EntryPtr ++) {
+ Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(*EntryPtr));
+ if (Table->Signature == Signature) {
+ return Table;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ This function scan ACPI table in XSDT.
+
+ @param Xsdt ACPI XSDT
+ @param Signature ACPI table signature
+
+ @return ACPI table
+
+**/
+VOID *
+ScanTableInXSDT (
+ IN EFI_ACPI_DESCRIPTION_HEADER *Xsdt,
+ IN UINT32 Signature
+ )
+{
+ UINTN Index;
+ UINT32 EntryCount;
+ UINT64 EntryPtr;
+ UINTN BasePtr;
+ EFI_ACPI_DESCRIPTION_HEADER *Table;
+
+ if (Xsdt == NULL) {
+ return NULL;
+ }
+
+ EntryCount = (Xsdt->Length - sizeof (EFI_ACPI_DESCRIPTION_HEADER)) / sizeof(UINT64);
+
+ BasePtr = (UINTN)(Xsdt + 1);
+ for (Index = 0; Index < EntryCount; Index ++) {
+ CopyMem (&EntryPtr, (VOID *)(BasePtr + Index * sizeof(UINT64)), sizeof(UINT64));
+ Table = (EFI_ACPI_DESCRIPTION_HEADER *)((UINTN)(EntryPtr));
+ if (Table->Signature == Signature) {
+ return Table;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ To find Facs in FADT.
+
+ @param Fadt FADT table pointer
+
+ @return Facs table pointer.
+**/
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
+FindAcpiFacsFromFadt (
+ IN EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt
+ )
+{
+ EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ UINT64 Data64;
+
+ if (Fadt == NULL) {
+ return NULL;
+ }
+
+ if (Fadt->Header.Revision < EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_REVISION) {
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
+ } else {
+ if (Fadt->FirmwareCtrl != 0) {
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Fadt->FirmwareCtrl;
+ } else {
+ CopyMem (&Data64, &Fadt->XFirmwareCtrl, sizeof(UINT64));
+ Facs = (EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *)(UINTN)Data64;
+ }
+ }
+ return Facs;
+}
+
+/**
+ To find Facs in Acpi tables.
+
+ To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
+ in the table.
+
+ @param AcpiTableGuid The guid used to find ACPI table in UEFI ConfigurationTable.
+
+ @return Facs table pointer.
+**/
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
+FindAcpiFacsTableByAcpiGuid (
+ IN EFI_GUID *AcpiTableGuid
+ )
+{
+ EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp;
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt;
+ EFI_ACPI_DESCRIPTION_HEADER *Xsdt;
+ EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt;
+ EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+ UINTN Index;
+
+ Rsdp = NULL;
+ //
+ // found ACPI table RSD_PTR from system table
+ //
+ for (Index = 0; Index < gST->NumberOfTableEntries; Index++) {
+ if (CompareGuid (&(gST->ConfigurationTable[Index].VendorGuid), AcpiTableGuid)) {
+ //
+ // A match was found.
+ //
+ Rsdp = gST->ConfigurationTable[Index].VendorTable;
+ break;
+ }
+ }
+
+ if (Rsdp == NULL) {
+ return NULL;
+ }
+
+ //
+ // Search XSDT
+ //
+ if (Rsdp->Revision >= EFI_ACPI_2_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION) {
+ Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->XsdtAddress;
+ Fadt = ScanTableInXSDT (Xsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ if (Fadt != NULL) {
+ Facs = FindAcpiFacsFromFadt (Fadt);
+ if (Facs != NULL) {
+ return Facs;
+ }
+ }
+ }
+
+ //
+ // Search RSDT
+ //
+ Rsdt = (EFI_ACPI_DESCRIPTION_HEADER *)(UINTN) Rsdp->RsdtAddress;
+ Fadt = ScanTableInRSDT (Rsdt, EFI_ACPI_2_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE);
+ if (Fadt != NULL) {
+ Facs = FindAcpiFacsFromFadt (Fadt);
+ if (Facs != NULL) {
+ return Facs;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+ To find Facs in Acpi tables.
+
+ To find Firmware ACPI control strutcure in Acpi Tables since the S3 waking vector is stored
+ in the table.
+
+ @return Facs table pointer.
+**/
+EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *
+FindAcpiFacsTable (
+ VOID
+ )
+{
+ EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+
+ Facs = FindAcpiFacsTableByAcpiGuid (&gEfiAcpi20TableGuid);
+ if (Facs != NULL) {
+ return Facs;
+ }
+
+ return FindAcpiFacsTableByAcpiGuid (&gEfiAcpi10TableGuid);
+}
+
+/**
+ The function will check if long mode waking vector is supported.
+
+ @param[in] Facs Pointer to FACS table.
+
+ @retval TRUE Long mode waking vector is supported.
+ @retval FALSE Long mode waking vector is not supported.
+
+**/
+BOOLEAN
+IsLongModeWakingVectorSupport (
+ IN EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs
+ )
+{
+ if ((Facs == NULL) ||
+ (Facs->Signature != EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ) {
+ //
+ // Something wrong with FACS.
+ //
+ return FALSE;
+ }
+ if (Facs->XFirmwareWakingVector != 0) {
+ if ((Facs->Version == EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_VERSION) &&
+ ((Facs->Flags & EFI_ACPI_4_0_64BIT_WAKE_SUPPORTED_F) != 0)) {
+ //
+ // BIOS supports 64bit waking vector.
+ //
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ return TRUE;
+ }
+ }
+ }
+ return FALSE;
+}
+
+/**
+ Allocates page table buffer.
+
+ @param[in] LongModeWakingVectorSupport Support long mode waking vector or not.
+
+ If BootScriptExector driver will run in 64-bit mode, this function will establish the 1:1
+ virtual to physical mapping page table when long mode waking vector is supported, otherwise
+ create 4G page table when long mode waking vector is not supported and let PF handler to
+ handle > 4G request.
+ If BootScriptExector driver will not run in 64-bit mode, this function will do nothing.
+
+ @return Page table base address.
+
+**/
+EFI_PHYSICAL_ADDRESS
+S3AllocatePageTablesBuffer (
+ IN BOOLEAN LongModeWakingVectorSupport
+ )
+{
+ if (FeaturePcdGet (PcdDxeIplSwitchToLongMode)) {
+ UINTN ExtraPageTablePages;
+ UINT32 RegEax;
+ UINT32 RegEdx;
+ UINT8 PhysicalAddressBits;
+ UINT32 NumberOfPml4EntriesNeeded;
+ UINT32 NumberOfPdpEntriesNeeded;
+ EFI_PHYSICAL_ADDRESS S3NvsPageTableAddress;
+ UINTN TotalPageTableSize;
+ VOID *Hob;
+ BOOLEAN Page1GSupport;
+
+ Page1GSupport = FALSE;
+ if (PcdGetBool(PcdUse1GPageTable)) {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000001) {
+ AsmCpuid (0x80000001, NULL, NULL, NULL, &RegEdx);
+ if ((RegEdx & BIT26) != 0) {
+ Page1GSupport = TRUE;
+ }
+ }
+ }
+
+ //
+ // Get physical address bits supported.
+ //
+ Hob = GetFirstHob (EFI_HOB_TYPE_CPU);
+ if (Hob != NULL) {
+ PhysicalAddressBits = ((EFI_HOB_CPU *) Hob)->SizeOfMemorySpace;
+ } else {
+ AsmCpuid (0x80000000, &RegEax, NULL, NULL, NULL);
+ if (RegEax >= 0x80000008) {
+ AsmCpuid (0x80000008, &RegEax, NULL, NULL, NULL);
+ PhysicalAddressBits = (UINT8) RegEax;
+ } else {
+ PhysicalAddressBits = 36;
+ }
+ }
+
+ //
+ // IA-32e paging translates 48-bit linear addresses to 52-bit physical addresses.
+ //
+ ASSERT (PhysicalAddressBits <= 52);
+ if (PhysicalAddressBits > 48) {
+ PhysicalAddressBits = 48;
+ }
+
+ ExtraPageTablePages = 0;
+ if (!LongModeWakingVectorSupport) {
+ //
+ // Create 4G page table when BIOS does not support long mode waking vector,
+ // and let PF handler to handle > 4G request.
+ //
+ PhysicalAddressBits = 32;
+ ExtraPageTablePages = EXTRA_PAGE_TABLE_PAGES;
+ }
+
+ //
+ // Calculate the table entries needed.
+ //
+ if (PhysicalAddressBits <= 39 ) {
+ NumberOfPml4EntriesNeeded = 1;
+ NumberOfPdpEntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 30));
+ } else {
+ NumberOfPml4EntriesNeeded = (UINT32)LShiftU64 (1, (PhysicalAddressBits - 39));
+ NumberOfPdpEntriesNeeded = 512;
+ }
+
+ //
+ // We need calculate whole page size then allocate once, because S3 restore page table does not know each page in Nvs.
+ //
+ if (!Page1GSupport) {
+ TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded + NumberOfPml4EntriesNeeded * NumberOfPdpEntriesNeeded);
+ } else {
+ TotalPageTableSize = (UINTN)(1 + NumberOfPml4EntriesNeeded);
+ }
+
+ TotalPageTableSize += ExtraPageTablePages;
+ DEBUG ((EFI_D_ERROR, "AcpiS3Save TotalPageTableSize - 0x%x pages\n", TotalPageTableSize));
+
+ //
+ // By architecture only one PageMapLevel4 exists - so lets allocate storage for it.
+ //
+ S3NvsPageTableAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGES_TO_SIZE(TotalPageTableSize));
+ ASSERT (S3NvsPageTableAddress != 0);
+ return S3NvsPageTableAddress;
+ } else {
+ //
+ // If DXE is running 32-bit mode, no need to establish page table.
+ //
+ return (EFI_PHYSICAL_ADDRESS) 0;
+ }
+}
+
+/**
+ Gets the buffer of legacy memory below 1 MB
+ This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
+
+ @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
+ @param Size The returned size of legacy memory below 1 MB.
+
+ @retval EFI_SUCCESS Size is successfully returned.
+ @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyGetS3MemorySize (
+ IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
+ OUT UINTN *Size
+ )
+{
+ if (Size == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Size = mLegacyRegionSize;
+ return EFI_SUCCESS;
+}
+
+/**
+ Prepares all information that is needed in the S3 resume boot path.
+
+ Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
+
+ @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
+ @param LegacyMemoryAddress The base address of legacy memory.
+
+ @retval EFI_NOT_FOUND Some necessary information cannot be found.
+ @retval EFI_SUCCESS All information was saved successfully.
+ @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information.
+ @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
+
+**/
+EFI_STATUS
+EFIAPI
+S3Ready (
+ IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
+ IN VOID *LegacyMemoryAddress
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AcpiS3ContextBuffer;
+ ACPI_S3_CONTEXT *AcpiS3Context;
+ STATIC BOOLEAN AlreadyEntered;
+ IA32_DESCRIPTOR *Idtr;
+ IA32_IDT_GATE_DESCRIPTOR *IdtGate;
+ EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs;
+
+ DEBUG ((EFI_D_INFO, "S3Ready!\n"));
+
+ //
+ // Platform may invoke AcpiS3Save->S3Save() before ExitPmAuth, because we need save S3 information there, while BDS ReadyToBoot may invoke it again.
+ // So if 2nd S3Save() is triggered later, we need ignore it.
+ //
+ if (AlreadyEntered) {
+ return EFI_SUCCESS;
+ }
+ AlreadyEntered = TRUE;
+
+ AcpiS3Context = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(*AcpiS3Context));
+ ASSERT (AcpiS3Context != NULL);
+ AcpiS3ContextBuffer = (EFI_PHYSICAL_ADDRESS)(UINTN)AcpiS3Context;
+
+ //
+ // Get ACPI Table because we will save its position to variable
+ //
+ Facs = (EFI_ACPI_4_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) FindAcpiFacsTable ();
+ AcpiS3Context->AcpiFacsTable = (EFI_PHYSICAL_ADDRESS) (UINTN) Facs;
+ ASSERT (AcpiS3Context->AcpiFacsTable != 0);
+
+ IdtGate = AllocateMemoryBelow4G (EfiReservedMemoryType, sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 + sizeof(IA32_DESCRIPTOR));
+ Idtr = (IA32_DESCRIPTOR *)(IdtGate + 0x100);
+ Idtr->Base = (UINTN)IdtGate;
+ Idtr->Limit = (UINT16)(sizeof(IA32_IDT_GATE_DESCRIPTOR) * 0x100 - 1);
+ AcpiS3Context->IdtrProfile = (EFI_PHYSICAL_ADDRESS)(UINTN)Idtr;
+
+ Status = SaveLockBox (
+ &mAcpiS3IdtrProfileGuid,
+ (VOID *)(UINTN)Idtr,
+ (UINTN)sizeof(IA32_DESCRIPTOR)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&mAcpiS3IdtrProfileGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Allocate page table
+ //
+ AcpiS3Context->S3NvsPageTableAddress = S3AllocatePageTablesBuffer (IsLongModeWakingVectorSupport (Facs));
+
+ //
+ // Allocate stack
+ //
+ AcpiS3Context->BootScriptStackSize = PcdGet32 (PcdS3BootScriptStackSize);
+ AcpiS3Context->BootScriptStackBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3BootScriptStackSize));
+ ASSERT (AcpiS3Context->BootScriptStackBase != 0);
+
+ //
+ // Allocate a code buffer < 4G for S3 debug to load external code, set invalid code instructions in it.
+ //
+ AcpiS3Context->S3DebugBufferAddress = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, EFI_PAGE_SIZE);
+ SetMem ((VOID *)(UINTN)AcpiS3Context->S3DebugBufferAddress, EFI_PAGE_SIZE, 0xff);
+
+ DEBUG((EFI_D_INFO, "AcpiS3Context: AcpiFacsTable is 0x%8x\n", AcpiS3Context->AcpiFacsTable));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: IdtrProfile is 0x%8x\n", AcpiS3Context->IdtrProfile));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: S3NvsPageTableAddress is 0x%8x\n", AcpiS3Context->S3NvsPageTableAddress));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: S3DebugBufferAddress is 0x%8x\n", AcpiS3Context->S3DebugBufferAddress));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackBase is 0x%8x\n", AcpiS3Context->BootScriptStackBase));
+ DEBUG((EFI_D_INFO, "AcpiS3Context: BootScriptStackSize is 0x%8x\n", AcpiS3Context->BootScriptStackSize));
+
+ Status = SaveLockBox (
+ &gEfiAcpiVariableGuid,
+ &AcpiS3ContextBuffer,
+ sizeof(AcpiS3ContextBuffer)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SaveLockBox (
+ &gEfiAcpiS3ContextGuid,
+ (VOID *)(UINTN)AcpiS3Context,
+ (UINTN)sizeof(*AcpiS3Context)
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = SetLockBoxAttributes (&gEfiAcpiS3ContextGuid, LOCK_BOX_ATTRIBUTE_RESTORE_IN_PLACE);
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
+ S3ReadyThunkPlatform (AcpiS3Context);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The Driver Entry Point.
+
+ The function is the driver Entry point which will produce AcpiS3SaveProtocol.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS: Driver initialized successfully
+ @retval EFI_LOAD_ERROR: Failed to Initialize or has been loaded
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiS3Save (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (!FeaturePcdGet(PcdPlatformCsmSupport)) {
+ //
+ // More memory for no CSM tip, because GDT need relocation
+ //
+ mLegacyRegionSize = 0x250;
+ } else {
+ mLegacyRegionSize = 0x100;
+ }
+
+ if (FeaturePcdGet(PcdFrameworkCompatibilitySupport)) {
+ InstallAcpiS3SaveThunk ();
+ }
+
+ Status = gBS->InstallProtocolInterface (
+ &ImageHandle,
+ &gEfiAcpiS3SaveProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mS3Save
+ );
+ ASSERT_EFI_ERROR (Status);
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h
new file mode 100644
index 0000000000..65974a3402
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3Save.h
@@ -0,0 +1,59 @@
+/** @file
+ This is an implementation of the ACPI S3 Save protocol. This is defined in
+ S3 boot path specification 0.9.
+
+Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ACPI_S3_SAVE_H_
+#define _ACPI_S3_SAVE_H_
+
+/**
+ Gets the buffer of legacy memory below 1 MB
+ This function is to get the buffer in legacy memory below 1MB that is required during S3 resume.
+
+ @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
+ @param Size The returned size of legacy memory below 1 MB.
+
+ @retval EFI_SUCCESS Size is successfully returned.
+ @retval EFI_INVALID_PARAMETER The pointer Size is NULL.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyGetS3MemorySize (
+ IN EFI_ACPI_S3_SAVE_PROTOCOL * This,
+ OUT UINTN * Size
+ );
+
+/**
+ Prepares all information that is needed in the S3 resume boot path.
+
+ Allocate the resources or prepare informations and save in ACPI variable set for S3 resume boot path
+
+ @param This A pointer to the EFI_ACPI_S3_SAVE_PROTOCOL instance.
+ @param LegacyMemoryAddress The base address of legacy memory.
+
+ @retval EFI_NOT_FOUND Some necessary information cannot be found.
+ @retval EFI_SUCCESS All information was saved successfully.
+ @retval EFI_OUT_OF_RESOURCES Resources were insufficient to save all the information.
+ @retval EFI_INVALID_PARAMETER The memory range is not located below 1 MB.
+
+**/
+EFI_STATUS
+EFIAPI
+S3Ready (
+ IN EFI_ACPI_S3_SAVE_PROTOCOL *This,
+ IN VOID *LegacyMemoryAddress
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
new file mode 100644
index 0000000000..366eb147b7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.inf
@@ -0,0 +1,89 @@
+## @file
+# AcpiS3Save module installs ACPI S3 Save protocol to prepare S3 boot data.
+#
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are
+# licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AcpiS3SaveDxe
+ MODULE_UNI_FILE = AcpiS3SaveDxe.uni
+ FILE_GUID = 2BDED685-F733-455f-A840-43A22B791FB3
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InstallAcpiS3Save
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ AcpiS3Save.h
+ AcpiS3Save.c
+ AcpiVariableThunkPlatform.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ PcdLib
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ HobLib
+ UefiLib
+ LockBoxLib
+ DebugLib
+ DxeServicesLib
+
+[Guids]
+ gEfiAcpiVariableGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiAcpiS3ContextGuid ## PRODUCES ## UNDEFINED # LockBox Save Data.
+ gEfiAcpi20TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ gEfiAcpi10TableGuid ## SOMETIMES_CONSUMES ## SystemTable
+ ## SOMETIMES_CONSUMES ## Variable:L"AcpiGlobalVariable"
+ ## SOMETIMES_PRODUCES ## Variable:L"AcpiGlobalVariable"
+ gEfiAcpiVariableCompatiblityGuid
+
+[Protocols]
+ gEfiAcpiS3SaveProtocolGuid ## PRODUCES
+ gFrameworkEfiMpServiceProtocolGuid ## SOMETIMES_CONSUMES
+ ## NOTIFY
+ ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdPlatformCsmSupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFrameworkCompatibilitySupport ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdDxeIplSwitchToLongMode ## CONSUMES
+
+[Pcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3AcpiReservedMemorySize ## SOMETIMES_CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdS3BootScriptStackSize ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdUse1GPageTable ## CONSUMES
+
+[Depex]
+ #
+ # Note: the extra dependency of gEfiMpServiceProtocolGuid is to ensure that ACPI variable is set by MpDxe driver before
+ # AcpiS3SaveDxe module is executed.
+ #
+ gEfiVariableArchProtocolGuid AND gEfiVariableWriteArchProtocolGuid AND gEfiMpServiceProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiS3SaveDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.uni b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.uni
new file mode 100644
index 0000000000..05f1398985
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxeExtra.uni
new file mode 100644
index 0000000000..7b89727292
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiS3SaveDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c
new file mode 100644
index 0000000000..7ad9eb4336
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiS3SaveDxe/AcpiVariableThunkPlatform.c
@@ -0,0 +1,224 @@
+/** @file
+ This is an implementation of the AcpiVariable platform field for ECP platform.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+==
+
+typedef struct {
+ EFI_PHYSICAL_ADDRESS AcpiReservedMemoryBase; <<===
+ UINT32 AcpiReservedMemorySize; <<===
+ EFI_PHYSICAL_ADDRESS S3ReservedLowMemoryBase;
+ EFI_PHYSICAL_ADDRESS AcpiBootScriptTable;
+ EFI_PHYSICAL_ADDRESS RuntimeScriptTableBase;
+ EFI_PHYSICAL_ADDRESS AcpiFacsTable;
+ UINT64 SystemMemoryLength; <<===
+ ACPI_CPU_DATA_COMPATIBILITY AcpiCpuData;
+ EFI_PHYSICAL_ADDRESS VideoOpromAddress;
+ UINT32 VideoOpromSize;
+ EFI_PHYSICAL_ADDRESS S3DebugBufferAddress;
+ EFI_PHYSICAL_ADDRESS S3ResumeNvsEntryPoint;
+} ACPI_VARIABLE_SET_COMPATIBILITY;
+
+**/
+
+#include <FrameworkDxe.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/FrameworkMpService.h>
+#include <Protocol/VariableLock.h>
+#include <Guid/AcpiVariableCompatibility.h>
+#include <Guid/AcpiS3Context.h>
+
+GLOBAL_REMOVE_IF_UNREFERENCED
+ACPI_VARIABLE_SET_COMPATIBILITY *mAcpiVariableSetCompatibility = NULL;
+
+/**
+ Allocate memory below 4G memory address.
+
+ This function allocates memory below 4G memory address.
+
+ @param MemoryType Memory type of memory to allocate.
+ @param Size Size of memory to allocate.
+
+ @return Allocated address for output.
+
+**/
+VOID*
+AllocateMemoryBelow4G (
+ IN EFI_MEMORY_TYPE MemoryType,
+ IN UINTN Size
+ );
+
+/**
+ Hook point for AcpiVariableThunkPlatform for S3Ready.
+
+ @param AcpiS3Context ACPI s3 context
+**/
+VOID
+S3ReadyThunkPlatform (
+ IN ACPI_S3_CONTEXT *AcpiS3Context
+ )
+{
+ EFI_PHYSICAL_ADDRESS AcpiMemoryBase;
+ UINT32 AcpiMemorySize;
+ EFI_PEI_HOB_POINTERS Hob;
+ UINT64 MemoryLength;
+
+ DEBUG ((EFI_D_INFO, "S3ReadyThunkPlatform\n"));
+
+ if (mAcpiVariableSetCompatibility == NULL) {
+ return;
+ }
+
+ //
+ // Allocate ACPI reserved memory under 4G
+ //
+ AcpiMemoryBase = (EFI_PHYSICAL_ADDRESS)(UINTN)AllocateMemoryBelow4G (EfiReservedMemoryType, PcdGet32 (PcdS3AcpiReservedMemorySize));
+ ASSERT (AcpiMemoryBase != 0);
+ AcpiMemorySize = PcdGet32 (PcdS3AcpiReservedMemorySize);
+
+ //
+ // Calculate the system memory length by memory hobs
+ //
+ MemoryLength = 0x100000;
+ Hob.Raw = GetFirstHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR);
+ ASSERT (Hob.Raw != NULL);
+ while ((Hob.Raw != NULL) && (!END_OF_HOB_LIST (Hob))) {
+ if (Hob.ResourceDescriptor->ResourceType == EFI_RESOURCE_SYSTEM_MEMORY) {
+ //
+ // Skip the memory region below 1MB
+ //
+ if (Hob.ResourceDescriptor->PhysicalStart >= 0x100000) {
+ MemoryLength += Hob.ResourceDescriptor->ResourceLength;
+ }
+ }
+ Hob.Raw = GET_NEXT_HOB (Hob);
+ Hob.Raw = GetNextHob (EFI_HOB_TYPE_RESOURCE_DESCRIPTOR, Hob.Raw);
+ }
+
+ mAcpiVariableSetCompatibility->AcpiReservedMemoryBase = AcpiMemoryBase;
+ mAcpiVariableSetCompatibility->AcpiReservedMemorySize = AcpiMemorySize;
+ mAcpiVariableSetCompatibility->SystemMemoryLength = MemoryLength;
+
+ DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemoryBase is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemoryBase));
+ DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: AcpiMemorySize is 0x%8x\n", mAcpiVariableSetCompatibility->AcpiReservedMemorySize));
+ DEBUG((EFI_D_INFO, "AcpiVariableThunkPlatform: SystemMemoryLength is 0x%8x\n", mAcpiVariableSetCompatibility->SystemMemoryLength));
+
+ return ;
+}
+
+/**
+ Register callback function upon VariableLockProtocol
+ to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
+
+ @param[in] Event Event whose notification function is being invoked.
+ @param[in] Context Pointer to the notification function's context.
+**/
+VOID
+EFIAPI
+VariableLockAcpiGlobalVariable (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+ //
+ // Mark ACPI_GLOBAL_VARIABLE variable to read-only if the Variable Lock protocol exists
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLock->RequestToLock (VariableLock, ACPI_GLOBAL_VARIABLE, &gEfiAcpiVariableCompatiblityGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ Hook point for AcpiVariableThunkPlatform for InstallAcpiS3Save.
+**/
+VOID
+InstallAcpiS3SaveThunk (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ FRAMEWORK_EFI_MP_SERVICES_PROTOCOL *FrameworkMpService;
+ UINTN VarSize;
+ VOID *Registration;
+
+ Status = gBS->LocateProtocol (
+ &gFrameworkEfiMpServiceProtocolGuid,
+ NULL,
+ (VOID**) &FrameworkMpService
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // On ECP platform, if framework CPU drivers are in use, The compatible version of ACPI variable set
+ // should be produced by CPU driver.
+ //
+ VarSize = sizeof (mAcpiVariableSetCompatibility);
+ Status = gRT->GetVariable (
+ ACPI_GLOBAL_VARIABLE,
+ &gEfiAcpiVariableCompatiblityGuid,
+ NULL,
+ &VarSize,
+ &mAcpiVariableSetCompatibility
+ );
+ if (EFI_ERROR (Status) || (VarSize != sizeof (mAcpiVariableSetCompatibility))) {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility was not saved by CPU driver correctly. OS S3 may fail!\n"));
+ mAcpiVariableSetCompatibility = NULL;
+ }
+ } else {
+ //
+ // Allocate/initialize the compatible version of Acpi Variable Set since Framework chipset/platform
+ // driver need this variable. ACPI_GLOBAL_VARIABLE variable is not used in runtime phase,
+ // so RT attribute is not needed for it.
+ //
+ mAcpiVariableSetCompatibility = AllocateMemoryBelow4G (EfiACPIMemoryNVS, sizeof(ACPI_VARIABLE_SET_COMPATIBILITY));
+ Status = gRT->SetVariable (
+ ACPI_GLOBAL_VARIABLE,
+ &gEfiAcpiVariableCompatiblityGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof(mAcpiVariableSetCompatibility),
+ &mAcpiVariableSetCompatibility
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Register callback function upon VariableLockProtocol
+ // to lock ACPI_GLOBAL_VARIABLE variable to avoid malicious code to update it.
+ //
+ EfiCreateProtocolNotifyEvent (
+ &gEdkiiVariableLockProtocolGuid,
+ TPL_CALLBACK,
+ VariableLockAcpiGlobalVariable,
+ NULL,
+ &Registration
+ );
+ } else {
+ DEBUG ((EFI_D_ERROR, "FATAL ERROR: AcpiVariableSetCompatibility cannot be saved: %r. OS S3 may fail!\n", Status));
+ gBS->FreePages (
+ (EFI_PHYSICAL_ADDRESS) (UINTN) mAcpiVariableSetCompatibility,
+ EFI_SIZE_TO_PAGES (sizeof (ACPI_VARIABLE_SET_COMPATIBILITY))
+ );
+ mAcpiVariableSetCompatibility = NULL;
+ }
+ }
+
+ DEBUG((EFI_D_INFO, "AcpiVariableSetCompatibility is 0x%8x\n", mAcpiVariableSetCompatibility));
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.c b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.c
new file mode 100644
index 0000000000..a8b1f06117
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.c
@@ -0,0 +1,91 @@
+/** @file
+ This is an implementation of the ACPI Support protocol. This is defined in
+ the Tiano ACPI External Product Specification, revision 0.3.6.
+
+Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Includes
+//
+#include "AcpiSupport.h"
+
+//
+// Handle to install ACPI Table Protocol (and ACPI Suppport protocol).
+//
+EFI_HANDLE mHandle = NULL;
+
+/**
+ Entry point of the ACPI support driver. This function creates and initializes an instance of the ACPI Support
+ Protocol and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_LOAD_ERROR Failed to Initialize or has been loaded
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiSupport (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+
+{
+ EFI_STATUS Status;
+ EFI_ACPI_SUPPORT_INSTANCE *PrivateData;
+
+ //
+ // Initialize our protocol
+ //
+ PrivateData = AllocateZeroPool (sizeof (EFI_ACPI_SUPPORT_INSTANCE));
+ ASSERT (PrivateData);
+ PrivateData->Signature = EFI_ACPI_SUPPORT_SIGNATURE;
+
+ //
+ // Call all constructors per produced protocols
+ //
+ Status = AcpiSupportAcpiSupportConstructor (PrivateData);
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (PrivateData);
+ return EFI_LOAD_ERROR;
+ }
+
+ //
+ // Install ACPI Table protocol and optional ACPI support protocol based on
+ // feature flag: PcdInstallAcpiSupportProtocol.
+ //
+ if (FeaturePcdGet (PcdInstallAcpiSupportProtocol)) {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ &gEfiAcpiSupportProtocolGuid,
+ &PrivateData->AcpiSupport,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiAcpiTableProtocolGuid,
+ &PrivateData->AcpiTableProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.h b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.h
new file mode 100644
index 0000000000..1bcf1e6ee5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupport.h
@@ -0,0 +1,166 @@
+/** @file
+ This is an implementation of the ACPI Support protocol.
+ It is in compliance with the 0.9 definition of the protocol.
+
+Copyright (c) 2006 - 2013, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _ACPI_SUPPORT_H_
+#define _ACPI_SUPPORT_H_
+
+
+#include <PiDxe.h>
+
+#include <Protocol/AcpiTable.h>
+#include <Guid/Acpi.h>
+#include <Protocol/AcpiSupport.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/PcdLib.h>
+
+//
+// Statements that include other files
+//
+#include <IndustryStandard/Acpi.h>
+
+
+//
+// Private Driver Data
+//
+//
+// ACPI Table Linked List Signature.
+//
+#define EFI_ACPI_TABLE_LIST_SIGNATURE SIGNATURE_32 ('E', 'A', 'T', 'L')
+
+//
+// ACPI Table Linked List Entry definition.
+//
+// Signature must be set to EFI_ACPI_TABLE_LIST_SIGNATURE
+// Link is the linked list data.
+// Version is the versions of the ACPI tables that this table belongs in.
+// Table is a pointer to the table.
+// PageAddress is the address of the pages allocated for the table.
+// NumberOfPages is the number of pages allocated at PageAddress.
+// Handle is used to identify a particular table.
+//
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ EFI_ACPI_TABLE_VERSION Version;
+ EFI_ACPI_COMMON_HEADER *Table;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ UINTN NumberOfPages;
+ UINTN Handle;
+} EFI_ACPI_TABLE_LIST;
+
+//
+// Containment record for linked list.
+//
+#define EFI_ACPI_TABLE_LIST_FROM_LINK(_link) CR (_link, EFI_ACPI_TABLE_LIST, Link, EFI_ACPI_TABLE_LIST_SIGNATURE)
+
+//
+// The maximum number of tables this driver supports
+//
+#define EFI_ACPI_MAX_NUM_TABLES 20
+
+//
+// Protocol private structure definition
+//
+//
+// ACPI support protocol instance signature definition.
+//
+#define EFI_ACPI_SUPPORT_SIGNATURE SIGNATURE_32 ('S', 'S', 'A', 'E')
+
+//
+// ACPI support protocol instance data structure
+//
+typedef struct {
+ UINTN Signature;
+ EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp1; // Pointer to RSD_PTR structure
+ EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *Rsdp3; // Pointer to RSD_PTR structure
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt1; // Pointer to RSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Rsdt3; // Pointer to RSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Xsdt; // Pointer to XSDT table header
+ EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt1; // Pointer to FADT table header
+ EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *Fadt3; // Pointer to FADT table header
+ EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs1; // Pointer to FACS table header
+ EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *Facs3; // Pointer to FACS table header
+ EFI_ACPI_DESCRIPTION_HEADER *Dsdt1; // Pointer to DSDT table header
+ EFI_ACPI_DESCRIPTION_HEADER *Dsdt3; // Pointer to DSDT table header
+ LIST_ENTRY TableList;
+ UINTN NumberOfTableEntries1; // Number of ACPI 1.0 tables
+ UINTN NumberOfTableEntries3; // Number of ACPI 3.0 tables
+ UINTN CurrentHandle;
+ BOOLEAN TablesInstalled1; // ACPI 1.0 tables published
+ BOOLEAN TablesInstalled3; // ACPI 3.0 tables published
+ EFI_ACPI_SUPPORT_PROTOCOL AcpiSupport;
+ EFI_ACPI_TABLE_PROTOCOL AcpiTableProtocol;
+} EFI_ACPI_SUPPORT_INSTANCE;
+
+//
+// ACPI support protocol instance containing record macro
+//
+#define EFI_ACPI_SUPPORT_INSTANCE_FROM_ACPI_SUPPORT_THIS(a) \
+ CR (a, \
+ EFI_ACPI_SUPPORT_INSTANCE, \
+ AcpiSupport, \
+ EFI_ACPI_SUPPORT_SIGNATURE \
+ )
+//
+// ACPI table protocol instance containing record macro
+//
+#define EFI_ACPI_TABLE_INSTANCE_FROM_ACPI_SUPPORT_THIS(a) \
+ CR (a, \
+ EFI_ACPI_SUPPORT_INSTANCE, \
+ AcpiTableProtocol, \
+ EFI_ACPI_SUPPORT_SIGNATURE \
+ )
+
+/**
+ Constructor for the ACPI support protocol.
+
+ Constructor for the ACPI support protocol to initializes instance data.
+
+ @param AcpiSupportInstance Instance to construct
+
+ @retval EFI_SUCCESS Instance initialized.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+**/
+EFI_STATUS
+AcpiSupportAcpiSupportConstructor (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance
+ );
+/**
+ Entry point of the ACPI support driver. This function creates and initializes an instance of the ACPI Support
+ Protocol and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_LOAD_ERROR Failed to Initialize or has been loaded
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiSupport (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportAcpiSupportProtocol.c b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportAcpiSupportProtocol.c
new file mode 100644
index 0000000000..6443c3acd0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportAcpiSupportProtocol.c
@@ -0,0 +1,1918 @@
+/** @file
+ ACPI Support Protocol implementation
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+This program and the accompanying materials
+are licensed and made available under the terms and conditions
+of the BSD License which accompanies this distribution. The
+full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+//
+// Includes
+//
+#include "AcpiSupport.h"
+//
+// The maximum number of tables that pre-allocated.
+//
+UINTN mEfiAcpiMaxNumTables = EFI_ACPI_MAX_NUM_TABLES;
+/**
+ This function adds an ACPI table to the table list. It will detect FACS and
+ allocate the correct type of memory and properly align the table.
+
+ @param AcpiSupportInstance Instance of the protocol.
+ @param Table Table to add.
+ @param Checksum Does the table require checksumming.
+ @param Version The version of the list to add the table to.
+ @param Handle Pointer for returning the handle.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+ @return EFI_ABORTED The table is a duplicate of a table that is required
+ to be unique.
+**/
+EFI_STATUS
+AddTableToList (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance,
+ IN VOID *Table,
+ IN BOOLEAN Checksum,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ OUT UINTN *Handle
+ );
+/**
+ This function finds and removes the table specified by the handle.
+
+ @param AcpiSupportInstance Instance of the protocol.
+ @param Version Bitmask of which versions to remove.
+ @param Handle Table to remove.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED An error occurred.
+ @return EFI_NOT_FOUND Handle not found in table list.
+**/
+EFI_STATUS
+RemoveTableFromList (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ );
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+ @param ChecksumOffset Offset to place the checksum result in
+
+ @return EFI_SUCCESS The function completed successfully.
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ );
+/**
+ Checksum all versions of the common tables, RSDP, RSDT, XSDT.
+
+ @param AcpiSupportInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance
+ );
+
+/**
+ This function returns a table specified by an index if it exists.
+
+ The function returns a buffer containing the table that the caller must free.
+ The function also returns a handle used to identify the table for update or
+ deletion using the SetAcpiTable function.
+
+ @param This Instance of the protocol.
+ @param Index Zero-based index of the table to retrieve.
+ @param Table Returned pointer to the table.
+ @param Version Versions that the table is currently used in.
+ @param Handle Handle of the table, used in updating tables.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND The requested table does not exist.
+
+**/
+EFI_STATUS
+EFIAPI
+GetAcpiTable (
+ IN EFI_ACPI_SUPPORT_PROTOCOL *This,
+ IN INTN Index,
+ OUT VOID **Table,
+ OUT EFI_ACPI_TABLE_VERSION *Version,
+ OUT UINTN *Handle
+ )
+
+{
+ EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance;
+ INTN TempIndex;
+ LIST_ENTRY *CurrentLink;
+ LIST_ENTRY *StartLink;
+ EFI_ACPI_TABLE_LIST *CurrentTable;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (This);
+ ASSERT (Table);
+ ASSERT (Handle);
+
+ //
+ // Get the instance of the protocol
+ //
+ AcpiSupportInstance = EFI_ACPI_SUPPORT_INSTANCE_FROM_ACPI_SUPPORT_THIS (This);
+
+ //
+ // Find the table
+ //
+ CurrentLink = AcpiSupportInstance->TableList.ForwardLink;
+ StartLink = &AcpiSupportInstance->TableList;
+ for (TempIndex = 0; (TempIndex < Index) && (CurrentLink != StartLink) && (CurrentLink != NULL); TempIndex++) {
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+
+ if (TempIndex != Index || CurrentLink == StartLink) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Get handle and version
+ //
+ CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ *Handle = CurrentTable->Handle;
+ *Version = CurrentTable->Version;
+
+ //
+ // Copy the table
+ //
+ *Table = AllocateCopyPool (CurrentTable->Table->Length, CurrentTable->Table);
+ ASSERT (*Table);
+
+ return EFI_SUCCESS;
+}
+/**
+ This function adds, removes, or updates ACPI tables. If the address is not
+ null and the handle value is null, the table is added. If both the address and
+ handle are not null, the table at handle is updated with the table at address.
+ If the address is null and the handle is not, the table at handle is deleted.
+
+ @param This Pointer of the protocol.
+ @param Table Pointer to a table.
+ @param Checksum Boolean indicating if the checksum should be calculated.
+ @param Version Version(s) to set.
+ @param Handle Handle of the table.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_INVALID_PARAMETER Both the Table and *Handle were NULL.
+ @return EFI_ABORTED Could not complete the desired request.
+
+**/
+EFI_STATUS
+EFIAPI
+SetAcpiTable (
+ IN EFI_ACPI_SUPPORT_PROTOCOL *This,
+ IN VOID *Table OPTIONAL,
+ IN BOOLEAN Checksum,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN OUT UINTN *Handle
+ )
+{
+ EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance;
+ UINTN SavedHandle;
+ EFI_STATUS Status;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (This);
+ ASSERT (Handle != NULL);
+
+ //
+ // Get the instance of the protocol
+ //
+ AcpiSupportInstance = EFI_ACPI_SUPPORT_INSTANCE_FROM_ACPI_SUPPORT_THIS (This);
+
+ //
+ // Initialize locals
+ //
+ //
+ // Determine desired action
+ //
+ if (*Handle == 0) {
+ if (Table == NULL) {
+ //
+ // Invalid parameter combination
+ //
+ return EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // Add table
+ //
+ Status = AddTableToList (AcpiSupportInstance, Table, Checksum, Version, Handle);
+ }
+ } else {
+ if (Table != NULL) {
+ //
+ // Update table
+ //
+ //
+ // Delete the table list entry
+ //
+ Status = RemoveTableFromList (AcpiSupportInstance, Version, *Handle);
+ if (EFI_ERROR (Status)) {
+ //
+ // Should not get an error here ever, but abort if we do.
+ //
+ return EFI_ABORTED;
+ }
+ //
+ // Set the handle to replace the table at the same handle
+ //
+ SavedHandle = AcpiSupportInstance->CurrentHandle;
+ AcpiSupportInstance->CurrentHandle = *Handle;
+
+ //
+ // Add the table
+ //
+ Status = AddTableToList (AcpiSupportInstance, Table, Checksum, Version, Handle);
+
+ //
+ // Restore the saved current handle
+ //
+ AcpiSupportInstance->CurrentHandle = SavedHandle;
+ } else {
+ //
+ // Delete table
+ //
+ Status = RemoveTableFromList (AcpiSupportInstance, Version, *Handle);
+ }
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Should not get an error here ever, but abort if we do.
+ //
+ return EFI_ABORTED;
+ }
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+/**
+ This function publishes the specified versions of the ACPI tables by
+ installing EFI configuration table entries for them. Any combination of
+ table versions can be published.
+
+ @param This Pointer of the protocol.
+ @param Version Version(s) to publish.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED The function could not complete successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PublishTables (
+ IN EFI_ACPI_SUPPORT_PROTOCOL *This,
+ IN EFI_ACPI_TABLE_VERSION Version
+ )
+{
+ EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance;
+ EFI_STATUS Status;
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 Buffer64;
+
+ //
+ // Get the instance of the protocol
+ //
+ AcpiSupportInstance = EFI_ACPI_SUPPORT_INSTANCE_FROM_ACPI_SUPPORT_THIS (This);
+
+ //
+ // Reorder tables as some operating systems don't seem to find the
+ // FADT correctly if it is not in the first few entries
+ //
+
+ //
+ // Add FADT as the first entry
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) AcpiSupportInstance->Rsdt1 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiSupportInstance->Fadt1;
+ }
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 || (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) AcpiSupportInstance->Rsdt3 + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ *CurrentRsdtEntry = (UINT32) (UINTN) AcpiSupportInstance->Fadt3;
+ CurrentXsdtEntry = (VOID *) ((UINT8 *) AcpiSupportInstance->Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER));
+ //
+ // Add entry to XSDT, XSDT expects 64 bit pointers, but
+ // the table pointers in XSDT are not aligned on 8 byte boundary.
+ //
+ Buffer64 = (UINT64) (UINTN) AcpiSupportInstance->Fadt3;
+ CopyMem (
+ CurrentXsdtEntry,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ }
+
+ //
+ // Do checksum again because Dsdt/Xsdt is updated.
+ //
+ ChecksumCommonTables (AcpiSupportInstance);
+
+ //
+ // Add the RSD_PTR to the system table and store that we have installed the
+ // tables.
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && !AcpiSupportInstance->TablesInstalled1) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpi10TableGuid, AcpiSupportInstance->Rsdp1);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ AcpiSupportInstance->TablesInstalled1 = TRUE;
+ }
+
+ if (((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 || (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) &&
+ !AcpiSupportInstance->TablesInstalled3) {
+ Status = gBS->InstallConfigurationTable (&gEfiAcpiTableGuid, AcpiSupportInstance->Rsdp3);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+
+ AcpiSupportInstance->TablesInstalled3= TRUE;
+ }
+
+ return EFI_SUCCESS;
+}
+/**
+ Installs an ACPI table into the RSDT/XSDT.
+ Note that the ACPI table should be checksumed before installing it.
+ Otherwise it will assert.
+
+ @param This Protocol instance pointer.
+ @param AcpiTableBuffer A pointer to a buffer containing the ACPI table to be installed.
+ @param AcpiTableBufferSize Specifies the size, in bytes, of the AcpiTableBuffer buffer.
+ @param TableKey Reurns a key to refer to the ACPI table.
+
+ @return EFI_SUCCESS The table was successfully inserted.
+ @return EFI_INVALID_PARAMETER Either AcpiTableBuffer is NULL, TableKey is NULL, or AcpiTableBufferSize
+ and the size field embedded in the ACPI table pointed to by AcpiTableBuffer
+ are not in sync.
+ @return EFI_OUT_OF_RESOURCES Insufficient resources exist to complete the request.
+ @retval EFI_ACCESS_DENIED The table signature matches a table already
+ present in the system and platform policy
+ does not allow duplicate tables of this type.
+
+**/
+EFI_STATUS
+EFIAPI
+InstallAcpiTable (
+ IN EFI_ACPI_TABLE_PROTOCOL *This,
+ IN VOID *AcpiTableBuffer,
+ IN UINTN AcpiTableBufferSize,
+ OUT UINTN *TableKey
+ )
+{
+ EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance;
+ EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
+ EFI_STATUS Status;
+ VOID *AcpiTableBufferConst;
+
+ //
+ // Check for invalid input parameters
+ //
+ if ((AcpiTableBuffer == NULL) || (TableKey == NULL)
+ || (((EFI_ACPI_DESCRIPTION_HEADER *) AcpiTableBuffer)->Length != AcpiTableBufferSize)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the instance of the ACPI support protocol
+ //
+ AcpiSupportInstance = EFI_ACPI_TABLE_INSTANCE_FROM_ACPI_SUPPORT_THIS (This);
+ AcpiSupport = &AcpiSupportInstance->AcpiSupport;
+
+ //
+ // Install the ACPI table by using ACPI support protocol
+ //
+ AcpiTableBufferConst = AllocateCopyPool (AcpiTableBufferSize, AcpiTableBuffer);
+ *TableKey = 0;
+ Status = AddTableToList (
+ AcpiSupportInstance,
+ AcpiTableBufferConst,
+ TRUE,
+ EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AcpiSupport->PublishTables (
+ AcpiSupport,
+ EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0
+ );
+ }
+ FreePool (AcpiTableBufferConst);
+
+ return Status;
+}
+/**
+ Removes an ACPI table from the RSDT/XSDT.
+
+ @param This Protocol instance pointer.
+ @param TableKey Specifies the table to uninstall. The key was returned from InstallAcpiTable().
+
+ @return EFI_SUCCESS The table was successfully uninstalled.
+ @return EFI_NOT_FOUND TableKey does not refer to a valid key for a table entry.
+
+**/
+EFI_STATUS
+EFIAPI
+UninstallAcpiTable (
+ IN EFI_ACPI_TABLE_PROTOCOL *This,
+ IN UINTN TableKey
+ )
+{
+ EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance;
+ EFI_ACPI_SUPPORT_PROTOCOL *AcpiSupport;
+ EFI_STATUS Status;
+
+ //
+ // Get the instance of the ACPI support protocol
+ //
+ AcpiSupportInstance = EFI_ACPI_TABLE_INSTANCE_FROM_ACPI_SUPPORT_THIS (This);
+ AcpiSupport = &AcpiSupportInstance->AcpiSupport;
+
+ //
+ // Uninstall the ACPI table by using ACPI support protocol
+ //
+ Status = RemoveTableFromList (
+ AcpiSupportInstance,
+ EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0,
+ TableKey
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = AcpiSupport->PublishTables (
+ AcpiSupport,
+ EFI_ACPI_TABLE_VERSION_1_0B | EFI_ACPI_TABLE_VERSION_2_0 | EFI_ACPI_TABLE_VERSION_3_0
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ } else {
+ return EFI_SUCCESS;
+ }
+}
+/**
+ If the number of APCI tables exceeds the preallocated max table number, enlarge the table buffer.
+
+ @param AcpiSupportInstance ACPI support protocol instance data structure
+
+ @return EFI_SUCCESS reallocate the table beffer successfully.
+ @return EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+
+**/
+EFI_STATUS
+ReallocateAcpiTableBuffer (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance
+ )
+{
+ UINTN NewMaxTableNumber;
+ UINTN TotalSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+ EFI_ACPI_SUPPORT_INSTANCE TempPrivateData;
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+
+ CopyMem (&TempPrivateData, AcpiSupportInstance, sizeof (EFI_ACPI_SUPPORT_INSTANCE));
+ //
+ // Enlarge the max table number from mEfiAcpiMaxNumTables to mEfiAcpiMaxNumTables + EFI_ACPI_MAX_NUM_TABLES
+ //
+ NewMaxTableNumber = mEfiAcpiMaxNumTables + EFI_ACPI_MAX_NUM_TABLES;
+ //
+ // Create RSDT, XSDT structures and allocate buffers.
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ NewMaxTableNumber * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ NewMaxTableNumber * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ NewMaxTableNumber * sizeof (UINT64);
+
+ //
+ // Allocate memory in the lower 32 bit of address range for
+ // compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiSupportInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ AcpiSupportInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + NewMaxTableNumber * sizeof (UINT32));
+ AcpiSupportInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Update RSDP to point to the new Rsdt and Xsdt address.
+ //
+ AcpiSupportInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiSupportInstance->Rsdt1;
+ AcpiSupportInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiSupportInstance->Rsdt3;
+ CurrentData = (UINT64) (UINTN) AcpiSupportInstance->Xsdt;
+ CopyMem (&AcpiSupportInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+
+ //
+ // copy the original Rsdt1, Rsdt3 and Xsdt structure to new buffer
+ //
+ CopyMem (AcpiSupportInstance->Rsdt1, TempPrivateData.Rsdt1, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ CopyMem (AcpiSupportInstance->Rsdt3, TempPrivateData.Rsdt3, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT32)));
+ CopyMem (AcpiSupportInstance->Xsdt, TempPrivateData.Xsdt, (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + mEfiAcpiMaxNumTables * sizeof (UINT64)));
+
+ //
+ // Calculate orignal ACPI table buffer size
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)TempPrivateData.Rsdt1, EFI_SIZE_TO_PAGES (TotalSize));
+
+ //
+ // Update the Max ACPI table number
+ //
+ mEfiAcpiMaxNumTables = NewMaxTableNumber;
+ return EFI_SUCCESS;
+}
+/**
+ This function adds an ACPI table to the table list. It will detect FACS and
+ allocate the correct type of memory and properly align the table.
+
+ @param AcpiSupportInstance Instance of the protocol.
+ @param Table Table to add.
+ @param Checksum Does the table require checksumming.
+ @param Version The version of the list to add the table to.
+ @param Handle Pointer for returning the handle.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_OUT_OF_RESOURCES Could not allocate a required resource.
+ @retval EFI_ACCESS_DENIED The table signature matches a table already
+ present in the system and platform policy
+ does not allow duplicate tables of this type.
+**/
+EFI_STATUS
+AddTableToList (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance,
+ IN VOID *Table,
+ IN BOOLEAN Checksum,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ OUT UINTN *Handle
+ )
+{
+ EFI_STATUS Status;
+ EFI_ACPI_TABLE_LIST *CurrentTableList;
+ UINT32 CurrentTableSignature;
+ UINT32 CurrentTableSize;
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 Buffer64;
+ BOOLEAN AddToRsdt;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiSupportInstance);
+ ASSERT (Table);
+ ASSERT (Handle);
+
+ //
+ // Init locals
+ //
+ AddToRsdt = TRUE;
+
+ //
+ // Create a new list entry
+ //
+ CurrentTableList = AllocatePool (sizeof (EFI_ACPI_TABLE_LIST));
+ ASSERT (CurrentTableList);
+
+ //
+ // Determine table type and size
+ //
+ CurrentTableSignature = ((EFI_ACPI_COMMON_HEADER *) Table)->Signature;
+ CurrentTableSize = ((EFI_ACPI_COMMON_HEADER *) Table)->Length;
+
+ //
+ // Allocate a buffer for the table. All tables are allocated in the lower 32 bits of address space
+ // for backwards compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ CurrentTableList->PageAddress = 0xFFFFFFFF;
+ CurrentTableList->NumberOfPages = EFI_SIZE_TO_PAGES (CurrentTableSize);
+
+ //
+ // Allocation memory type depends on the type of the table
+ //
+ if ((CurrentTableSignature == EFI_ACPI_2_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_4_0_UEFI_ACPI_DATA_TABLE_SIGNATURE)) {
+ //
+ // Allocate memory for the FACS. This structure must be aligned
+ // on a 64 byte boundary and must be ACPI NVS memory.
+ // Using AllocatePages should ensure that it is always aligned.
+ // Do not change signature for new ACPI version because they are same.
+ //
+ // UEFI table also need to be in ACPI NVS memory, because some data field
+ // could be updated by OS present agent. For example, BufferPtrAddress in
+ // SMM communication ACPI table.
+ //
+ ASSERT ((EFI_PAGE_SIZE % 64) == 0);
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIMemoryNVS,
+ CurrentTableList->NumberOfPages,
+ &CurrentTableList->PageAddress
+ );
+ } else {
+ //
+ // All other tables are ACPI reclaim memory, no alignment requirements.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIReclaimMemory,
+ CurrentTableList->NumberOfPages,
+ &CurrentTableList->PageAddress
+ );
+ }
+ //
+ // Check return value from memory alloc.
+ //
+ if (EFI_ERROR (Status)) {
+ gBS->FreePool (CurrentTableList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Update the table pointer with the allocated memory start
+ //
+ CurrentTableList->Table = (EFI_ACPI_COMMON_HEADER *) (UINTN) CurrentTableList->PageAddress;
+
+ //
+ // Initialize the table contents
+ //
+ CurrentTableList->Signature = EFI_ACPI_TABLE_LIST_SIGNATURE;
+ CopyMem (CurrentTableList->Table, Table, CurrentTableSize);
+ CurrentTableList->Handle = AcpiSupportInstance->CurrentHandle++;
+ *Handle = CurrentTableList->Handle;
+ CurrentTableList->Version = Version;
+
+ //
+ // Update internal pointers if this is a required table. If it is a required
+ // table and a table of that type already exists, return an error.
+ //
+ // Calculate the checksum if the table is not FACS.
+ //
+ switch (CurrentTableSignature) {
+
+ case EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ //
+ // We don't add the FADT in the standard way because some
+ // OS expect the FADT to be early in the table list.
+ // So we always add it as the first element in the list.
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiSupportInstance->Fadt1 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 && AcpiSupportInstance->Fadt3 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_3_0) != 0 && AcpiSupportInstance->Fadt3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Fadt1 = (EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE *) CurrentTableList->Table;
+
+ //
+ // Update pointers in FADT. If tables don't exist this will put NULL pointers there.
+ //
+ AcpiSupportInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiSupportInstance->Facs1;
+ AcpiSupportInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiSupportInstance->Dsdt1;
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiSupportInstance->Rsdp1->OemId,
+ &AcpiSupportInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ //
+ // RSDT OEM information is updated to match the FADT OEM information.
+ //
+ CopyMem (
+ &AcpiSupportInstance->Rsdt1->OemId,
+ &AcpiSupportInstance->Fadt1->Header.OemId,
+ 6
+ );
+
+ CopyMem (
+ &AcpiSupportInstance->Rsdt1->OemTableId,
+ &AcpiSupportInstance->Fadt1->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiSupportInstance->Rsdt1->OemRevision = AcpiSupportInstance->Fadt1->Header.OemRevision;
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Fadt3 = (EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE *) CurrentTableList->Table;
+
+ //
+ // Update pointers in FADT. If tables don't exist this will put NULL pointers there.
+ // Note: If the FIRMWARE_CTRL is non-zero, then X_FIRMWARE_CTRL must be zero, and
+ // vice-versa.
+ //
+ if ((UINT64)(UINTN)AcpiSupportInstance->Facs3 < BASE_4GB) {
+ AcpiSupportInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiSupportInstance->Facs3;
+ ZeroMem (
+ &AcpiSupportInstance->Fadt3->XFirmwareCtrl,
+ sizeof (UINT64)
+ );
+ } else {
+ AcpiSupportInstance->Fadt3->FirmwareCtrl = 0;
+ Buffer64 = (UINT64) (UINTN) AcpiSupportInstance->Facs3;
+ CopyMem (
+ &AcpiSupportInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ }
+ AcpiSupportInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiSupportInstance->Dsdt3;
+ Buffer64 = (UINT64) (UINTN) AcpiSupportInstance->Dsdt3;
+ CopyMem (
+ &AcpiSupportInstance->Fadt3->XDsdt,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+
+ //
+ // RSDP OEM information is updated to match the FADT OEM information
+ //
+ CopyMem (
+ &AcpiSupportInstance->Rsdp3->OemId,
+ &AcpiSupportInstance->Fadt3->Header.OemId,
+ 6
+ );
+
+ //
+ // RSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiSupportInstance->Rsdt3->OemId,
+ &AcpiSupportInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiSupportInstance->Rsdt3->OemTableId,
+ &AcpiSupportInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiSupportInstance->Rsdt3->OemRevision = AcpiSupportInstance->Fadt3->Header.OemRevision;
+
+ //
+ // XSDT OEM information is updated to match FADT OEM information.
+ //
+ CopyMem (
+ &AcpiSupportInstance->Xsdt->OemId,
+ &AcpiSupportInstance->Fadt3->Header.OemId,
+ 6
+ );
+ CopyMem (
+ &AcpiSupportInstance->Xsdt->OemTableId,
+ &AcpiSupportInstance->Fadt3->Header.OemTableId,
+ sizeof (UINT64)
+ );
+ AcpiSupportInstance->Xsdt->OemRevision = AcpiSupportInstance->Fadt3->Header.OemRevision;
+ }
+
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+
+ case EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiSupportInstance->Facs1 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 && AcpiSupportInstance->Facs3 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_3_0) != 0 && AcpiSupportInstance->Facs3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // FACS is referenced by FADT and is not part of RSDT
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Facs1 = (EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiSupportInstance->Fadt1 != NULL) {
+ AcpiSupportInstance->Fadt1->FirmwareCtrl = (UINT32) (UINTN) AcpiSupportInstance->Facs1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt1,
+ AcpiSupportInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Facs3 = (EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiSupportInstance->Fadt3 != NULL) {
+ //
+ // Note: If the FIRMWARE_CTRL is non-zero, then X_FIRMWARE_CTRL must be zero, and
+ // vice-versa.
+ //
+ if ((UINT64)(UINTN)AcpiSupportInstance->Facs3 < BASE_4GB) {
+ AcpiSupportInstance->Fadt3->FirmwareCtrl = (UINT32) (UINTN) AcpiSupportInstance->Facs3;
+ } else {
+ Buffer64 = (UINT64) (UINTN) AcpiSupportInstance->Facs3;
+ CopyMem (
+ &AcpiSupportInstance->Fadt3->XFirmwareCtrl,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+ }
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt3,
+ AcpiSupportInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ break;
+
+ case EFI_ACPI_1_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+ //
+ // Check that the table has not been previously added.
+ //
+ if (((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0 && AcpiSupportInstance->Dsdt1 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 && AcpiSupportInstance->Dsdt3 != NULL) ||
+ ((Version & EFI_ACPI_TABLE_VERSION_3_0) != 0 && AcpiSupportInstance->Dsdt3 != NULL)
+ ) {
+ gBS->FreePages (CurrentTableList->PageAddress, CurrentTableList->NumberOfPages);
+ gBS->FreePool (CurrentTableList);
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // DSDT is referenced by FADT and is not part of RSDT
+ //
+ AddToRsdt = FALSE;
+
+ //
+ // Add the table to the appropriate table version
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Dsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiSupportInstance->Fadt1 != NULL) {
+ AcpiSupportInstance->Fadt1->Dsdt = (UINT32) (UINTN) AcpiSupportInstance->Dsdt1;
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt1,
+ AcpiSupportInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ //
+ // Save a pointer to the table
+ //
+ AcpiSupportInstance->Dsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) CurrentTableList->Table;
+
+ //
+ // If FADT already exists, update table pointers.
+ //
+ if (AcpiSupportInstance->Fadt3 != NULL) {
+ AcpiSupportInstance->Fadt3->Dsdt = (UINT32) (UINTN) AcpiSupportInstance->Dsdt3;
+ Buffer64 = (UINT64) (UINTN) AcpiSupportInstance->Dsdt3;
+ CopyMem (
+ &AcpiSupportInstance->Fadt3->XDsdt,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+
+ //
+ // Checksum FADT table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt3,
+ AcpiSupportInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+
+ default:
+ //
+ // Checksum the table
+ //
+ if (Checksum) {
+ AcpiPlatformChecksum (
+ CurrentTableList->Table,
+ CurrentTableList->Table->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ break;
+ }
+ //
+ // Add the table to the current list of tables
+ //
+ InsertTailList (&AcpiSupportInstance->TableList, &CurrentTableList->Link);
+
+ //
+ // Add the table to RSDT and/or XSDT table entry lists.
+ //
+ //
+ // Add to ACPI 1.0b table tree
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ if (AddToRsdt) {
+ //
+ // If the table number exceed the gEfiAcpiMaxNumTables, enlarge the table buffer
+ //
+ if (AcpiSupportInstance->NumberOfTableEntries1 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiSupportInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+ CurrentRsdtEntry = (UINT32 *)
+ (
+ (UINT8 *) AcpiSupportInstance->Rsdt1 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiSupportInstance->NumberOfTableEntries1 *
+ sizeof (UINT32)
+ );
+
+ //
+ // Add entry to the RSDT unless its the FACS or DSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiSupportInstance->Rsdt1->Length = AcpiSupportInstance->Rsdt1->Length + sizeof (UINT32);
+
+ AcpiSupportInstance->NumberOfTableEntries1++;
+ }
+ }
+ //
+ // Add to ACPI 2.0/3.0 table tree
+ //
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 || (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ if (AddToRsdt) {
+ //
+ // If the table number exceed the gEfiAcpiMaxNumTables, enlarge the table buffer
+ //
+ if (AcpiSupportInstance->NumberOfTableEntries3 >= mEfiAcpiMaxNumTables) {
+ Status = ReallocateAcpiTableBuffer (AcpiSupportInstance);
+ ASSERT_EFI_ERROR (Status);
+ }
+ //
+ // At this time, it is assumed that RSDT and XSDT maintain parallel lists of tables.
+ // If it becomes necessary to maintain separate table lists, changes will be required.
+ //
+ CurrentRsdtEntry = (UINT32 *)
+ (
+ (UINT8 *) AcpiSupportInstance->Rsdt3 +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiSupportInstance->NumberOfTableEntries3 *
+ sizeof (UINT32)
+ );
+
+ //
+ // This pointer must not be directly dereferenced as the XSDT entries may not
+ // be 64 bit aligned resulting in a possible fault. Use CopyMem to update.
+ //
+ CurrentXsdtEntry = (VOID *)
+ (
+ (UINT8 *) AcpiSupportInstance->Xsdt +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) +
+ AcpiSupportInstance->NumberOfTableEntries3 *
+ sizeof (UINT64)
+ );
+
+ //
+ // Add entry to the RSDT
+ //
+ *CurrentRsdtEntry = (UINT32) (UINTN) CurrentTableList->Table;
+
+ //
+ // Update RSDT length
+ //
+ AcpiSupportInstance->Rsdt3->Length = AcpiSupportInstance->Rsdt3->Length + sizeof (UINT32);
+
+ //
+ // Add entry to XSDT, XSDT expects 64 bit pointers, but
+ // the table pointers in XSDT are not aligned on 8 byte boundary.
+ //
+ Buffer64 = (UINT64) (UINTN) CurrentTableList->Table;
+ CopyMem (
+ CurrentXsdtEntry,
+ &Buffer64,
+ sizeof (UINT64)
+ );
+
+ //
+ // Update length
+ //
+ AcpiSupportInstance->Xsdt->Length = AcpiSupportInstance->Xsdt->Length + sizeof (UINT64);
+
+ AcpiSupportInstance->NumberOfTableEntries3++;
+ }
+ }
+
+ ChecksumCommonTables (AcpiSupportInstance);
+ return EFI_SUCCESS;
+}
+/**
+ This function finds the table specified by the handle and returns a pointer to it.
+ If the handle is not found, EFI_NOT_FOUND is returned and the contents of Table are
+ undefined.
+
+ @param Handle Table to find.
+ @param TableList Table list to search
+ @param Table Pointer to table found.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_NOT_FOUND No table found matching the handle specified.
+
+**/
+EFI_STATUS
+FindTableByHandle (
+ IN UINTN Handle,
+ IN LIST_ENTRY *TableList,
+ OUT EFI_ACPI_TABLE_LIST **Table
+ )
+{
+ LIST_ENTRY *CurrentLink;
+ EFI_ACPI_TABLE_LIST *CurrentTable;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (Table);
+
+ //
+ // Find the table
+ //
+ CurrentLink = TableList->ForwardLink;
+
+ while (CurrentLink != TableList) {
+ CurrentTable = EFI_ACPI_TABLE_LIST_FROM_LINK (CurrentLink);
+ if (CurrentTable->Handle == Handle) {
+ //
+ // Found handle, so return this table.
+ //
+ *Table = CurrentTable;
+ return EFI_SUCCESS;
+ }
+
+ CurrentLink = CurrentLink->ForwardLink;
+ }
+ //
+ // Table not found
+ //
+ return EFI_NOT_FOUND;
+}
+/**
+ This function removes a basic table from the RSDT and/or XSDT.
+ For Acpi 1.0 tables, pass in the Rsdt.
+ For Acpi 2.0 tables, pass in both Rsdt and Xsdt.
+
+ @param Table Pointer to table found.
+ @param NumberOfTableEntries Current number of table entries in the RSDT/XSDT
+ @param Rsdt Pointer to the RSDT to remove from
+ @param Xsdt Pointer to the Xsdt to remove from
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_INVALID_PARAMETER The table was not found in both Rsdt and Xsdt.
+
+**/
+EFI_STATUS
+RemoveTableFromRsdt (
+ IN OUT EFI_ACPI_TABLE_LIST * Table,
+ IN OUT UINTN *NumberOfTableEntries,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER * Rsdt,
+ IN OUT EFI_ACPI_DESCRIPTION_HEADER * Xsdt OPTIONAL
+ )
+{
+ UINT32 *CurrentRsdtEntry;
+ VOID *CurrentXsdtEntry;
+ UINT64 CurrentTablePointer64;
+ UINTN TempIndex;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (Table);
+ ASSERT (NumberOfTableEntries);
+ ASSERT (Rsdt);
+
+ //
+ // Find the table entry in the RSDT and XSDT
+ //
+ for (TempIndex = 0; TempIndex < *NumberOfTableEntries; TempIndex++) {
+ //
+ // At this time, it is assumed that RSDT and XSDT maintain parallel lists of tables.
+ // If it becomes necessary to maintain separate table lists, changes will be required.
+ //
+ CurrentRsdtEntry = (UINT32 *) ((UINT8 *) Rsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER) + TempIndex * sizeof (UINT32));
+ if (Xsdt != NULL) {
+ //
+ // This pointer must not be directly dereferenced as the XSDT entries may not
+ // be 64 bit aligned resulting in a possible fault. Use CopyMem to update.
+ //
+ CurrentXsdtEntry = (VOID *) ((UINT8 *) Xsdt + sizeof (EFI_ACPI_DESCRIPTION_HEADER) + TempIndex * sizeof (UINT64));
+
+ //
+ // Read the entry value out of the XSDT
+ //
+ CopyMem (&CurrentTablePointer64, CurrentXsdtEntry, sizeof (UINT64));
+ } else {
+ //
+ // Initialize to NULL
+ //
+ CurrentXsdtEntry = 0;
+ CurrentTablePointer64 = 0;
+ }
+ //
+ // Check if we have found the corresponding entry in both RSDT and XSDT
+ //
+ if (*CurrentRsdtEntry == (UINT32) (UINTN) Table->Table &&
+ ((Xsdt == NULL) || CurrentTablePointer64 == (UINT64) (UINTN) Table->Table)
+ ) {
+ //
+ // Found entry, so copy all following entries and shrink table
+ // We actually copy all + 1 to copy the initialized value of memory over
+ // the last entry.
+ //
+ CopyMem (CurrentRsdtEntry, CurrentRsdtEntry + 1, (*NumberOfTableEntries - TempIndex) * sizeof (UINT32));
+ Rsdt->Length = Rsdt->Length - sizeof (UINT32);
+ if (Xsdt != NULL) {
+ CopyMem (CurrentXsdtEntry, ((UINT64 *) CurrentXsdtEntry) + 1, (*NumberOfTableEntries - TempIndex) * sizeof (UINT64));
+ Xsdt->Length = Xsdt->Length - sizeof (UINT64);
+ }
+ break;
+ } else if (TempIndex + 1 == *NumberOfTableEntries) {
+ //
+ // At the last entry, and table not found
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Checksum the tables
+ //
+ AcpiPlatformChecksum (
+ Rsdt,
+ Rsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ if (Xsdt != NULL) {
+ AcpiPlatformChecksum (
+ Xsdt,
+ Xsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ //
+ // Decrement the number of tables
+ //
+ (*NumberOfTableEntries)--;
+
+ return EFI_SUCCESS;
+}
+/**
+ This function removes a table and frees any associated memory.
+
+ @param AcpiSupportInstance Instance of the protocol.
+ @param Version Version(s) to delete.
+ @param Table Pointer to table found.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+DeleteTable (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN OUT EFI_ACPI_TABLE_LIST *Table
+ )
+{
+ UINT32 CurrentTableSignature;
+ BOOLEAN RemoveFromRsdt;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiSupportInstance);
+ ASSERT (Table);
+
+ //
+ // Init locals
+ //
+ RemoveFromRsdt = TRUE;
+
+ if (Table->Table != NULL) {
+ CurrentTableSignature = ((EFI_ACPI_COMMON_HEADER *) Table->Table)->Signature;
+
+ //
+ // Basic tasks to accomplish delete are:
+ // Determine removal requirements (in RSDT/XSDT or not)
+ // Remove entry from RSDT/XSDT
+ // Remove any table references to the table
+ // If no one is using the table
+ // Free the table (removing pointers from private data and tables)
+ // Remove from list
+ // Free list structure
+ //
+ //
+ // Determine if this table is in the RSDT or XSDT
+ //
+ if ((CurrentTableSignature == EFI_ACPI_1_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_2_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE) ||
+ (CurrentTableSignature == EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE)
+ ) {
+ RemoveFromRsdt = FALSE;
+ }
+ //
+ // We don't remove the FADT in the standard way because some
+ // OS expect the FADT to be early in the table list.
+ // So we always put it as the first element in the list.
+ //
+ if (CurrentTableSignature == EFI_ACPI_1_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE) {
+ RemoveFromRsdt = FALSE;
+ }
+
+ //
+ // Remove the table from RSDT and XSDT
+ //
+
+ //
+ // This is a basic table, remove it from any lists and the Rsdt and/or Xsdt
+ //
+ if (Version & EFI_ACPI_TABLE_VERSION_NONE & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_NONE;
+ }
+
+ if (Version & EFI_ACPI_TABLE_VERSION_1_0B & Table->Version) {
+ //
+ // Remove this version from the table
+ //
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_1_0B;
+
+ //
+ // Remove from Rsdt. We don't care about the return value because it is
+ // acceptable for the table to not exist in Rsdt.
+ // We didn't add some tables so we don't remove them.
+ //
+ if (RemoveFromRsdt) {
+ RemoveTableFromRsdt (
+ Table,
+ &AcpiSupportInstance->NumberOfTableEntries1,
+ AcpiSupportInstance->Rsdt1,
+ NULL
+ );
+ }
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0 & Table->Version) ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0 & Table->Version)) {
+ //
+ // Remove this version from the table
+ //
+ if (Version & EFI_ACPI_TABLE_VERSION_2_0 & Table->Version) {
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_2_0;
+ }
+ if (Version & EFI_ACPI_TABLE_VERSION_3_0 & Table->Version) {
+ Table->Version = Table->Version &~EFI_ACPI_TABLE_VERSION_3_0;
+ }
+
+ //
+ // Remove from Rsdt and Xsdt. We don't care about the return value
+ // because it is acceptable for the table to not exist in Rsdt/Xsdt.
+ // We didn't add some tables so we don't remove them.
+ //
+ if (RemoveFromRsdt) {
+ RemoveTableFromRsdt (
+ Table,
+ &AcpiSupportInstance->NumberOfTableEntries3,
+ AcpiSupportInstance->Rsdt3,
+ AcpiSupportInstance->Xsdt
+ );
+ }
+ }
+ //
+ // Free the table, clean up any dependent tables and our private data pointers.
+ //
+ switch (Table->Table->Signature) {
+
+ case EFI_ACPI_3_0_FIXED_ACPI_DESCRIPTION_TABLE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiSupportInstance->Fadt1 = NULL;
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ AcpiSupportInstance->Fadt3 = NULL;
+ }
+ break;
+
+ case EFI_ACPI_3_0_FIRMWARE_ACPI_CONTROL_STRUCTURE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiSupportInstance->Facs1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiSupportInstance->Fadt1 != NULL) {
+ AcpiSupportInstance->Fadt1->FirmwareCtrl = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt1,
+ AcpiSupportInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ AcpiSupportInstance->Facs3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiSupportInstance->Fadt3 != NULL) {
+ AcpiSupportInstance->Fadt3->FirmwareCtrl = 0;
+ ZeroMem (&AcpiSupportInstance->Fadt3->XFirmwareCtrl, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt3,
+ AcpiSupportInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ break;
+
+ case EFI_ACPI_3_0_DIFFERENTIATED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE:
+ if ((Version & EFI_ACPI_TABLE_VERSION_1_0B) != 0) {
+ AcpiSupportInstance->Dsdt1 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiSupportInstance->Fadt1 != NULL) {
+ AcpiSupportInstance->Fadt1->Dsdt = 0;
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt1,
+ AcpiSupportInstance->Fadt1->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+
+
+ if ((Version & EFI_ACPI_TABLE_VERSION_2_0) != 0 ||
+ (Version & EFI_ACPI_TABLE_VERSION_3_0) != 0) {
+ AcpiSupportInstance->Dsdt3 = NULL;
+
+ //
+ // Update FADT table pointers
+ //
+ if (AcpiSupportInstance->Fadt3 != NULL) {
+ AcpiSupportInstance->Fadt3->Dsdt = 0;
+ ZeroMem (&AcpiSupportInstance->Fadt3->XDsdt, sizeof (UINT64));
+
+ //
+ // Checksum table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Fadt3,
+ AcpiSupportInstance->Fadt3->Header.Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+ }
+ }
+ break;
+
+ default:
+ //
+ // Do nothing
+ //
+ break;
+ }
+ }
+ //
+ // If no version is using this table anymore, remove and free list entry.
+ //
+ if (Table->Version == 0) {
+ //
+ // Free the Table
+ //
+ gBS->FreePages (Table->PageAddress, Table->NumberOfPages);
+ RemoveEntryList (&(Table->Link));
+ gBS->FreePool (Table);
+ }
+ //
+ // Done
+ //
+ return EFI_SUCCESS;
+}
+/**
+ This function finds and removes the table specified by the handle.
+
+ @param AcpiSupportInstance Instance of the protocol.
+ @param Version Bitmask of which versions to remove.
+ @param Handle Table to remove.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @return EFI_ABORTED An error occurred.
+ @return EFI_NOT_FOUND Handle not found in table list.
+**/
+EFI_STATUS
+RemoveTableFromList (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance,
+ IN EFI_ACPI_TABLE_VERSION Version,
+ IN UINTN Handle
+ )
+{
+ EFI_ACPI_TABLE_LIST *Table;
+ EFI_STATUS Status;
+
+ Table = NULL;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiSupportInstance);
+
+ //
+ // Find the table
+ //
+ Status = FindTableByHandle (
+ Handle,
+ &AcpiSupportInstance->TableList,
+ &Table
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Remove the table
+ //
+ Status = DeleteTable (AcpiSupportInstance, Version, Table);
+ if (EFI_ERROR (Status)) {
+ return EFI_ABORTED;
+ }
+ //
+ // Completed successfully
+ //
+ return EFI_SUCCESS;
+}
+/**
+ This function calculates and updates an UINT8 checksum.
+
+ @param Buffer Pointer to buffer to checksum
+ @param Size Number of bytes to checksum
+ @param ChecksumOffset Offset to place the checksum result in
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+AcpiPlatformChecksum (
+ IN VOID *Buffer,
+ IN UINTN Size,
+ IN UINTN ChecksumOffset
+ )
+{
+ UINT8 Sum;
+ UINT8 *Ptr;
+
+ Sum = 0;
+ //
+ // Initialize pointer
+ //
+ Ptr = Buffer;
+
+ //
+ // set checksum to 0 first
+ //
+ Ptr[ChecksumOffset] = 0;
+
+ //
+ // add all content of buffer
+ //
+ while ((Size--) != 0) {
+ Sum = (UINT8) (Sum + (*Ptr++));
+ }
+ //
+ // set checksum
+ //
+ Ptr = Buffer;
+ Ptr[ChecksumOffset] = (UINT8) (0xff - Sum + 1);
+
+ return EFI_SUCCESS;
+}
+/**
+ Checksum all versions of the common tables, RSDP, RSDT, XSDT.
+
+ @param AcpiSupportInstance Protocol instance private data.
+
+ @return EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+ChecksumCommonTables (
+ IN OUT EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance
+ )
+{
+ //
+ // RSDP ACPI 1.0 checksum for 1.0 table. This is only the first 20 bytes of the structure
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Rsdp1,
+ sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ Checksum)
+ );
+
+ //
+ // RSDP ACPI 1.0 checksum for 2.0/3.0 table. This is only the first 20 bytes of the structure
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Rsdp3,
+ sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ Checksum)
+ );
+
+ //
+ // RSDP ACPI 2.0/3.0 checksum, this is the entire table
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Rsdp3,
+ sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER),
+ OFFSET_OF (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER,
+ ExtendedChecksum)
+ );
+
+ //
+ // RSDT checksums
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Rsdt1,
+ AcpiSupportInstance->Rsdt1->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Rsdt3,
+ AcpiSupportInstance->Rsdt3->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ //
+ // XSDT checksum
+ //
+ AcpiPlatformChecksum (
+ AcpiSupportInstance->Xsdt,
+ AcpiSupportInstance->Xsdt->Length,
+ OFFSET_OF (EFI_ACPI_DESCRIPTION_HEADER,
+ Checksum)
+ );
+
+ return EFI_SUCCESS;
+}
+/**
+ Constructor for the ACPI support protocol to initializes instance data.
+
+ @param AcpiSupportInstance Instance to construct
+
+ @retval EFI_SUCCESS Instance initialized.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate required resources.
+**/
+EFI_STATUS
+AcpiSupportAcpiSupportConstructor (
+ IN EFI_ACPI_SUPPORT_INSTANCE *AcpiSupportInstance
+ )
+{
+ EFI_STATUS Status;
+ UINT64 CurrentData;
+ UINTN TotalSize;
+ UINTN RsdpTableSize;
+ UINT8 *Pointer;
+ EFI_PHYSICAL_ADDRESS PageAddress;
+
+ //
+ // Check for invalid input parameters
+ //
+ ASSERT (AcpiSupportInstance);
+
+ InitializeListHead (&AcpiSupportInstance->TableList);
+ AcpiSupportInstance->CurrentHandle = 1;
+ AcpiSupportInstance->AcpiSupport.GetAcpiTable = GetAcpiTable;
+ AcpiSupportInstance->AcpiSupport.SetAcpiTable = SetAcpiTable;
+ AcpiSupportInstance->AcpiSupport.PublishTables = PublishTables;
+
+ AcpiSupportInstance->AcpiTableProtocol.InstallAcpiTable = InstallAcpiTable;
+ AcpiSupportInstance->AcpiTableProtocol.UninstallAcpiTable = UninstallAcpiTable;
+
+ //
+ // Create RSDP table
+ //
+ RsdpTableSize = sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER) +
+ sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (RsdpTableSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, RsdpTableSize);
+
+ AcpiSupportInstance->Rsdp1 = (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+ Pointer += sizeof (EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ AcpiSupportInstance->Rsdp3 = (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER *) Pointer;
+
+ //
+ // Create RSDT, XSDT structures
+ //
+ TotalSize = sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 1.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 RSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT32) +
+ sizeof (EFI_ACPI_DESCRIPTION_HEADER) + // for ACPI 2.0/3.0 XSDT
+ mEfiAcpiMaxNumTables * sizeof (UINT64);
+
+ //
+ // Allocate memory in the lower 32 bit of address range for
+ // compatibility with ACPI 1.0 OS.
+ //
+ // This is done because ACPI 1.0 pointers are 32 bit values.
+ // ACPI 2.0 OS and all 64 bit OS must use the 64 bit ACPI table addresses.
+ // There is no architectural reason these should be below 4GB, it is purely
+ // for convenience of implementation that we force memory below 4GB.
+ //
+ PageAddress = 0xFFFFFFFF;
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiACPIReclaimMemory,
+ EFI_SIZE_TO_PAGES (TotalSize),
+ &PageAddress
+ );
+
+ if (EFI_ERROR (Status)) {
+ gBS->FreePages ((EFI_PHYSICAL_ADDRESS)(UINTN)AcpiSupportInstance->Rsdp1, EFI_SIZE_TO_PAGES (RsdpTableSize));
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Pointer = (UINT8 *) (UINTN) PageAddress;
+ ZeroMem (Pointer, TotalSize);
+
+ AcpiSupportInstance->Rsdt1 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ AcpiSupportInstance->Rsdt3 = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+ Pointer += (sizeof (EFI_ACPI_DESCRIPTION_HEADER) + EFI_ACPI_MAX_NUM_TABLES * sizeof (UINT32));
+ AcpiSupportInstance->Xsdt = (EFI_ACPI_DESCRIPTION_HEADER *) Pointer;
+
+ //
+ // Initialize RSDP
+ //
+ CurrentData = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiSupportInstance->Rsdp1->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiSupportInstance->Rsdp1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiSupportInstance->Rsdp1->OemId));
+ AcpiSupportInstance->Rsdp1->Reserved = EFI_ACPI_RESERVED_BYTE;
+ AcpiSupportInstance->Rsdp1->RsdtAddress = (UINT32) (UINTN) AcpiSupportInstance->Rsdt1;
+
+ CurrentData = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_SIGNATURE;
+ CopyMem (&AcpiSupportInstance->Rsdp3->Signature, &CurrentData, sizeof (UINT64));
+ CopyMem (AcpiSupportInstance->Rsdp3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiSupportInstance->Rsdp3->OemId));
+ AcpiSupportInstance->Rsdp3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER_REVISION;
+ AcpiSupportInstance->Rsdp3->RsdtAddress = (UINT32) (UINTN) AcpiSupportInstance->Rsdt3;
+ AcpiSupportInstance->Rsdp3->Length = sizeof (EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_POINTER);
+ CurrentData = (UINT64) (UINTN) AcpiSupportInstance->Xsdt;
+ CopyMem (&AcpiSupportInstance->Rsdp3->XsdtAddress, &CurrentData, sizeof (UINT64));
+ SetMem (AcpiSupportInstance->Rsdp3->Reserved, 3, EFI_ACPI_RESERVED_BYTE);
+
+ //
+ // Initialize Rsdt
+ //
+ // Note that we "reserve" one entry for the FADT so it can always be
+ // at the beginning of the list of tables. Some OS don't seem
+ // to find it correctly if it is too far down the list.
+ //
+ AcpiSupportInstance->Rsdt1->Signature = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiSupportInstance->Rsdt1->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiSupportInstance->Rsdt1->Revision = EFI_ACPI_1_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiSupportInstance->Rsdt1->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiSupportInstance->Rsdt1->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiSupportInstance->Rsdt1->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiSupportInstance->Rsdt1->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiSupportInstance->Rsdt1->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiSupportInstance->Rsdt1->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiSupportInstance->NumberOfTableEntries1 = 1;
+ AcpiSupportInstance->Rsdt1->Length = AcpiSupportInstance->Rsdt1->Length + sizeof(UINT32);
+
+ AcpiSupportInstance->Rsdt3->Signature = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiSupportInstance->Rsdt3->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiSupportInstance->Rsdt3->Revision = EFI_ACPI_3_0_ROOT_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiSupportInstance->Rsdt3->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiSupportInstance->Rsdt3->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiSupportInstance->Rsdt3->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiSupportInstance->Rsdt3->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiSupportInstance->Rsdt3->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiSupportInstance->Rsdt3->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiSupportInstance->NumberOfTableEntries3 = 1;
+ AcpiSupportInstance->Rsdt3->Length = AcpiSupportInstance->Rsdt3->Length + sizeof(UINT32);
+
+ //
+ // Initialize Xsdt
+ //
+ AcpiSupportInstance->Xsdt->Signature = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_SIGNATURE;
+ AcpiSupportInstance->Xsdt->Length = sizeof (EFI_ACPI_DESCRIPTION_HEADER);
+ AcpiSupportInstance->Xsdt->Revision = EFI_ACPI_3_0_EXTENDED_SYSTEM_DESCRIPTION_TABLE_REVISION;
+ CopyMem (AcpiSupportInstance->Xsdt->OemId, PcdGetPtr (PcdAcpiDefaultOemId), sizeof (AcpiSupportInstance->Xsdt->OemId));
+ CurrentData = PcdGet64 (PcdAcpiDefaultOemTableId);
+ CopyMem (&AcpiSupportInstance->Xsdt->OemTableId, &CurrentData, sizeof (UINT64));
+ AcpiSupportInstance->Xsdt->OemRevision = PcdGet32 (PcdAcpiDefaultOemRevision);
+ AcpiSupportInstance->Xsdt->CreatorId = PcdGet32 (PcdAcpiDefaultCreatorId);
+ AcpiSupportInstance->Xsdt->CreatorRevision = PcdGet32 (PcdAcpiDefaultCreatorRevision);
+ //
+ // We always reserve first one for FADT
+ //
+ AcpiSupportInstance->Xsdt->Length = AcpiSupportInstance->Xsdt->Length + sizeof(UINT64);
+
+ ChecksumCommonTables (AcpiSupportInstance);
+
+ //
+ // Completed successfully
+ //
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.inf b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.inf
new file mode 100644
index 0000000000..32ca4f648f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.inf
@@ -0,0 +1,81 @@
+## @file
+# Acpi Support Dirver to install Framework Acpi Support Protocol.
+#
+# This driver initializes ACPI support protocol instance data structure and intstall
+# ACPI support protocol to provide Get, Set and Publish Table services.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions
+# of the BSD License which accompanies this distribution. The
+# full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = AcpiSupportDxe
+ MODULE_UNI_FILE = AcpiSupportDxe.uni
+ FILE_GUID = 506533a6-e626-4500-b14f-17939c0e5b60
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = InstallAcpiSupport
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ AcpiSupportAcpiSupportProtocol.c
+ AcpiSupport.h
+ AcpiSupport.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiDriverEntryPoint
+ BaseMemoryLib
+ UefiLib
+ DebugLib
+ BaseLib
+ PcdLib
+
+
+[Guids]
+ gEfiAcpi10TableGuid ## PRODUCES ## SystemTable
+ gEfiAcpiTableGuid ## PRODUCES ## SystemTable
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdInstallAcpiSupportProtocol ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemTableId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultOemRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorId ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdAcpiDefaultCreatorRevision ## CONSUMES
+
+[Protocols]
+ gEfiAcpiTableProtocolGuid ## PRODUCES
+ gEfiAcpiSupportProtocolGuid ## SOMETIMES_PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ AcpiSupportDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.uni b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.uni
new file mode 100644
index 0000000000..7916f6b9a2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxeExtra.uni
new file mode 100644
index 0000000000..13539ce1be
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Acpi/AcpiSupportDxe/AcpiSupportDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
new file mode 100644
index 0000000000..93bafd2dd8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Bds.h
@@ -0,0 +1,237 @@
+/** @file
+ Head file for BDS Architectural Protocol implementation
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BDS_MODULE_H_
+#define _BDS_MODULE_H_
+
+#include <FrameworkDxe.h>
+#include <IndustryStandard/PeImage.h>
+#include <Guid/MdeModuleHii.h>
+#include <Guid/FileSystemVolumeLabelInfo.h>
+#include <Guid/HiiPlatformSetupFormset.h>
+#include <Guid/StatusCodeDataTypeVariable.h>
+#include <Protocol/DevicePath.h>
+#include <IndustryStandard/SmBios.h>
+#include <Protocol/LoadFile.h>
+#include <Guid/FileInfo.h>
+#include <Protocol/HiiConfigRouting.h>
+#include <Protocol/Bds.h>
+#include <Protocol/Smbios.h>
+#include <Protocol/UgaDraw.h>
+#include <Protocol/BlockIo.h>
+#include <Guid/GlobalVariable.h>
+#include <Guid/CapsuleVendor.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/LegacyDevOrder.h>
+#include <Guid/BdsHii.h>
+#include <Guid/ConnectConInEvent.h>
+#include <Guid/Performance.h>
+#include <Guid/FmpCapsule.h>
+#include <Protocol/GenericMemoryTest.h>
+#include <Protocol/FormBrowser2.h>
+#include <Protocol/HiiConfigAccess.h>
+#include <Protocol/GraphicsOutput.h>
+#include <Protocol/SimpleFileSystem.h>
+#include <Protocol/HiiDatabase.h>
+#include <Protocol/HiiString.h>
+#include <Protocol/SerialIo.h>
+#include <Protocol/LegacyBios.h>
+#include <Protocol/SimpleTextInEx.h>
+#include <Protocol/DriverHealth.h>
+#include <Protocol/BootLogo.h>
+#include <Protocol/VariableLock.h>
+
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/PrintLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/PerformanceLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/HobLib.h>
+#include <Library/BaseLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/PcdLib.h>
+#include <Library/CapsuleLib.h>
+#include <Library/HiiLib.h>
+#include <Library/DevicePathLib.h>
+#include <Library/UefiHiiServicesLib.h>
+
+#include <Library/GenericBdsLib.h>
+#include <Library/PlatformBdsLib.h>
+
+#pragma pack(1)
+
+///
+/// HII specific Vendor Device Path definition.
+///
+typedef struct {
+ VENDOR_DEVICE_PATH VendorDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL End;
+} HII_VENDOR_DEVICE_PATH;
+
+#pragma pack()
+
+/**
+
+ Show progress bar with title above it. It only works in Graphics mode.
+
+ @param TitleForeground Foreground color for Title.
+ @param TitleBackground Background color for Title.
+ @param Title Title above progress bar.
+ @param ProgressColor Progress bar color.
+ @param Progress Progress (0-100)
+ @param PreviousValue The previous value of the progress.
+
+ @retval EFI_STATUS Success update the progress bar
+
+**/
+EFI_STATUS
+PlatformBdsShowProgress (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
+ IN CHAR16 *Title,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
+ IN UINTN Progress,
+ IN UINTN PreviousValue
+ );
+
+//
+// Prototypes
+//
+
+/**
+
+ Install Boot Device Selection Protocol
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS BDS has finished initializing.
+ Return the dispatcher and recall BDS.Entry
+ @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
+
+**/
+EFI_STATUS
+EFIAPI
+BdsInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ );
+
+/**
+
+ Service routine for BdsInstance->Entry(). Devices are connected, the
+ consoles are initialized, and the boot options are tried.
+
+ @param This Protocol Instance structure.
+
+**/
+VOID
+EFIAPI
+BdsEntry (
+ IN EFI_BDS_ARCH_PROTOCOL *This
+ );
+
+
+/**
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+ @param Level The memory test intensive level.
+
+ @retval EFI_STATUS Success test all the system memory and update
+ the memory resource
+
+**/
+EFI_STATUS
+EFIAPI
+BdsMemoryTest (
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ );
+
+/**
+
+ This routine is called to see if there are any capsules we need to process.
+ If the boot mode is not UPDATE, then we do nothing. Otherwise find the
+ capsule HOBS and produce firmware volumes for them via the DXE service.
+ Then call the dispatcher to dispatch drivers from them. Finally, check
+ the status of the updates.
+
+ This function should be called by BDS in case we need to do some
+ sort of processing even if there is no capsule to process. We
+ need to do this if an earlier update went away and we need to
+ clear the capsule variable so on the next reset PEI does not see it and
+ think there is a capsule available.
+
+ @param BootMode the current boot mode
+
+ @retval EFI_INVALID_PARAMETER boot mode is not correct for an update
+ @retval EFI_SUCCESS There is no error when processing capsule
+
+**/
+EFI_STATUS
+EFIAPI
+BdsProcessCapsules (
+ EFI_BOOT_MODE BootMode
+ );
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+BdsDxeSetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
new file mode 100644
index 0000000000..6afb8a09df
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.inf
@@ -0,0 +1,228 @@
+## @file
+# BDSDxe module is core driver for BDS phase.
+#
+# When DxeCore dispatching all DXE driver, this module will produce architecture protocol
+# gEfiBdsArchProtocolGuid. After DxeCore finish dispatching, DxeCore will invoke Entry
+# interface of protocol gEfiBdsArchProtocolGuid, then BDS phase is entered.
+#
+# Generally, this module take reposiblity to connect all necessary devices for platform boot,
+# these boot device path are hold in PlatformBdsLib library instance produced by platform.
+# For legacy boot, BDS will transfer control to legacy BIOS after legacy boot device is select.
+# For EFI boot, BDS will load boot loader file EFI\BOOT\BOOTIA32.EFI, EFI\BOOT\BOOTX64.EFI,
+# EFI\BOOT\BOOTIA64.EFI file from selected boot device and transfer control to boot loader.
+#
+# BDSDxe also maintain the UI for "Boot Manager, Boot Maintaince Manager, Device Manager" which
+# is used for user to configure boot option or maintain hardware device.
+#
+# Copyright (c) 2008 - 2015, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = BdsDxe
+ MODULE_UNI_FILE = BdsDxe.uni
+ FILE_GUID = FC5C7020-1A48-4198-9BE2-EAD5ABC8CF2F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = BdsInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FrontPage.h
+ Language.h
+ Bds.h
+ Hotkey.h
+ BootMaint/BBSsupport.h
+ BootMngr/BootManager.h
+ BootMaint/BootMaint.h
+ String.h
+ BootMaint/FormGuid.h
+ HwErrRecSupport.c
+ HwErrRecSupport.h
+
+ DeviceMngr/DeviceManager.h
+ DeviceMngr/DeviceManagerVfr.h
+ DeviceMngr/DeviceManagerVfr.Vfr
+ DeviceMngr/DriverHealthVfr.Vfr
+ DeviceMngr/DeviceManagerStrings.uni
+ DeviceMngr/DeviceManager.c
+ BootMngr/BootManagerVfr.Vfr
+ BootMngr/BootManagerStrings.uni
+ BootMngr/BootManager.c
+ BootMaint/FE.vfr
+ BootMaint/FileExplorer.c
+ BootMaint/BootMaint.c
+ BootMaint/BBSsupport.c
+ BootMaint/UpdatePage.c
+ BootMaint/Variable.c
+ BootMaint/Data.c
+ BootMaint/ConsoleOption.c
+ BootMaint/BootOption.c
+ BootMaint/BmLib.c
+ BootMaint/Bm.vfr
+ BootMaint/Bmstring.uni
+ Hotkey.c
+ MemoryTest.c
+ Capsules.c
+ Strings.uni
+ String.c
+ Language.c
+ FrontPageVfr.Vfr
+ FrontPageStrings.uni
+ FrontPage.c
+ BdsEntry.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ DevicePathLib
+ BaseLib
+ HobLib
+ UefiRuntimeServicesTableLib
+ GenericBdsLib
+ ReportStatusCodeLib
+ PerformanceLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ PrintLib
+ HiiLib
+ UefiDriverEntryPoint
+ PlatformBdsLib
+ CapsuleLib
+ PcdLib
+ UefiHiiServicesLib
+
+[Guids]
+ ## SOMETIMES_PRODUCES ## Variable:L"BootXXXX" # Boot option variable
+ ## SOMETIMES_PRODUCES ## Variable:L"DriverXXXX" # Driver load option.
+ ## SOMETIMES_PRODUCES ## Variable:L"PlatformLang" # Platform supported languange in Rfc4646 format
+ ## SOMETIMES_PRODUCES ## Variable:L"Lang" # Platform supported languange in Iso639 format
+ ## SOMETIMES_PRODUCES ## Variable:L"LangCodes" # Value of PcdUefiVariableDefaultLangCodes
+ ## PRODUCES ## Variable:L"PlatformLangCodes" # Value of PcdUefiVariableDefaultPlatformLangCodes
+ ## SOMETIMES_PRODUCES ## Variable:L"KeyXXXX" # Hotkey option variable
+ ## PRODUCES ## Variable:L"HwErrRecSupport" # The level of platform supported hardware Error Record Persistence
+ ## PRODUCES ## Variable:L"Timeout" # The time out value in second of showing progress bar
+ ## SOMETIMES_PRODUCES ## Variable:L"BootOptionSupport" # The feature supported in boot option menu, value could be: EFI_BOOT_OPTION_SUPPORT_KEY, EFI_BOOT_OPTION_SUPPORT_APP
+ ## SOMETIMES_PRODUCES ## Variable:L"BootOrder" # The boot option array
+ ## SOMETIMES_PRODUCES ## Variable:L"DriverOrder" # The driver order list
+ ## SOMETIMES_CONSUMES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConIn" # The device path of console in device
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ConOut" # The device path of console out device
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"ErrOut" # The device path of error out device
+ ## SOMETIMES_CONSUMES ## Variable:L"ConInDev" # The device path of console in device
+ ## SOMETIMES_CONSUMES ## Variable:L"ConOutDev" # The device path of console out device
+ ## SOMETIMES_CONSUMES ## Variable:L"ErrOutDev" # The device path of error out device
+ ## SOMETIMES_PRODUCES ## Variable:L"BootNext" # The number of next boot option
+ gEfiGlobalVariableGuid
+ gEfiFileSystemVolumeLabelInfoIdGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Indicate the information type is volume
+ gEfiFileInfoGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Indicate the information type is file
+ gEfiHiiPlatformSetupFormsetGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Indicate the formset class guid to be displayed
+ gEfiIfrTianoGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Extended IFR Guid Opcode
+ gEfiHiiDriverHealthFormsetGuid ## SOMETIMES_CONSUMES ## UNDEFINED # Indicate the Driver Health formset class guid to be displayed
+ ## SOMETIMES_PRODUCES ## Variable:L"LegacyDevOrder"
+ ## SOMETIMES_CONSUMES ## Variable:L"LegacyDevOrder"
+ gEfiLegacyDevOrderVariableGuid
+ gFrontPageFormSetGuid ## SOMETIMES_CONSUMES ## HII # FrontPage HII Package
+ gBootMaintFormSetGuid ## SOMETIMES_CONSUMES ## HII # BootMaint HII Package
+ gFileExploreFormSetGuid ## SOMETIMES_CONSUMES ## HII # FileExplore HII Package
+ gBootManagerFormSetGuid ## SOMETIMES_CONSUMES ## HII # BootManager HII Package
+ gDeviceManagerFormSetGuid ## SOMETIMES_CONSUMES ## HII # DeviceManager HII Package
+ gDriverHealthFormSetGuid ## SOMETIMES_CONSUMES ## HII # DriverHealth HII Package
+ ## SOMETIMES_PRODUCES ## Event
+ ## SOMETIMES_CONSUMES ## Event
+ gConnectConInEventGuid
+ gEfiFmpCapsuleGuid ## SOMETIMES_CONSUMES ## GUID # FMP Capsule
+ gEdkiiStatusCodeDataTypeVariableGuid ## SOMETIMES_CONSUMES ## GUID
+ gEfiUartDevicePathGuid ## SOMETIMES_CONSUMES ## GUID (Identify the device path for UARD device)
+
+[Protocols]
+ gEfiSimpleFileSystemProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLoadFileProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBdsArchProtocolGuid ## PRODUCES
+ gEfiSmbiosProtocolGuid ## CONSUMES
+ gEfiGenericMemTestProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiLegacyBiosProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiUgaDrawProtocolGuid |gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## SOMETIMES_CONSUMES
+ gEfiBlockIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiGraphicsOutputProtocolGuid ## SOMETIMES_CONSUMES
+ ## CONSUMES
+ ## NOTIFY
+ gEfiSimpleTextInputExProtocolGuid
+ gEfiHiiConfigAccessProtocolGuid ## SOMETIMES_PRODUCES
+ gEfiFormBrowser2ProtocolGuid ## CONSUMES
+ gEfiSerialIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiDevicePathProtocolGuid ## CONSUMES
+ gEfiDriverHealthProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiPciIoProtocolGuid ## SOMETIMES_CONSUMES
+ gEfiBootLogoProtocolGuid ## SOMETIMES_CONSUMES
+ gEdkiiVariableLockProtocolGuid ## SOMETIMES_CONSUMES
+
+[FeaturePcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangDeprecate ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUgaConsumeSupport ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootlogoOnlyEnable ## CONSUMES
+
+[Pcd]
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLangCodes ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultLang ## SOMETIMES_CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLangCodes ## CONSUMES
+ gEfiMdePkgTokenSpaceGuid.PcdUefiVariableDefaultPlatformLang ## SOMETIMES_CONSUMES
+ ## CONSUMES
+ ## PRODUCES
+ gEfiMdePkgTokenSpaceGuid.PcdHardwareErrorRecordLevel
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutRow ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConOutColumn ## PRODUCES
+ ## SOMETIMES_CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdePkgTokenSpaceGuid.PcdPlatformBootTimeOut
+ ## CONSUMES
+ ## PRODUCES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdBootState
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareVendor ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdFirmwareRevision ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoHorizontalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdVideoVerticalResolution ## PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdConInConnectOnDemand ## SOMETIMES_CONSUMES
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutColumn
+ ## CONSUMES
+ ## SOMETIMES_PRODUCES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupConOutRow
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoHorizontalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdSetupVideoVerticalResolution ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdErrorCodeSetVariable ## CONSUMES
+
+[Depex]
+ TRUE
+
+#
+# [BootMode]
+# FLASH_UPDATE ## SOMETIMES_CONSUMES # Update Capsule Image
+#
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ BdsDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.uni
new file mode 100644
index 0000000000..a120733895
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxeExtra.uni
new file mode 100644
index 0000000000..9aee074abe
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
new file mode 100644
index 0000000000..ae7ad2153c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BdsEntry.c
@@ -0,0 +1,754 @@
+/** @file
+ This module produce main entry for BDS phase - BdsEntry.
+ When this module was dispatched by DxeCore, gEfiBdsArchProtocolGuid will be installed
+ which contains interface of BdsEntry.
+ After DxeCore finish DXE phase, gEfiBdsArchProtocolGuid->BdsEntry will be invoked
+ to enter BDS phase.
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Bds.h"
+#include "Language.h"
+#include "FrontPage.h"
+#include "Hotkey.h"
+#include "HwErrRecSupport.h"
+
+///
+/// BDS arch protocol instance initial value.
+///
+/// Note: Current BDS not directly get the BootMode, DefaultBoot,
+/// TimeoutDefault, MemoryTestLevel value from the BDS arch protocol.
+/// Please refer to the library useage of BdsLibGetBootMode, BdsLibGetTimeout
+/// and PlatformBdsDiagnostics in BdsPlatform.c
+///
+EFI_HANDLE gBdsHandle = NULL;
+
+EFI_BDS_ARCH_PROTOCOL gBds = {
+ BdsEntry
+};
+
+UINT16 *mBootNext = NULL;
+
+///
+/// The read-only variables defined in UEFI Spec.
+///
+CHAR16 *mReadOnlyVariables[] = {
+ L"PlatformLangCodes",
+ L"LangCodes",
+ L"BootOptionSupport",
+ L"HwErrRecSupport",
+ L"OsIndicationsSupported"
+ };
+
+/**
+
+ Install Boot Device Selection Protocol
+
+ @param ImageHandle The image handle.
+ @param SystemTable The system table.
+
+ @retval EFI_SUCEESS BDS has finished initializing.
+ Return the dispatcher and recall BDS.Entry
+ @retval Other Return status from AllocatePool() or gBS->InstallProtocolInterface
+
+**/
+EFI_STATUS
+EFIAPI
+BdsInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install protocol interface
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gBdsHandle,
+ &gEfiBdsArchProtocolGuid, &gBds,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+
+/**
+ An empty function to pass error checking of CreateEventEx ().
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context,
+ which is implementation-dependent.
+
+**/
+VOID
+EFIAPI
+BdsEmptyCallbackFunction (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+}
+
+/**
+
+ This function attempts to boot for the boot order specified
+ by platform policy.
+
+**/
+VOID
+BdsBootDeviceSelect (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_COMMON_OPTION *BootOption;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ UINT16 Timeout;
+ LIST_ENTRY BootLists;
+ CHAR16 Buffer[20];
+ BOOLEAN BootNextExist;
+ LIST_ENTRY *LinkBootNext;
+ EFI_EVENT ConnectConInEvent;
+
+ //
+ // Got the latest boot option
+ //
+ BootNextExist = FALSE;
+ LinkBootNext = NULL;
+ ConnectConInEvent = NULL;
+ InitializeListHead (&BootLists);
+
+ //
+ // First check the boot next option
+ //
+ ZeroMem (Buffer, sizeof (Buffer));
+
+ //
+ // Create Event to signal ConIn connection request
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ BdsEmptyCallbackFunction,
+ NULL,
+ &gConnectConInEventGuid,
+ &ConnectConInEvent
+ );
+ if (EFI_ERROR(Status)) {
+ ConnectConInEvent = NULL;
+ }
+ }
+
+ if (mBootNext != NULL) {
+ //
+ // Indicate we have the boot next variable, so this time
+ // boot will always have this boot option
+ //
+ BootNextExist = TRUE;
+
+ //
+ // Clear the this variable so it's only exist in this time boot
+ //
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Add the boot next boot option
+ //
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", *mBootNext);
+ BootOption = BdsLibVariableToOption (&BootLists, Buffer);
+
+ //
+ // If fail to get boot option from variable, just return and do nothing.
+ //
+ if (BootOption == NULL) {
+ return;
+ }
+
+ BootOption->BootCurrent = *mBootNext;
+ }
+ //
+ // Parse the boot order to get boot option
+ //
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+
+ //
+ // When we didn't have chance to build boot option variables in the first
+ // full configuration boot (e.g.: Reset in the first page or in Device Manager),
+ // we have no boot options in the following mini configuration boot.
+ // Give the last chance to enumerate the boot options.
+ //
+ if (IsListEmpty (&BootLists)) {
+ BdsLibEnumerateAllBootOption (&BootLists);
+ }
+
+ Link = BootLists.ForwardLink;
+
+ //
+ // Parameter check, make sure the loop will be valid
+ //
+ if (Link == NULL) {
+ return ;
+ }
+ //
+ // Here we make the boot in a loop, every boot success will
+ // return to the front page
+ //
+ for (;;) {
+ //
+ // Check the boot option list first
+ //
+ if (Link == &BootLists) {
+ //
+ // When LazyConIn enabled, signal connect ConIn event before enter UI
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
+ gBS->SignalEvent (ConnectConInEvent);
+ }
+
+ //
+ // There are two ways to enter here:
+ // 1. There is no active boot option, give user chance to
+ // add new boot option
+ // 2. All the active boot option processed, and there is no
+ // one is success to boot, then we back here to allow user
+ // add new active boot option
+ //
+ Timeout = 0xffff;
+ PlatformBdsEnterFrontPage (Timeout, FALSE);
+ InitializeListHead (&BootLists);
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+ Link = BootLists.ForwardLink;
+ continue;
+ }
+ //
+ // Get the boot option from the link list
+ //
+ BootOption = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // According to EFI Specification, if a load option is not marked
+ // as LOAD_OPTION_ACTIVE, the boot manager will not automatically
+ // load the option.
+ //
+ if (!IS_LOAD_OPTION_TYPE (BootOption->Attribute, LOAD_OPTION_ACTIVE)) {
+ //
+ // skip the header of the link list, because it has no boot option
+ //
+ Link = Link->ForwardLink;
+ continue;
+ }
+ //
+ // Make sure the boot option device path connected,
+ // but ignore the BBS device path
+ //
+ if (DevicePathType (BootOption->DevicePath) != BBS_DEVICE_PATH) {
+ //
+ // Notes: the internal shell can not been connected with device path
+ // so we do not check the status here
+ //
+ BdsLibConnectDevicePath (BootOption->DevicePath);
+ }
+
+ //
+ // Restore to original mode before launching boot option.
+ //
+ BdsSetConsoleMode (FALSE);
+
+ //
+ // All the driver options should have been processed since
+ // now boot will be performed.
+ //
+ Status = BdsLibBootViaBootOption (BootOption, BootOption->DevicePath, &ExitDataSize, &ExitData);
+ if (Status != EFI_SUCCESS) {
+ //
+ // Call platform action to indicate the boot fail
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (BootOption, Status, ExitData, ExitDataSize);
+
+ //
+ // Check the next boot option
+ //
+ Link = Link->ForwardLink;
+
+ } else {
+ //
+ // Call platform action to indicate the boot success
+ //
+ BootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (BootOption);
+
+ //
+ // Boot success, then stop process the boot order, and
+ // present the boot manager menu, front page
+ //
+
+ //
+ // When LazyConIn enabled, signal connect ConIn Event before enter UI
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand) && ConnectConInEvent != NULL) {
+ gBS->SignalEvent (ConnectConInEvent);
+ }
+
+ Timeout = 0xffff;
+ PlatformBdsEnterFrontPage (Timeout, FALSE);
+
+ //
+ // Rescan the boot option list, avoid potential risk of the boot
+ // option change in front page
+ //
+ if (BootNextExist) {
+ LinkBootNext = BootLists.ForwardLink;
+ }
+
+ InitializeListHead (&BootLists);
+ if (LinkBootNext != NULL) {
+ //
+ // Reserve the boot next option
+ //
+ InsertTailList (&BootLists, LinkBootNext);
+ }
+
+ BdsLibBuildOptionFromVar (&BootLists, L"BootOrder");
+ Link = BootLists.ForwardLink;
+ }
+ }
+
+}
+
+/**
+
+ Validate input console variable data.
+
+ If found the device path is not a valid device path, remove the variable.
+
+ @param VariableName Input console variable name.
+
+**/
+VOID
+BdsFormalizeConsoleVariable (
+ IN CHAR16 *VariableName
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN VariableSize;
+ EFI_STATUS Status;
+
+ DevicePath = BdsLibGetVariableAndSize (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ &VariableSize
+ );
+ if ((DevicePath != NULL) && !IsDevicePathValid (DevicePath, VariableSize)) {
+ Status = gRT->SetVariable (
+ VariableName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+
+ Formalize Bds global variables.
+
+ 1. For ConIn/ConOut/ConErr, if found the device path is not a valid device path, remove the variable.
+ 2. For OsIndicationsSupported, Create a BS/RT/UINT64 variable to report caps
+ 3. Delete OsIndications variable if it is not NV/BS/RT UINT64
+ Item 3 is used to solve case when OS corrupts OsIndications. Here simply delete this NV variable.
+
+**/
+VOID
+BdsFormalizeEfiGlobalVariable (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT64 OsIndicationSupport;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ UINT32 Attributes;
+
+ //
+ // Validate Console variable.
+ //
+ BdsFormalizeConsoleVariable (L"ConIn");
+ BdsFormalizeConsoleVariable (L"ConOut");
+ BdsFormalizeConsoleVariable (L"ErrOut");
+
+ //
+ // OS indicater support variable
+ //
+ OsIndicationSupport = EFI_OS_INDICATIONS_BOOT_TO_FW_UI \
+ | EFI_OS_INDICATIONS_FMP_CAPSULE_SUPPORTED;
+
+ BdsDxeSetVariableAndReportStatusCodeOnError (
+ L"OsIndicationsSupported",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof(UINT64),
+ &OsIndicationSupport
+ );
+
+ //
+ // If OsIndications is invalid, remove it.
+ // Invalid case
+ // 1. Data size != UINT64
+ // 2. OsIndication value inconsistence
+ // 3. OsIndication attribute inconsistence
+ //
+ OsIndication = 0;
+ Attributes = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ &Attributes,
+ &DataSize,
+ &OsIndication
+ );
+
+ if (!EFI_ERROR(Status)) {
+ if (DataSize != sizeof(UINT64) ||
+ (OsIndication & ~OsIndicationSupport) != 0 ||
+ Attributes != (EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE)){
+
+ DEBUG ((EFI_D_ERROR, "Unformalized OsIndications variable exists. Delete it\n"));
+ Status = gRT->SetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ 0,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+}
+
+/**
+
+ Allocate a block of memory that will contain performance data to OS.
+
+**/
+VOID
+BdsAllocateMemoryForPerformanceData (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_PHYSICAL_ADDRESS AcpiLowMemoryBase;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+
+ AcpiLowMemoryBase = 0x0FFFFFFFFULL;
+
+ //
+ // Allocate a block of memory that will contain performance data to OS.
+ //
+ Status = gBS->AllocatePages (
+ AllocateMaxAddress,
+ EfiReservedMemoryType,
+ EFI_SIZE_TO_PAGES (PERF_DATA_MAX_LENGTH),
+ &AcpiLowMemoryBase
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Save the pointer to variable for use in S3 resume.
+ //
+ BdsDxeSetVariableAndReportStatusCodeOnError (
+ L"PerfDataMemAddr",
+ &gPerformanceProtocolGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (EFI_PHYSICAL_ADDRESS),
+ &AcpiLowMemoryBase
+ );
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "[Bds] PerfDataMemAddr (%08x) cannot be saved to NV storage.\n", AcpiLowMemoryBase));
+ }
+ //
+ // Mark L"PerfDataMemAddr" variable to read-only if the Variable Lock protocol exists
+ // Still lock it even the variable cannot be saved to prevent it's set by 3rd party code.
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ if (!EFI_ERROR (Status)) {
+ Status = VariableLock->RequestToLock (VariableLock, L"PerfDataMemAddr", &gPerformanceProtocolGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+}
+
+/**
+
+ Service routine for BdsInstance->Entry(). Devices are connected, the
+ consoles are initialized, and the boot options are tried.
+
+ @param This Protocol Instance structure.
+
+**/
+VOID
+EFIAPI
+BdsEntry (
+ IN EFI_BDS_ARCH_PROTOCOL *This
+ )
+{
+ LIST_ENTRY DriverOptionList;
+ LIST_ENTRY BootOptionList;
+ UINTN BootNextSize;
+ CHAR16 *FirmwareVendor;
+ EFI_STATUS Status;
+ UINT16 BootTimeOut;
+ UINTN Index;
+ EDKII_VARIABLE_LOCK_PROTOCOL *VariableLock;
+
+ //
+ // Insert the performance probe
+ //
+ PERF_END (NULL, "DXE", NULL, 0);
+ PERF_START (NULL, "BDS", NULL, 0);
+
+ PERF_CODE (
+ BdsAllocateMemoryForPerformanceData ();
+ );
+
+ //
+ // Initialize the global system boot option and driver option
+ //
+ InitializeListHead (&DriverOptionList);
+ InitializeListHead (&BootOptionList);
+
+ //
+ // Initialize hotkey service
+ //
+ InitializeHotkeyService ();
+
+ //
+ // Fill in FirmwareVendor and FirmwareRevision from PCDs
+ //
+ FirmwareVendor = (CHAR16 *)PcdGetPtr (PcdFirmwareVendor);
+ gST->FirmwareVendor = AllocateRuntimeCopyPool (StrSize (FirmwareVendor), FirmwareVendor);
+ ASSERT (gST->FirmwareVendor != NULL);
+ gST->FirmwareRevision = PcdGet32 (PcdFirmwareRevision);
+
+ //
+ // Fixup Tasble CRC after we updated Firmware Vendor and Revision
+ //
+ gST->Hdr.CRC32 = 0;
+ gBS->CalculateCrc32 ((VOID *)gST, sizeof(EFI_SYSTEM_TABLE), &gST->Hdr.CRC32);
+
+ //
+ // Validate Variable.
+ //
+ BdsFormalizeEfiGlobalVariable();
+
+ //
+ // Mark the read-only variables if the Variable Lock protocol exists
+ //
+ Status = gBS->LocateProtocol (&gEdkiiVariableLockProtocolGuid, NULL, (VOID **) &VariableLock);
+ DEBUG ((EFI_D_INFO, "[BdsDxe] Locate Variable Lock protocol - %r\n", Status));
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < sizeof (mReadOnlyVariables) / sizeof (mReadOnlyVariables[0]); Index++) {
+ Status = VariableLock->RequestToLock (VariableLock, mReadOnlyVariables[Index], &gEfiGlobalVariableGuid);
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+ //
+ // Report Status Code to indicate connecting drivers will happen
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_DXE_BS_PC_BEGIN_CONNECTING_DRIVERS)
+ );
+
+ InitializeHwErrRecSupport();
+
+ //
+ // Initialize L"Timeout" EFI global variable.
+ //
+ BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
+ if (BootTimeOut != 0xFFFF) {
+ //
+ // If time out value equal 0xFFFF, no need set to 0xFFFF to variable area because UEFI specification
+ // define same behavior between no value or 0xFFFF value for L"Timeout".
+ //
+ BdsDxeSetVariableAndReportStatusCodeOnError (
+ L"Timeout",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &BootTimeOut
+ );
+ }
+
+ //
+ // bugbug: platform specific code
+ // Initialize the platform specific string and language
+ //
+ InitializeStringSupport ();
+ InitializeLanguage (TRUE);
+ InitializeFrontPage (TRUE);
+
+ //
+ // Do the platform init, can be customized by OEM/IBV
+ //
+ PERF_START (NULL, "PlatformBds", "BDS", 0);
+ PlatformBdsInit ();
+
+ //
+ // Set up the device list based on EFI 1.1 variables
+ // process Driver#### and Load the driver's in the
+ // driver option list
+ //
+ BdsLibBuildOptionFromVar (&DriverOptionList, L"DriverOrder");
+ if (!IsListEmpty (&DriverOptionList)) {
+ BdsLibLoadDrivers (&DriverOptionList);
+ }
+ //
+ // Check if we have the boot next option
+ //
+ mBootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ //
+ // Setup some platform policy here
+ //
+ PlatformBdsPolicyBehavior (&DriverOptionList, &BootOptionList, BdsProcessCapsules, BdsMemoryTest);
+ PERF_END (NULL, "PlatformBds", "BDS", 0);
+
+ //
+ // BDS select the boot device to load OS
+ //
+ BdsBootDeviceSelect ();
+
+ //
+ // Only assert here since this is the right behavior, we should never
+ // return back to DxeCore.
+ //
+ ASSERT (FALSE);
+
+ return ;
+}
+
+
+/**
+ Set the variable and report the error through status code upon failure.
+
+ @param VariableName A Null-terminated string that is the name of the vendor's variable.
+ Each VariableName is unique for each VendorGuid. VariableName must
+ contain 1 or more characters. If VariableName is an empty string,
+ then EFI_INVALID_PARAMETER is returned.
+ @param VendorGuid A unique identifier for the vendor.
+ @param Attributes Attributes bitmask to set for the variable.
+ @param DataSize The size in bytes of the Data buffer. Unless the EFI_VARIABLE_APPEND_WRITE,
+ EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS, or
+ EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACCESS attribute is set, a size of zero
+ causes the variable to be deleted. When the EFI_VARIABLE_APPEND_WRITE attribute is
+ set, then a SetVariable() call with a DataSize of zero will not cause any change to
+ the variable value (the timestamp associated with the variable may be updated however
+ even if no new data value is provided,see the description of the
+ EFI_VARIABLE_AUTHENTICATION_2 descriptor below. In this case the DataSize will not
+ be zero since the EFI_VARIABLE_AUTHENTICATION_2 descriptor will be populated).
+ @param Data The contents for the variable.
+
+ @retval EFI_SUCCESS The firmware has successfully stored the variable and its data as
+ defined by the Attributes.
+ @retval EFI_INVALID_PARAMETER An invalid combination of attribute bits, name, and GUID was supplied, or the
+ DataSize exceeds the maximum allowed.
+ @retval EFI_INVALID_PARAMETER VariableName is an empty string.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be retrieved due to a hardware error.
+ @retval EFI_WRITE_PROTECTED The variable in question is read-only.
+ @retval EFI_WRITE_PROTECTED The variable in question cannot be deleted.
+ @retval EFI_SECURITY_VIOLATION The variable could not be written due to EFI_VARIABLE_AUTHENTICATED_WRITE_ACCESS
+ or EFI_VARIABLE_TIME_BASED_AUTHENTICATED_WRITE_ACESS being set, but the AuthInfo
+ does NOT pass the validation check carried out by the firmware.
+
+ @retval EFI_NOT_FOUND The variable trying to be updated or deleted was not found.
+**/
+EFI_STATUS
+BdsDxeSetVariableAndReportStatusCodeOnError (
+ IN CHAR16 *VariableName,
+ IN EFI_GUID *VendorGuid,
+ IN UINT32 Attributes,
+ IN UINTN DataSize,
+ IN VOID *Data
+ )
+{
+ EFI_STATUS Status;
+ EDKII_SET_VARIABLE_STATUS *SetVariableStatus;
+ UINTN NameSize;
+
+ Status = gRT->SetVariable (
+ VariableName,
+ VendorGuid,
+ Attributes,
+ DataSize,
+ Data
+ );
+ if (EFI_ERROR (Status)) {
+ NameSize = StrSize (VariableName);
+ SetVariableStatus = AllocatePool (sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize);
+ if (SetVariableStatus != NULL) {
+ CopyGuid (&SetVariableStatus->Guid, VendorGuid);
+ SetVariableStatus->NameSize = NameSize;
+ SetVariableStatus->DataSize = DataSize;
+ SetVariableStatus->SetStatus = Status;
+ SetVariableStatus->Attributes = Attributes;
+ CopyMem (SetVariableStatus + 1, VariableName, NameSize);
+ CopyMem (((UINT8 *) (SetVariableStatus + 1)) + NameSize, Data, DataSize);
+
+ REPORT_STATUS_CODE_EX (
+ EFI_ERROR_CODE,
+ PcdGet32 (PcdErrorCodeSetVariable),
+ 0,
+ NULL,
+ &gEdkiiStatusCodeDataTypeVariableGuid,
+ SetVariableStatus,
+ sizeof (EDKII_SET_VARIABLE_STATUS) + NameSize + DataSize
+ );
+
+ FreePool (SetVariableStatus);
+ }
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c
new file mode 100644
index 0000000000..6a0b525f15
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.c
@@ -0,0 +1,254 @@
+/** @file
+ This function deal with the legacy boot option, it create, delete
+ and manage the legacy boot option, all legacy boot option is getting from
+ the legacy BBS table.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BBSsupport.h"
+
+#pragma pack(1)
+typedef struct {
+ BBS_TABLE BbsEntry;
+ UINT16 BbsIndex;
+} LEGACY_BOOT_OPTION_BBS_DATA;
+#pragma pack()
+
+/**
+ Re-order the Boot Option according to the DevOrder.
+
+ The routine re-orders the Boot Option in BootOption array according to
+ the order specified by DevOrder.
+
+ @param DevOrder Pointer to buffer containing the BBS Index,
+ high 8-bit value 0xFF indicating a disabled boot option
+ @param DevOrderCount Count of the BBS Index
+ @param EnBootOption Callee allocated buffer containing the enabled Boot Option Numbers
+ @param EnBootOptionCount Count of the enabled Boot Option Numbers
+ @param DisBootOption Callee allocated buffer containing the disabled Boot Option Numbers
+ @param DisBootOptionCount Count of the disabled Boot Option Numbers
+**/
+VOID
+OrderLegacyBootOption4SameType (
+ UINT16 *DevOrder,
+ UINTN DevOrderCount,
+ UINT16 **EnBootOption,
+ UINTN *EnBootOptionCount,
+ UINT16 **DisBootOption,
+ UINTN *DisBootOptionCount
+ )
+{
+ EFI_STATUS Status;
+ UINT16 *NewBootOption;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ UINTN Index;
+ UINTN StartPosition;
+
+ BDS_COMMON_OPTION *BootOption;
+
+ CHAR16 OptionName[sizeof ("Boot####")];
+ UINT16 *BbsIndexArray;
+ UINT16 *DeviceTypeArray;
+ LIST_ENTRY List;
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+ ASSERT (BootOrder != NULL);
+
+ BbsIndexArray = AllocatePool (BootOrderSize);
+ DeviceTypeArray = AllocatePool (BootOrderSize);
+ *EnBootOption = AllocatePool (BootOrderSize);
+ *DisBootOption = AllocatePool (BootOrderSize);
+ *DisBootOptionCount = 0;
+ *EnBootOptionCount = 0;
+ Index = 0;
+
+ ASSERT (BbsIndexArray != NULL);
+ ASSERT (DeviceTypeArray != NULL);
+ ASSERT (*EnBootOption != NULL);
+ ASSERT (*DisBootOption != NULL);
+
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
+ InitializeListHead (&List);
+ BootOption = BdsLibVariableToOption (&List, OptionName);
+ ASSERT (BootOption != NULL);
+
+ if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
+ //
+ // Legacy Boot Option
+ //
+ ASSERT (BootOption->LoadOptionsSize == sizeof (LEGACY_BOOT_OPTION_BBS_DATA));
+
+ DeviceTypeArray[Index] = ((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType;
+ BbsIndexArray [Index] = ((LEGACY_BOOT_OPTION_BBS_DATA *) BootOption->LoadOptions)->BbsIndex;
+ } else {
+ DeviceTypeArray[Index] = BBS_TYPE_UNKNOWN;
+ BbsIndexArray [Index] = 0xFFFF;
+ }
+ FreePool (BootOption->DevicePath);
+ FreePool (BootOption->Description);
+ FreePool (BootOption->LoadOptions);
+ FreePool (BootOption);
+ }
+
+ //
+ // Record the corresponding Boot Option Numbers according to the DevOrder
+ // Record the EnBootOption and DisBootOption according to the DevOrder
+ //
+ StartPosition = BootOrderSize / sizeof (UINT16);
+ NewBootOption = AllocatePool (DevOrderCount * sizeof (UINT16));
+ ASSERT (NewBootOption != NULL);
+ while (DevOrderCount-- != 0) {
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ if (BbsIndexArray[Index] == (DevOrder[DevOrderCount] & 0xFF)) {
+ StartPosition = MIN (StartPosition, Index);
+ NewBootOption[DevOrderCount] = BootOrder[Index];
+
+ if ((DevOrder[DevOrderCount] & 0xFF00) == 0xFF00) {
+ (*DisBootOption)[*DisBootOptionCount] = BootOrder[Index];
+ (*DisBootOptionCount)++;
+ } else {
+ (*EnBootOption)[*EnBootOptionCount] = BootOrder[Index];
+ (*EnBootOptionCount)++;
+ }
+ break;
+ }
+ }
+ }
+
+ //
+ // Overwrite the old BootOption
+ //
+ CopyMem (&BootOrder[StartPosition], NewBootOption, (*DisBootOptionCount + *EnBootOptionCount) * sizeof (UINT16));
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Changing content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (NewBootOption);
+ FreePool (DeviceTypeArray);
+ FreePool (BbsIndexArray);
+ FreePool (BootOrder);
+}
+
+/**
+ Group the legacy boot options in the BootOption.
+
+ The routine assumes the boot options in the beginning that covers all the device
+ types are ordered properly and re-position the following boot options just after
+ the corresponding boot options with the same device type.
+ For example:
+ 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
+ Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
+ Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
+
+ 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
+ Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
+ Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
+
+**/
+VOID
+GroupMultipleLegacyBootOption4SameType (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN DeviceIndex;
+ UINTN DeviceTypeIndex[7];
+ UINTN *NextIndex;
+ UINT16 OptionNumber;
+ UINT16 *BootOrder;
+ UINTN BootOrderSize;
+ CHAR16 OptionName[sizeof ("Boot####")];
+ BDS_COMMON_OPTION *BootOption;
+ LIST_ENTRY List;
+
+ SetMem (DeviceTypeIndex, sizeof (DeviceTypeIndex), 0xff);
+
+ BootOrder = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderSize
+ );
+
+ for (Index = 0; Index < BootOrderSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (OptionName, sizeof (OptionName), L"Boot%04x", BootOrder[Index]);
+ InitializeListHead (&List);
+ BootOption = BdsLibVariableToOption (&List, OptionName);
+ ASSERT (BootOption != NULL);
+
+ if ((DevicePathType (BootOption->DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (BootOption->DevicePath) == BBS_BBS_DP)) {
+ //
+ // Legacy Boot Option
+ //
+ ASSERT ((((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF) < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]));
+ NextIndex = &DeviceTypeIndex[((BBS_BBS_DEVICE_PATH *) BootOption->DevicePath)->DeviceType & 0xF];
+
+ if (*NextIndex == (UINTN) -1) {
+ //
+ // *NextIndex is the Index in BootOrder to put the next Option Number for the same type
+ //
+ *NextIndex = Index + 1;
+ } else {
+ //
+ // insert the current boot option before *NextIndex, causing [*Next .. Index] shift right one position
+ //
+ OptionNumber = BootOrder[Index];
+ CopyMem (&BootOrder[*NextIndex + 1], &BootOrder[*NextIndex], (Index - *NextIndex) * sizeof (UINT16));
+ BootOrder[*NextIndex] = OptionNumber;
+
+ //
+ // Update the DeviceTypeIndex array to reflect the right shift operation
+ //
+ for (DeviceIndex = 0; DeviceIndex < sizeof (DeviceTypeIndex) / sizeof (DeviceTypeIndex[0]); DeviceIndex++) {
+ if (DeviceTypeIndex[DeviceIndex] != (UINTN) -1 && DeviceTypeIndex[DeviceIndex] >= *NextIndex) {
+ DeviceTypeIndex[DeviceIndex]++;
+ }
+ }
+ }
+ }
+ FreePool (BootOption->DevicePath);
+ FreePool (BootOption->Description);
+ FreePool (BootOption->LoadOptions);
+ FreePool (BootOption);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderSize,
+ BootOrder
+ );
+ //
+ // Changing content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOrder);
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h
new file mode 100644
index 0000000000..e73dc85995
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BBSsupport.h
@@ -0,0 +1,82 @@
+/** @file
+ declares interface functions
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_BDS_BBS_SUPPORT_H_
+#define _EFI_BDS_BBS_SUPPORT_H_
+
+#include "BootMaint.h"
+
+/**
+ Build Legacy Device Name String according.
+
+ @param CurBBSEntry BBS Table.
+ @param Index Index.
+ @param BufSize The buffer size.
+ @param BootString The output string.
+
+ @return VOID No output.
+
+**/
+VOID
+BdsBuildLegacyDevNameString (
+ IN BBS_TABLE *CurBBSEntry,
+ IN UINTN Index,
+ IN UINTN BufSize,
+ OUT CHAR16 *BootString
+ );
+
+/**
+ Group the legacy boot options in the BootOption.
+
+ The routine assumes the boot options in the beginning that covers all the device
+ types are ordered properly and re-position the following boot options just after
+ the corresponding boot options with the same device type.
+ For example:
+ 1. Input = [Harddisk1 CdRom2 Efi1 Harddisk0 CdRom0 CdRom1 Harddisk2 Efi0]
+ Assuming [Harddisk1 CdRom2 Efi1] is ordered properly
+ Output = [Harddisk1 Harddisk0 Harddisk2 CdRom2 CdRom0 CdRom1 Efi1 Efi0]
+
+ 2. Input = [Efi1 Efi0 CdRom1 Harddisk0 Harddisk1 Harddisk2 CdRom0 CdRom2]
+ Assuming [Efi1 Efi0 CdRom1 Harddisk0] is ordered properly
+ Output = [Efi1 Efi0 CdRom1 CdRom0 CdRom2 Harddisk0 Harddisk1 Harddisk2]
+**/
+VOID
+GroupMultipleLegacyBootOption4SameType (
+ VOID
+ );
+
+/**
+ Re-order the Boot Option according to the DevOrder.
+
+ The routine re-orders the Boot Option in BootOption array according to
+ the order specified by DevOrder.
+
+ @param DevOrder Pointer to buffer containing the BBS Index,
+ high 8-bit value 0xFF indicating a disabled boot option
+ @param DevOrderCount Count of the BBS Index
+ @param EnBootOption Callee allocated buffer containing the enabled Boot Option Numbers
+ @param EnBootOptionCount Count of the enabled Boot Option Numbers
+ @param DisBootOption Callee allocated buffer containing the disabled Boot Option Numbers
+ @param DisBootOptionCount Count of the disabled Boot Option Numbers
+**/
+VOID
+OrderLegacyBootOption4SameType (
+ UINT16 *DevOrder,
+ UINTN DevOrderCount,
+ UINT16 **EnBootOption,
+ UINTN *EnBootOptionCount,
+ UINT16 **DisBootOption,
+ UINTN *DisBootOptionCount
+ );
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr
new file mode 100644
index 0000000000..0d35c2c37e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bm.vfr
@@ -0,0 +1,365 @@
+///** @file
+//
+// Boot Maintenance Utility Formset
+//
+// Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include "FormGuid.h"
+
+formset
+ guid = BOOT_MAINT_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FORM_MAIN_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = BOOT_MAINT_FORMSET_GUID,
+
+ varstore BMM_FAKE_NV_DATA,
+ varid = VARSTORE_ID_BOOT_MAINT,
+ name = BmmData,
+ guid = BOOT_MAINT_FORMSET_GUID;
+
+ form formid = FORM_MAIN_ID,
+ title = STRING_TOKEN(STR_FORM_MAIN_TITLE);
+
+ goto FORM_BOOT_SETUP_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_SETUP_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_SETUP_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_DRIVER_SETUP_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRIVER_SETUP_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRIVER_SETUP_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRIVER_SETUP_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_CON_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_MAIN_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_MAIN_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_MAIN_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ goto FORM_BOOT_FROM_FILE_ID,
+ prompt = STRING_TOKEN(STR_BOOT_FROM_FILE),
+ help = STRING_TOKEN(STR_BOOT_FROM_FILE_HELP),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_BOOT_FROM_FILE;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+// label FORM_MAIN_ID;
+
+ goto FORM_BOOT_NEXT_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_NEXT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_NEXT_ID;
+
+ goto FORM_TIME_OUT_ID,
+ prompt = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE),
+ help = STRING_TOKEN(STR_FORM_TIME_OUT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_TIME_OUT_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_RESET),
+ text = STRING_TOKEN(STR_RESET),
+ flags = INTERACTIVE,
+ key = FORM_RESET;
+
+ endform;
+
+ form formid = FORM_BOOT_SETUP_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_SETUP_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_BOOT_ADD_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_ADD_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_ADD_ID;
+
+ goto FORM_BOOT_DEL_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_IMMEDIATE_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_DEL_ID;
+
+ goto FORM_BOOT_CHG_ID,
+ prompt = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE),
+ help = STRING_TOKEN(STR_FORM_BOOT_IMMEDIATE_HELP),
+ flags = INTERACTIVE,
+ key = FORM_BOOT_CHG_ID;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+ //
+ // We will add "Select Legacy Boot Floppy Drive" and "Select Legacy Boot Hard Drive"
+ // here dynamically
+ //
+ label FORM_BOOT_LEGACY_DEVICE_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_DRIVER_SETUP_ID,
+ title = STRING_TOKEN(STR_FORM_DRIVER_SETUP_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //help = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_DRV_ADD_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_ADD_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRV_ADD_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_ADD_ID;
+
+ goto FORM_DRV_DEL_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_DEL_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_DEL_ID;
+
+ goto FORM_DRV_CHG_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE),
+ help = STRING_TOKEN(STR_FORM_NEXT_BOOT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_DRV_CHG_ID;
+ endform;
+
+ form formid = FORM_BOOT_DEL_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_DEL_TITLE);
+
+ label FORM_BOOT_DEL_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_BOOT_CHG_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_CHG_TITLE);
+
+ label FORM_BOOT_CHG_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_BOOT_NEXT_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_NEXT_TITLE);
+
+ label FORM_BOOT_NEXT_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_TIME_OUT_ID,
+ title = STRING_TOKEN(STR_FORM_TIME_OUT_TITLE);
+
+ label FORM_TIME_OUT_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_DRV_ADD_FILE_ID,
+ prompt = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE),
+ help = STRING_TOKEN(STR_FORM_DRV_ADD_FILE_TITLE),
+ flags = INTERACTIVE,
+ key = FORM_DRV_ADD_FILE_ID;
+
+ endform;
+
+ form formid = FORM_DRV_DEL_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_DEL_TITLE);
+
+ label FORM_DRV_DEL_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_DRV_CHG_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_CHG_TITLE);
+
+ label FORM_DRV_CHG_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_MAIN_ID,
+ title = STRING_TOKEN(STR_FORM_CON_MAIN_TITLE);
+
+ goto FORM_MAIN_ID,
+ prompt = STRING_TOKEN(STR_FORM_GOTO_MAIN),
+ help = STRING_TOKEN(STR_FORM_GOTO_MAIN);
+ //flags = INTERACTIVE,
+ //key = FORM_MAIN_ID;
+
+ goto FORM_CON_IN_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_IN_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_IN_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_IN_ID;
+
+ goto FORM_CON_OUT_ID,
+ prompt = STRING_TOKEN(STR_FORM_CON_OUT_TITLE),
+ help = STRING_TOKEN(STR_FORM_CON_OUT_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_OUT_ID;
+
+ goto FORM_CON_ERR_ID,
+ prompt = STRING_TOKEN(STR_FORM_STD_ERR_TITLE),
+ help = STRING_TOKEN(STR_FORM_STD_ERR_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_ERR_ID;
+
+ goto FORM_CON_MODE_ID,
+ prompt = STRING_TOKEN(STR_FORM_MODE_TITLE),
+ help = STRING_TOKEN(STR_FORM_MODE_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_MODE_ID;
+
+ goto FORM_CON_COM_ID,
+ prompt = STRING_TOKEN(STR_FORM_COM_TITLE),
+ help = STRING_TOKEN(STR_FORM_COM_HELP),
+ flags = INTERACTIVE,
+ key = FORM_CON_COM_ID;
+ endform;
+
+ form formid = FORM_CON_MODE_ID,
+ title = STRING_TOKEN(STR_FORM_MODE_TITLE);
+
+ label FORM_CON_MODE_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_CON_COM_ID,
+ title = STRING_TOKEN(STR_FORM_COM_TITLE);
+
+ label FORM_CON_COM_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_CON_COM_SETUP_ID,
+ title = STRING_TOKEN(STR_CON_COM_SETUP);
+
+ label FORM_CON_COM_SETUP_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_FILE_SEEK_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE);
+
+ label FORM_FILE_SEEK_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_FILE_NEW_SEEK_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_TITLE);
+
+ label FORM_FILE_NEW_SEEK_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_HANDLE_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_HANDLE_TITLE);
+
+ label FORM_DRV_ADD_HANDLE_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_DRV_ADD_HANDLE_DESC_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE);
+
+ label FORM_DRV_ADD_HANDLE_DESC_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_IN_ID,
+ title = STRING_TOKEN(STR_FORM_CON_IN_TITLE);
+
+ label FORM_CON_IN_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_OUT_ID,
+ title = STRING_TOKEN(STR_FORM_CON_OUT_TITLE);
+
+ label FORM_CON_OUT_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_CON_ERR_ID,
+ title = STRING_TOKEN(STR_FORM_STD_ERR_TITLE);
+
+ label FORM_CON_ERR_ID;
+ label LABEL_END;
+
+ endform;
+
+ form formid = FORM_SET_FD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_FD_ORDER_TITLE);
+
+ label FORM_SET_FD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_HD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_HD_ORDER_TITLE);
+
+ label FORM_SET_HD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_CD_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_CD_ORDER_TITLE);
+
+ label FORM_SET_CD_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_NET_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_NET_ORDER_TITLE);
+
+ label FORM_SET_NET_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_SET_BEV_ORDER_ID,
+ title = STRING_TOKEN(STR_FORM_SET_BEV_ORDER_TITLE);
+
+ label FORM_SET_BEV_ORDER_ID;
+ label LABEL_END;
+ endform;
+
+endformset;
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BmLib.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BmLib.c
new file mode 100644
index 0000000000..4424831859
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BmLib.c
@@ -0,0 +1,411 @@
+/** @file
+ Utility routines used by boot maintenance modules.
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+/**
+
+ Function opens and returns a file handle to the root directory of a volume.
+
+ @param DeviceHandle A handle for a device
+
+ @return A valid file handle or NULL is returned
+
+**/
+EFI_FILE_HANDLE
+EfiLibOpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *Volume;
+ EFI_FILE_HANDLE File;
+
+ File = NULL;
+
+ //
+ // File the file system interface to the device
+ //
+ Status = gBS->HandleProtocol (
+ DeviceHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID *) &Volume
+ );
+
+ //
+ // Open the root directory of the volume
+ //
+ if (!EFI_ERROR (Status)) {
+ Status = Volume->OpenVolume (
+ Volume,
+ &File
+ );
+ }
+ //
+ // Done
+ //
+ return EFI_ERROR (Status) ? NULL : File;
+}
+
+/**
+
+ Helper function called as part of the code needed
+ to allocate the proper sized buffer for various
+ EFI interfaces.
+
+
+ @param Status Current status
+ @param Buffer Current allocated buffer, or NULL
+ @param BufferSize Current buffer size needed
+
+ @retval TRUE if the buffer was reallocated and the caller
+ should try the API again.
+ @retval FALSE The caller should not call this function again.
+
+**/
+BOOLEAN
+EfiGrowBuffer (
+ IN OUT EFI_STATUS *Status,
+ IN OUT VOID **Buffer,
+ IN UINTN BufferSize
+ )
+{
+ BOOLEAN TryAgain;
+
+ //
+ // If this is an initial request, buffer will be null with a new buffer size
+ //
+ if ((*Buffer == NULL) && (BufferSize != 0)) {
+ *Status = EFI_BUFFER_TOO_SMALL;
+ }
+ //
+ // If the status code is "buffer too small", resize the buffer
+ //
+ TryAgain = FALSE;
+ if (*Status == EFI_BUFFER_TOO_SMALL) {
+
+ if (*Buffer != NULL) {
+ FreePool (*Buffer);
+ }
+
+ *Buffer = AllocateZeroPool (BufferSize);
+
+ if (*Buffer != NULL) {
+ TryAgain = TRUE;
+ } else {
+ *Status = EFI_OUT_OF_RESOURCES;
+ }
+ }
+ //
+ // If there's an error, free the buffer
+ //
+ if (!TryAgain && EFI_ERROR (*Status) && (*Buffer != NULL)) {
+ FreePool (*Buffer);
+ *Buffer = NULL;
+ }
+
+ return TryAgain;
+}
+
+/**
+ Function returns the value of the specified variable.
+
+
+ @param Name A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+
+ @return The payload of the variable.
+ @retval NULL If the variable can't be read.
+
+**/
+VOID *
+EfiLibGetVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid
+ )
+{
+ UINTN VarSize;
+
+ return BdsLibGetVariableAndSize (Name, VendorGuid, &VarSize);
+}
+
+/**
+ Function deletes the variable specified by VarName and VarGuid.
+
+ @param VarName A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+
+ @param VarGuid A unique identifier for the vendor.
+
+ @retval EFI_SUCCESS The variable was found and removed
+ @retval EFI_UNSUPPORTED The variable store was inaccessible
+ @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available
+ @retval EFI_NOT_FOUND The variable was not found
+
+**/
+EFI_STATUS
+EfiLibDeleteVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VarGuid
+ )
+{
+ VOID *VarBuf;
+ EFI_STATUS Status;
+
+ VarBuf = EfiLibGetVariable (VarName, VarGuid);
+ Status = EFI_NOT_FOUND;
+
+ if (VarBuf != NULL) {
+ //
+ // Delete variable from Storage
+ //
+ Status = gRT->SetVariable (
+ VarName,
+ VarGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ 0,
+ NULL
+ );
+ //
+ // Deleting variable with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ FreePool (VarBuf);
+ }
+
+ return Status;
+}
+
+/**
+
+ Function gets the file system information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+
+ @param FHand The file handle.
+
+ @return A pointer to a buffer with file information.
+ @retval NULL is returned if failed to get Vaolume Label Info.
+
+**/
+EFI_FILE_SYSTEM_VOLUME_LABEL *
+EfiLibFileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Buffer;
+ UINTN BufferSize;
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_SYSTEM_VOLUME_LABEL + 200;
+
+ //
+ // Call the real function
+ //
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileSystemVolumeLabelInfoIdGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ Duplicate a string.
+
+ @param Src The source.
+
+ @return A new string which is duplicated copy of the source.
+ @retval NULL If there is not enough memory.
+
+**/
+CHAR16 *
+EfiStrDuplicate (
+ IN CHAR16 *Src
+ )
+{
+ CHAR16 *Dest;
+ UINTN Size;
+
+ Size = StrSize (Src);
+ Dest = AllocateZeroPool (Size);
+ ASSERT (Dest != NULL);
+ if (Dest != NULL) {
+ CopyMem (Dest, Src, Size);
+ }
+
+ return Dest;
+}
+
+/**
+
+ Function gets the file information from an open file descriptor, and stores it
+ in a buffer allocated from pool.
+
+ @param FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned
+
+**/
+EFI_FILE_INFO *
+EfiLibFileInfo (
+ IN EFI_FILE_HANDLE FHand
+ )
+{
+ EFI_STATUS Status;
+ EFI_FILE_INFO *Buffer;
+ UINTN BufferSize;
+
+ //
+ // Initialize for GrowBuffer loop
+ //
+ Buffer = NULL;
+ BufferSize = SIZE_OF_EFI_FILE_INFO + 200;
+
+ //
+ // Call the real function
+ //
+ while (EfiGrowBuffer (&Status, (VOID **) &Buffer, BufferSize)) {
+ Status = FHand->GetInfo (
+ FHand,
+ &gEfiFileInfoGuid,
+ &BufferSize,
+ Buffer
+ );
+ }
+
+ return Buffer;
+}
+
+/**
+ Function is used to determine the number of device path instances
+ that exist in a device path.
+
+
+ @param DevicePath A pointer to a device path data structure.
+
+ @return This function counts and returns the number of device path instances
+ in DevicePath.
+
+**/
+UINTN
+EfiDevicePathInstanceCount (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ UINTN Count;
+ UINTN Size;
+
+ Count = 0;
+ while (GetNextDevicePathInstance (&DevicePath, &Size) != NULL) {
+ Count += 1;
+ }
+
+ return Count;
+}
+
+/**
+ Adjusts the size of a previously allocated buffer.
+
+
+ @param OldPool - A pointer to the buffer whose size is being adjusted.
+ @param OldSize - The size of the current buffer.
+ @param NewSize - The size of the new buffer.
+
+ @return The newly allocated buffer.
+ @retval NULL Allocation failed.
+
+**/
+VOID *
+EfiReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ )
+{
+ VOID *NewPool;
+
+ NewPool = NULL;
+ if (NewSize != 0) {
+ NewPool = AllocateZeroPool (NewSize);
+ }
+
+ if (OldPool != NULL) {
+ if (NewPool != NULL) {
+ CopyMem (NewPool, OldPool, OldSize < NewSize ? OldSize : NewSize);
+ }
+
+ FreePool (OldPool);
+ }
+
+ return NewPool;
+}
+
+/**
+ Get a string from the Data Hub record based on
+ a device path.
+
+ @param DevPath The device Path.
+
+ @return A string located from the Data Hub records based on
+ the device path.
+ @retval NULL If failed to get the String from Data Hub.
+
+**/
+UINT16 *
+EfiLibStrFromDatahub (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ )
+{
+ return NULL;
+}
+
+/**
+
+ Find the first instance of this Protocol
+ in the system and return it's interface.
+
+
+ @param ProtocolGuid Provides the protocol to search for
+ @param Interface On return, a pointer to the first interface
+ that matches ProtocolGuid
+
+ @retval EFI_SUCCESS A protocol instance matching ProtocolGuid was found
+ @retval EFI_NOT_FOUND No protocol instances were found that match ProtocolGuid
+
+**/
+EFI_STATUS
+EfiLibLocateProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ OUT VOID **Interface
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ ProtocolGuid,
+ NULL,
+ (VOID **) Interface
+ );
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni
new file mode 100644
index 0000000000..b0aabc3b11
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Bmstring.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c
new file mode 100644
index 0000000000..d4b4475f09
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.c
@@ -0,0 +1,1690 @@
+/** @file
+ The functions for Boot Maintainence Main menu.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+#include "FormGuid.h"
+#include "Bds.h"
+#include "FrontPage.h"
+
+EFI_DEVICE_PATH_PROTOCOL EndDevicePath[] = {
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ END_DEVICE_PATH_LENGTH,
+ 0
+ }
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mBmmHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ BOOT_MAINT_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mFeHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ FILE_EXPLORE_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+CHAR16 mBootMaintStorageName[] = L"BmmData";
+CHAR16 mFileExplorerStorageName[] = L"FeData";
+BMM_CALLBACK_DATA *mBmmCallbackInfo = NULL;
+
+/**
+ Init all memu.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+InitAllMenu (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Free up all Menu Option list.
+
+**/
+VOID
+FreeAllMenu (
+ VOID
+ );
+
+/**
+ Initialize all of BMM configuration data in BmmFakeNvData and BmmOldFakeNVData member
+ in BMM context data and create all of dynamic OP code for BMM.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+InitializeBmmConfig (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+
+ ASSERT (CallbackData != NULL);
+
+ //
+ // Initialize data which located in BMM main page
+ //
+ CallbackData->BmmFakeNvData.BootNext = (UINT16) (BootOptionMenu.MenuNumber);
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewLoadContext->IsBootNext) {
+ CallbackData->BmmFakeNvData.BootNext = Index;
+ break;
+ }
+ }
+
+ CallbackData->BmmFakeNvData.BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
+
+ //
+ // Initialize data which located in Boot Options Menu
+ //
+ GetBootOrder (CallbackData);
+ GetLegacyDeviceOrder (CallbackData);
+
+ //
+ // Initialize data which located in Driver Options Menu
+ //
+ GetDriverOrder (CallbackData);
+
+ //
+ // Initialize data which located in Console Options Menu
+ //
+ GetConsoleOutMode (CallbackData);
+ GetConsoleInCheck (CallbackData);
+ GetConsoleOutCheck (CallbackData);
+ GetConsoleErrCheck (CallbackData);
+ GetTerminalAttribute (CallbackData);
+
+ //
+ // Backup Initialize BMM configuartion data to BmmOldFakeNVData
+ //
+ CopyMem (&CallbackData->BmmOldFakeNVData, &CallbackData->BmmFakeNvData, sizeof (BMM_FAKE_NV_DATA));
+}
+
+/**
+ Create string tokens for a menu from its help strings and display strings
+
+ @param CallbackData The BMM context data.
+ @param HiiHandle Hii Handle of the package to be updated.
+ @param MenuOption The Menu whose string tokens need to be created
+
+ @retval EFI_SUCCESS String tokens created successfully
+ @retval others contain some errors
+**/
+EFI_STATUS
+CreateMenuStringToken (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BM_MENU_OPTION *MenuOption
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index);
+
+ NewMenuEntry->DisplayStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->DisplayString,
+ NULL
+ );
+
+ if (NULL == NewMenuEntry->HelpString) {
+ NewMenuEntry->HelpStringToken = NewMenuEntry->DisplayStringToken;
+ } else {
+ NewMenuEntry->HelpStringToken = HiiSetString (
+ HiiHandle,
+ 0,
+ NewMenuEntry->HelpString,
+ NULL
+ );
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+BootMaintExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ BMM_CALLBACK_DATA *Private;
+ EFI_STRING ConfigRequestHdr;
+ EFI_STRING ConfigRequest;
+ BOOLEAN AllocatedRequest;
+ UINTN Size;
+
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Request;
+ if ((Request != NULL) && !HiiIsConfigHdrMatch (Request, &gBootMaintFormSetGuid, mBootMaintStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ ConfigRequestHdr = NULL;
+ ConfigRequest = NULL;
+ AllocatedRequest = FALSE;
+ Size = 0;
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+ //
+ // Convert buffer data to <ConfigResp> by helper function BlockToConfig()
+ //
+ BufferSize = sizeof (BMM_FAKE_NV_DATA);
+ ConfigRequest = Request;
+ if ((Request == NULL) || (StrStr (Request, L"OFFSET") == NULL)) {
+ //
+ // Request has no request element, construct full request string.
+ // Allocate and fill a buffer large enough to hold the <ConfigHdr> template
+ // followed by "&OFFSET=0&WIDTH=WWWWWWWWWWWWWWWW" followed by a Null-terminator
+ //
+ ConfigRequestHdr = HiiConstructConfigHdr (&gBootMaintFormSetGuid, mBootMaintStorageName, Private->BmmDriverHandle);
+ Size = (StrLen (ConfigRequestHdr) + 32 + 1) * sizeof (CHAR16);
+ ConfigRequest = AllocateZeroPool (Size);
+ ASSERT (ConfigRequest != NULL);
+ AllocatedRequest = TRUE;
+ UnicodeSPrint (ConfigRequest, Size, L"%s&OFFSET=0&WIDTH=%016LX", ConfigRequestHdr, (UINT64)BufferSize);
+ FreePool (ConfigRequestHdr);
+ }
+
+ Status = gHiiConfigRouting->BlockToConfig (
+ gHiiConfigRouting,
+ ConfigRequest,
+ (UINT8 *) &Private->BmmFakeNvData,
+ BufferSize,
+ Results,
+ Progress
+ );
+ //
+ // Free the allocated config request string.
+ //
+ if (AllocatedRequest) {
+ FreePool (ConfigRequest);
+ ConfigRequest = NULL;
+ }
+ //
+ // Set Progress string to the original request string.
+ //
+ if (Request == NULL) {
+ *Progress = NULL;
+ } else if (StrStr (Request, L"OFFSET") == NULL) {
+ *Progress = Request + StrLen (Request);
+ }
+
+ return Status;
+}
+
+/**
+ This function applies changes in a driver's configuration.
+ Input is a Configuration, which has the routing data for this
+ driver followed by name / value configuration pairs. The driver
+ must apply those pairs to its configurable storage. If the
+ driver's configuration is stored in a linear block of data
+ and the driver's name / value pairs are in <BlockConfig>
+ format, it may use the ConfigToBlock helper function (above) to
+ simplify the job. Currently not implemented.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ <ConfigString> format.
+ @param[out] Progress A pointer to a string filled in with the
+ offset of the most recent '&' before the
+ first failing name / value pair (or the
+ beginn ing of the string if the failure
+ is in the first name / value pair) or
+ the terminating NULL if all was
+ successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are
+ awaiting distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
+ Results parameter would result
+ in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data
+ was not found.
+**/
+EFI_STATUS
+EFIAPI
+BootMaintRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ BMM_FAKE_NV_DATA *NewBmmData;
+ BMM_FAKE_NV_DATA *OldBmmData;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+ BOOLEAN TerminalAttChange;
+ BMM_CALLBACK_DATA *Private;
+
+ if (Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Configuration;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: there is no name for Name/Value storage, only GUID will be checked
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gBootMaintFormSetGuid, mBootMaintStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID**) &ConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (BMM_FAKE_NV_DATA);
+ OldBmmData = &Private->BmmOldFakeNVData;
+ NewBmmData = &Private->BmmFakeNvData;
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ Status = ConfigRouting->ConfigToBlock (
+ ConfigRouting,
+ Configuration,
+ (UINT8 *) NewBmmData,
+ &BufferSize,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Compare new and old BMM configuration data and only do action for modified item to
+ // avoid setting unnecessary non-volatile variable
+ //
+
+ //
+ // Check data which located in BMM main page and save the settings if need
+ //
+ if (CompareMem (NewBmmData->LegacyFD, OldBmmData->LegacyFD, sizeof (NewBmmData->LegacyFD)) != 0) {
+ Var_UpdateBBSOption (Private, FORM_SET_FD_ORDER_ID);
+ }
+
+ if (CompareMem (NewBmmData->LegacyHD, OldBmmData->LegacyHD, sizeof (NewBmmData->LegacyHD)) != 0) {
+ Var_UpdateBBSOption (Private, FORM_SET_HD_ORDER_ID);
+ }
+
+ if (CompareMem (NewBmmData->LegacyCD, OldBmmData->LegacyCD, sizeof (NewBmmData->LegacyCD)) != 0) {
+ Var_UpdateBBSOption (Private, FORM_SET_CD_ORDER_ID);
+ }
+
+ if (CompareMem (NewBmmData->LegacyNET, OldBmmData->LegacyNET, sizeof (NewBmmData->LegacyNET)) != 0) {
+ Var_UpdateBBSOption (Private, FORM_SET_NET_ORDER_ID);
+ }
+
+ if (CompareMem (NewBmmData->LegacyBEV, OldBmmData->LegacyBEV, sizeof (NewBmmData->LegacyBEV)) != 0) {
+ Var_UpdateBBSOption (Private, FORM_SET_BEV_ORDER_ID);
+ }
+
+ //
+ // Change for "delete boot option" page need update NewBmmData->BootOptionOrder, so process
+ // NewBmmData->BootOptionOrder before NewBmmData->BootOptionDel
+ //
+ if (CompareMem (NewBmmData->BootOptionOrder, OldBmmData->BootOptionOrder, sizeof (NewBmmData->BootOptionOrder)) != 0) {
+ Status = Var_UpdateBootOrder (Private);
+ }
+
+ //
+ // Change for "delete driver option" page need update NewBmmData->DriverOptionOrder, so process
+ // NewBmmData->DriverOptionOrder before NewBmmData->DriverOptionDel
+ //
+ if (CompareMem (NewBmmData->DriverOptionOrder, OldBmmData->DriverOptionOrder, sizeof (NewBmmData->DriverOptionOrder)) != 0) {
+ Status = Var_UpdateDriverOrder (Private);
+ }
+
+ //
+ // Check data which located in Boot Options Menu and save the settings if need
+ //
+ if (CompareMem (NewBmmData->BootOptionDel, OldBmmData->BootOptionDel, sizeof (NewBmmData->BootOptionDel)) != 0) {
+ for (Index = 0;
+ ((Index < BootOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->BootOptionDel) / sizeof (NewBmmData->BootOptionDel[0]))));
+ Index ++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = NewBmmData->BootOptionDel[Index];
+ NewBmmData->BootOptionDel[Index] = FALSE;
+ NewBmmData->BootOptionDelMark[Index] = FALSE;
+ }
+
+ Var_DelBootOption ();
+ }
+
+ //
+ // Check data which located in Driver Options Menu and save the settings if need
+ //
+ if (CompareMem (NewBmmData->DriverOptionDel, OldBmmData->DriverOptionDel, sizeof (NewBmmData->DriverOptionDel)) != 0) {
+ for (Index = 0;
+ ((Index < DriverOptionMenu.MenuNumber) && (Index < (sizeof (NewBmmData->DriverOptionDel) / sizeof (NewBmmData->DriverOptionDel[0]))));
+ Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = NewBmmData->DriverOptionDel[Index];
+ NewBmmData->DriverOptionDel[Index] = FALSE;
+ NewBmmData->DriverOptionDelMark[Index] = FALSE;
+ }
+ Var_DelDriverOption ();
+ }
+
+ if (CompareMem (&NewBmmData->BootTimeOut, &OldBmmData->BootTimeOut, sizeof (NewBmmData->BootTimeOut)) != 0) {
+ Status = gRT->SetVariable (
+ L"Timeout",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &(NewBmmData->BootTimeOut)
+ );
+ ASSERT_EFI_ERROR(Status);
+
+ //
+ // Bugbug: code not exit in UiApp but in IntelFrameworkModulePkg, need do more check.
+ //
+ Private->BmmOldFakeNVData.BootTimeOut = NewBmmData->BootTimeOut;
+ }
+
+ if (CompareMem (&NewBmmData->BootNext, &OldBmmData->BootNext, sizeof (NewBmmData->BootNext)) != 0) {
+ Status = Var_UpdateBootNext (Private);
+ }
+
+ if (CompareMem (&NewBmmData->ConsoleOutMode, &OldBmmData->ConsoleOutMode, sizeof (NewBmmData->ConsoleOutMode)) != 0) {
+ Var_UpdateConMode (Private);
+ }
+
+ TerminalAttChange = FALSE;
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+
+ //
+ // only need update modified items
+ //
+ if (CompareMem (&NewBmmData->COMBaudRate[Index], &OldBmmData->COMBaudRate[Index], sizeof (NewBmmData->COMBaudRate[Index])) == 0 &&
+ CompareMem (&NewBmmData->COMDataRate[Index], &OldBmmData->COMDataRate[Index], sizeof (NewBmmData->COMDataRate[Index])) == 0 &&
+ CompareMem (&NewBmmData->COMStopBits[Index], &OldBmmData->COMStopBits[Index], sizeof (NewBmmData->COMStopBits[Index])) == 0 &&
+ CompareMem (&NewBmmData->COMParity[Index], &OldBmmData->COMParity[Index], sizeof (NewBmmData->COMParity[Index])) == 0 &&
+ CompareMem (&NewBmmData->COMTerminalType[Index], &OldBmmData->COMTerminalType[Index], sizeof (NewBmmData->COMTerminalType[Index])) == 0 &&
+ CompareMem (&NewBmmData->COMFlowControl[Index], &OldBmmData->COMFlowControl[Index], sizeof (NewBmmData->COMFlowControl[Index])) == 0) {
+ continue;
+ }
+
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ ASSERT (NewMenuEntry != NULL);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ NewTerminalContext->BaudRateIndex = NewBmmData->COMBaudRate[Index];
+ ASSERT (NewBmmData->COMBaudRate[Index] < (sizeof (BaudRateList) / sizeof (BaudRateList[0])));
+ NewTerminalContext->BaudRate = BaudRateList[NewBmmData->COMBaudRate[Index]].Value;
+ NewTerminalContext->DataBitsIndex = NewBmmData->COMDataRate[Index];
+ ASSERT (NewBmmData->COMDataRate[Index] < (sizeof (DataBitsList) / sizeof (DataBitsList[0])));
+ NewTerminalContext->DataBits = (UINT8) DataBitsList[NewBmmData->COMDataRate[Index]].Value;
+ NewTerminalContext->StopBitsIndex = NewBmmData->COMStopBits[Index];
+ ASSERT (NewBmmData->COMStopBits[Index] < (sizeof (StopBitsList) / sizeof (StopBitsList[0])));
+ NewTerminalContext->StopBits = (UINT8) StopBitsList[NewBmmData->COMStopBits[Index]].Value;
+ NewTerminalContext->ParityIndex = NewBmmData->COMParity[Index];
+ ASSERT (NewBmmData->COMParity[Index] < (sizeof (ParityList) / sizeof (ParityList[0])));
+ NewTerminalContext->Parity = (UINT8) ParityList[NewBmmData->COMParity[Index]].Value;
+ NewTerminalContext->TerminalType = NewBmmData->COMTerminalType[Index];
+ NewTerminalContext->FlowControl = NewBmmData->COMFlowControl[Index];
+ ChangeTerminalDevicePath (
+ &(NewTerminalContext->DevicePath),
+ FALSE
+ );
+ TerminalAttChange = TRUE;
+ }
+ if (TerminalAttChange) {
+ Var_UpdateConsoleInpOption ();
+ Var_UpdateConsoleOutOption ();
+ Var_UpdateErrorOutOption ();
+ }
+
+ //
+ // Check data which located in Console Options Menu and save the settings if need
+ //
+ if (CompareMem (NewBmmData->ConsoleInCheck, OldBmmData->ConsoleInCheck, sizeof (NewBmmData->ConsoleInCheck)) != 0) {
+ for (Index = 0; Index < ConsoleInpMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index < MAX_MENU_NUMBER);
+ NewConsoleContext->IsActive = NewBmmData->ConsoleInCheck[Index];
+ }
+
+ Var_UpdateConsoleInpOption ();
+ }
+
+ if (CompareMem (NewBmmData->ConsoleOutCheck, OldBmmData->ConsoleOutCheck, sizeof (NewBmmData->ConsoleOutCheck)) != 0) {
+ for (Index = 0; Index < ConsoleOutMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index < MAX_MENU_NUMBER);
+ NewConsoleContext->IsActive = NewBmmData->ConsoleOutCheck[Index];
+ }
+
+ Var_UpdateConsoleOutOption ();
+ }
+
+ if (CompareMem (NewBmmData->ConsoleErrCheck, OldBmmData->ConsoleErrCheck, sizeof (NewBmmData->ConsoleErrCheck)) != 0) {
+ for (Index = 0; Index < ConsoleErrMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ASSERT (Index < MAX_MENU_NUMBER);
+ NewConsoleContext->IsActive = NewBmmData->ConsoleErrCheck[Index];
+ }
+
+ Var_UpdateErrorOutOption ();
+ }
+
+ //
+ // After user do the save action, need to update OldBmmData.
+ //
+ CopyMem (OldBmmData, NewBmmData, sizeof (BMM_FAKE_NV_DATA));
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create GoTo OP code into FORM_BOOT_LEGACY_DEVICE label for legacy boot option.
+
+**/
+EFI_STATUS
+InitializeLegacyBootOption (
+ VOID
+ )
+{
+ RefreshUpdateData ();
+ mStartLabel->Number = FORM_BOOT_LEGACY_DEVICE_ID;
+
+ //
+ // If LegacyBios Protocol is installed, add 3 tags about legacy boot option
+ // in BootOption form: legacy FD/HD/CD/NET/BEV
+ //
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_SET_FD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_FD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_FD_ORDER_ID
+ );
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_SET_HD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_HD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_HD_ORDER_ID
+ );
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_SET_CD_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_CD_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_CD_ORDER_ID
+ );
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_SET_NET_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_NET_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_NET_ORDER_ID
+ );
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_SET_BEV_ORDER_ID,
+ STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
+ STRING_TOKEN (STR_FORM_SET_BEV_ORDER_TITLE),
+ EFI_IFR_FLAG_CALLBACK,
+ FORM_SET_BEV_ORDER_ID
+ );
+
+ HiiUpdateForm (
+ mBmmCallbackInfo->BmmHiiHandle,
+ &gBootMaintFormSetGuid,
+ FORM_BOOT_SETUP_ID,
+ mStartOpCodeHandle, // Label FORM_BOOT_LEGACY_DEVICE_ID
+ mEndOpCodeHandle // LABEL_END
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
+ @retval EFI_INVALID_PARAMETER The parameter of Value or ActionRequest is invalid.
+**/
+EFI_STATUS
+EFIAPI
+BootMaintCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ BMM_CALLBACK_DATA *Private;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BMM_FAKE_NV_DATA *CurrentFakeNVMap;
+ EFI_STATUS Status;
+ UINTN OldValue;
+ UINTN NewValue;
+ UINTN Number;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 NewValuePos;
+ UINT16 Index3;
+ UINT16 Index2;
+ UINT16 Index;
+ UINT8 *OldLegacyDev;
+ UINT8 *NewLegacyDev;
+ UINT8 *DisMap;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+ if (Action == EFI_BROWSER_ACTION_FORM_OPEN && QuestionId == FORM_BOOT_SETUP_ID) {
+ //
+ // Initilize Form for legacy boot option.
+ //
+ Status = EfiLibLocateProtocol (&gEfiLegacyBiosProtocolGuid, (VOID **) &LegacyBios);
+ if (!EFI_ERROR (Status)) {
+ InitializeLegacyBootOption ();
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+ OldValue = 0;
+ NewValue = 0;
+ Number = 0;
+ OldLegacyDev = NULL;
+ NewLegacyDev = NULL;
+ NewValuePos = 0;
+ DisMap = NULL;
+
+ Private = BMM_CALLBACK_DATA_FROM_THIS (This);
+ //
+ // Retrive uncommitted data from Form Browser
+ //
+ CurrentFakeNVMap = &Private->BmmFakeNvData;
+ HiiGetBrowserData (&gBootMaintFormSetGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap);
+ if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UpdatePageId (Private, QuestionId);
+
+ if (QuestionId < FILE_OPTION_OFFSET) {
+ if (QuestionId < CONFIG_OPTION_OFFSET) {
+ switch (QuestionId) {
+ case KEY_VALUE_BOOT_FROM_FILE:
+ Private->FeCurrentState = FileExplorerStateBootFromFile;
+ break;
+
+ case FORM_BOOT_ADD_ID:
+ Private->FeCurrentState = FileExplorerStateAddBootOption;
+ break;
+
+ case FORM_DRV_ADD_FILE_ID:
+ Private->FeCurrentState = FileExplorerStateAddDriverOptionState;
+ break;
+
+ case FORM_DRV_ADD_HANDLE_ID:
+ CleanUpPage (FORM_DRV_ADD_HANDLE_ID, Private);
+ UpdateDrvAddHandlePage (Private);
+ break;
+
+ case FORM_BOOT_DEL_ID:
+ CleanUpPage (FORM_BOOT_DEL_ID, Private);
+ UpdateBootDelPage (Private);
+ break;
+
+ case FORM_BOOT_CHG_ID:
+ case FORM_DRV_CHG_ID:
+ UpdatePageBody (QuestionId, Private);
+ break;
+
+ case FORM_DRV_DEL_ID:
+ CleanUpPage (FORM_DRV_DEL_ID, Private);
+ UpdateDrvDelPage (Private);
+ break;
+
+ case FORM_BOOT_NEXT_ID:
+ CleanUpPage (FORM_BOOT_NEXT_ID, Private);
+ UpdateBootNextPage (Private);
+ break;
+
+ case FORM_TIME_OUT_ID:
+ CleanUpPage (FORM_TIME_OUT_ID, Private);
+ UpdateTimeOutPage (Private);
+ break;
+
+ case FORM_CON_IN_ID:
+ case FORM_CON_OUT_ID:
+ case FORM_CON_ERR_ID:
+ UpdatePageBody (QuestionId, Private);
+ break;
+
+ case FORM_CON_MODE_ID:
+ CleanUpPage (FORM_CON_MODE_ID, Private);
+ UpdateConModePage (Private);
+ break;
+
+ case FORM_CON_COM_ID:
+ CleanUpPage (FORM_CON_COM_ID, Private);
+ UpdateConCOMPage (Private);
+ break;
+
+ case FORM_SET_FD_ORDER_ID:
+ case FORM_SET_HD_ORDER_ID:
+ case FORM_SET_CD_ORDER_ID:
+ case FORM_SET_NET_ORDER_ID:
+ case FORM_SET_BEV_ORDER_ID:
+ CleanUpPage (QuestionId, Private);
+ UpdateSetLegacyDeviceOrderPage (QuestionId, Private);
+ break;
+
+ default:
+ break;
+ }
+ } else if ((QuestionId >= TERMINAL_OPTION_OFFSET) && (QuestionId < CONSOLE_OPTION_OFFSET)) {
+ Index2 = (UINT16) (QuestionId - TERMINAL_OPTION_OFFSET);
+ Private->CurrentTerminal = Index2;
+
+ CleanUpPage (FORM_CON_COM_SETUP_ID, Private);
+ UpdateTerminalPage (Private);
+
+ } else if (QuestionId >= HANDLE_OPTION_OFFSET) {
+ Index2 = (UINT16) (QuestionId - HANDLE_OPTION_OFFSET);
+
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index2);
+ ASSERT (NewMenuEntry != NULL);
+ Private->HandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ CleanUpPage (FORM_DRV_ADD_HANDLE_DESC_ID, Private);
+
+ Private->MenuEntry = NewMenuEntry;
+ Private->LoadContext->FilePathList = Private->HandleContext->DevicePath;
+
+ UpdateDriverAddHandleDescPage (Private);
+ }
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ if ((QuestionId >= BOOT_OPTION_DEL_QUESTION_ID) && (QuestionId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
+ if (Value->b){
+ //
+ // Means user try to delete this boot option but not press F10 or "Commit Changes and Exit" menu.
+ //
+ CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = TRUE;
+ } else {
+ //
+ // Means user remove the old check status.
+ //
+ CurrentFakeNVMap->BootOptionDelMark[QuestionId - BOOT_OPTION_DEL_QUESTION_ID] = FALSE;
+ }
+ } else if ((QuestionId >= DRIVER_OPTION_DEL_QUESTION_ID) && (QuestionId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) {
+ if (Value->b){
+ CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = TRUE;
+ } else {
+ CurrentFakeNVMap->DriverOptionDelMark[QuestionId - DRIVER_OPTION_DEL_QUESTION_ID] = FALSE;
+ }
+ } else if ((QuestionId >= LEGACY_FD_QUESTION_ID) && (QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER)) {
+ //
+ // Update Select FD/HD/CD/NET/BEV Order Form
+ //
+
+ DisMap = Private->BmmOldFakeNVData.DisableMap;
+
+ if (QuestionId >= LEGACY_FD_QUESTION_ID && QuestionId < LEGACY_FD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyFDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyFD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyFD;
+ } else if (QuestionId >= LEGACY_HD_QUESTION_ID && QuestionId < LEGACY_HD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyHDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyHD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyHD;
+ } else if (QuestionId >= LEGACY_CD_QUESTION_ID && QuestionId < LEGACY_CD_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyCDMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyCD;
+ NewLegacyDev = CurrentFakeNVMap->LegacyCD;
+ } else if (QuestionId >= LEGACY_NET_QUESTION_ID && QuestionId < LEGACY_NET_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyNETMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyNET;
+ NewLegacyDev = CurrentFakeNVMap->LegacyNET;
+ } else if (QuestionId >= LEGACY_BEV_QUESTION_ID && QuestionId < LEGACY_BEV_QUESTION_ID + MAX_MENU_NUMBER) {
+ Number = (UINT16) LegacyBEVMenu.MenuNumber;
+ OldLegacyDev = Private->BmmOldFakeNVData.LegacyBEV;
+ NewLegacyDev = CurrentFakeNVMap->LegacyBEV;
+ }
+ //
+ // First, find the different position
+ // if there is change, it should be only one
+ //
+ for (Index = 0; Index < Number; Index++) {
+ if (OldLegacyDev[Index] != NewLegacyDev[Index]) {
+ OldValue = OldLegacyDev[Index];
+ NewValue = NewLegacyDev[Index];
+ break;
+ }
+ }
+
+ if (Index != Number) {
+ //
+ // there is change, now process
+ //
+ if (0xFF == NewValue) {
+ //
+ // This item will be disable
+ // Just move the items behind this forward to overlap it
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ for (Index2 = Index; Index2 < Number - 1; Index2++) {
+ NewLegacyDev[Index2] = NewLegacyDev[Index2 + 1];
+ }
+
+ NewLegacyDev[Index2] = 0xFF;
+ } else {
+ for (Index2 = 0; Index2 < Number; Index2++) {
+ if (Index2 == Index) {
+ continue;
+ }
+
+ if (OldLegacyDev[Index2] == NewValue) {
+ //
+ // If NewValue is in OldLegacyDev array
+ // remember its old position
+ //
+ NewValuePos = Index2;
+ break;
+ }
+ }
+
+ if (Index2 != Number) {
+ //
+ // We will change current item to an existing item
+ // (It's hard to describe here, please read code, it's like a cycle-moving)
+ //
+ for (Index2 = NewValuePos; Index2 != Index;) {
+ if (NewValuePos < Index) {
+ NewLegacyDev[Index2] = OldLegacyDev[Index2 + 1];
+ Index2++;
+ } else {
+ NewLegacyDev[Index2] = OldLegacyDev[Index2 - 1];
+ Index2--;
+ }
+ }
+ } else {
+ //
+ // If NewValue is not in OldlegacyDev array, we are changing to a disabled item
+ // so we should modify DisMap to reflect the change
+ //
+ Pos = NewValue / 8;
+ Bit = 7 - (NewValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] & (~ (UINT8) (1 << Bit)));
+ if (0xFF != OldValue) {
+ //
+ // Because NewValue is a item that was disabled before
+ // so after changing the OldValue should be disabled
+ // actually we are doing a swap of enable-disable states of two items
+ //
+ Pos = OldValue / 8;
+ Bit = 7 - (OldValue % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ }
+ }
+ }
+ //
+ // To prevent DISABLE appears in the middle of the list
+ // we should perform a re-ordering
+ //
+ Index3 = Index;
+ Index = 0;
+ while (Index < Number) {
+ if (0xFF != NewLegacyDev[Index]) {
+ Index++;
+ continue;
+ }
+
+ Index2 = Index;
+ Index2++;
+ while (Index2 < Number) {
+ if (0xFF != NewLegacyDev[Index2]) {
+ break;
+ }
+
+ Index2++;
+ }
+
+ if (Index2 < Number) {
+ NewLegacyDev[Index] = NewLegacyDev[Index2];
+ NewLegacyDev[Index2] = 0xFF;
+ }
+
+ Index++;
+ }
+
+ //
+ // Return correct question value.
+ //
+ Value->u8 = NewLegacyDev[Index3];
+ }
+ } else {
+ switch (QuestionId) {
+ case KEY_VALUE_SAVE_AND_EXIT:
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_SUBMIT_EXIT;
+ break;
+
+ case KEY_VALUE_NO_SAVE_AND_EXIT:
+ //
+ // Restore local maintain data.
+ //
+ DiscardChangeHandler (Private, CurrentFakeNVMap);
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_FORM_DISCARD_EXIT;
+ break;
+
+ case FORM_RESET:
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+ return EFI_UNSUPPORTED;
+
+ default:
+ break;
+ }
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ HiiSetBrowserData (&gBootMaintFormSetGuid, mBootMaintStorageName, sizeof (BMM_FAKE_NV_DATA), (UINT8 *) CurrentFakeNVMap, NULL);
+ return EFI_SUCCESS;
+}
+
+/**
+ Discard all changes done to the BMM pages such as Boot Order change,
+ Driver order change.
+
+ @param Private The BMM context data.
+ @param CurrentFakeNVMap The current Fack NV Map.
+
+**/
+VOID
+DiscardChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap
+ )
+{
+ UINT16 Index;
+
+ switch (Private->BmmPreviousPageId) {
+ case FORM_BOOT_CHG_ID:
+ CopyMem (CurrentFakeNVMap->BootOptionOrder, Private->BmmOldFakeNVData.BootOptionOrder, sizeof (CurrentFakeNVMap->BootOptionOrder));
+ break;
+
+ case FORM_DRV_CHG_ID:
+ CopyMem (CurrentFakeNVMap->DriverOptionOrder, Private->BmmOldFakeNVData.DriverOptionOrder, sizeof (CurrentFakeNVMap->DriverOptionOrder));
+ break;
+
+ case FORM_BOOT_DEL_ID:
+ ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->BootOptionDel) / sizeof (CurrentFakeNVMap->BootOptionDel[0])));
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ CurrentFakeNVMap->BootOptionDel[Index] = FALSE;
+ CurrentFakeNVMap->BootOptionDelMark[Index] = FALSE;
+ }
+ break;
+
+ case FORM_DRV_DEL_ID:
+ ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CurrentFakeNVMap->DriverOptionDel) / sizeof (CurrentFakeNVMap->DriverOptionDel[0])));
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ CurrentFakeNVMap->DriverOptionDel[Index] = FALSE;
+ CurrentFakeNVMap->DriverOptionDelMark[Index] = FALSE;
+ }
+ break;
+
+ case FORM_BOOT_NEXT_ID:
+ CurrentFakeNVMap->BootNext = Private->BmmOldFakeNVData.BootNext;
+ break;
+
+ case FORM_TIME_OUT_ID:
+ CurrentFakeNVMap->BootTimeOut = Private->BmmOldFakeNVData.BootTimeOut;
+ break;
+
+ case FORM_DRV_ADD_HANDLE_DESC_ID:
+ case FORM_DRV_ADD_FILE_ID:
+ case FORM_DRV_ADD_HANDLE_ID:
+ CurrentFakeNVMap->DriverAddHandleDesc[0] = 0x0000;
+ CurrentFakeNVMap->DriverAddHandleOptionalData[0] = 0x0000;
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Initialize the Boot Maintenance Utitliy.
+
+
+ @retval EFI_SUCCESS utility ended successfully
+ @retval others contain some errors
+
+**/
+EFI_STATUS
+InitializeBM (
+ VOID
+ )
+{
+ BMM_CALLBACK_DATA *BmmCallbackInfo;
+ EFI_STATUS Status;
+ EFI_HII_PACKAGE_LIST_HEADER *PackageListHeader;
+ UINT32 Length;
+ UINT8 *Data;
+
+ Status = EFI_SUCCESS;
+ BmmCallbackInfo = mBmmCallbackInfo;
+
+ BmmCallbackInfo->BmmPreviousPageId = FORM_MAIN_ID;
+ BmmCallbackInfo->BmmCurrentPageId = FORM_MAIN_ID;
+ BmmCallbackInfo->FeCurrentState = FileExplorerStateInActive;
+ BmmCallbackInfo->FeDisplayContext = FileExplorerDisplayUnknown;
+
+ //
+ // Reinstall String packages to include more new strings.
+ //
+
+ //
+ // String package size
+ //
+ Length = ReadUnaligned32 ((UINT32 *) BdsDxeStrings) - sizeof (UINT32);
+
+ //
+ // Add the length of the Package List Header and the terminating Package Header
+ //
+ Length += sizeof (EFI_HII_PACKAGE_LIST_HEADER) + sizeof (EFI_HII_PACKAGE_HEADER);
+
+ //
+ // Allocate the storage for the entire Package List
+ //
+ PackageListHeader = AllocateZeroPool (Length);
+
+ //
+ // If the Package List can not be allocated, then return a NULL HII Handle
+ //
+ if (PackageListHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Fill in the GUID and Length of the Package List Header
+ //
+ PackageListHeader->PackageLength = Length;
+
+ //
+ // Copy String Data into Package list.
+ //
+ Data = (UINT8 *)(PackageListHeader + 1);
+ Length = ReadUnaligned32 ((UINT32 *) BdsDxeStrings) - sizeof (UINT32);
+ CopyMem (Data, (UINT8 *) BdsDxeStrings + sizeof (UINT32), Length);
+
+ //
+ // Add End type HII package.
+ //
+ Data += Length;
+ ((EFI_HII_PACKAGE_HEADER *) Data)->Type = EFI_HII_PACKAGE_END;
+ ((EFI_HII_PACKAGE_HEADER *) Data)->Length = sizeof (EFI_HII_PACKAGE_HEADER);
+
+ //
+ // Update String package for BM
+ //
+ CopyGuid (&PackageListHeader->PackageListGuid, &gBootMaintFormSetGuid);
+ Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, BmmCallbackInfo->BmmHiiHandle, PackageListHeader);
+
+ //
+ // Update String package for FE.
+ //
+ CopyGuid (&PackageListHeader->PackageListGuid, &gFileExploreFormSetGuid);
+ Status = gHiiDatabase->UpdatePackageList (gHiiDatabase, BmmCallbackInfo->FeHiiHandle, PackageListHeader);
+
+ FreePool (PackageListHeader);
+
+ //
+ // Init OpCode Handle and Allocate space for creation of Buffer
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (mStartOpCodeHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ mEndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ if (mEndOpCodeHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Exit;
+ }
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (mStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ mEndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (mEndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ mEndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ mEndLabel->Number = LABEL_END;
+
+ InitializeStringDepository ();
+
+ InitAllMenu (BmmCallbackInfo);
+
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleInpMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleOutMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &ConsoleErrMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &BootOptionMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverOptionMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &TerminalMenu);
+ CreateMenuStringToken (BmmCallbackInfo, BmmCallbackInfo->BmmHiiHandle, &DriverMenu);
+
+ InitializeBmmConfig (BmmCallbackInfo);
+
+ //
+ // Dispatch BMM main formset and File Explorer formset.
+ //
+ FormSetDispatcher (BmmCallbackInfo);
+
+ //
+ // Clean up.
+ //
+ CleanUpStringDepository ();
+
+ FreeAllMenu ();
+
+Exit:
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ if (mEndOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mEndOpCodeHandle);
+ }
+
+ return Status;
+}
+
+
+/**
+ Initialized all Menu Option List.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+InitAllMenu (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ InitializeListHead (&BootOptionMenu.Head);
+ InitializeListHead (&DriverOptionMenu.Head);
+ BOpt_GetBootOptions (CallbackData);
+ BOpt_GetDriverOptions (CallbackData);
+ BOpt_GetLegacyOptions ();
+ InitializeListHead (&FsOptionMenu.Head);
+ BOpt_FindDrivers ();
+ InitializeListHead (&DirectoryMenu.Head);
+ InitializeListHead (&ConsoleInpMenu.Head);
+ InitializeListHead (&ConsoleOutMenu.Head);
+ InitializeListHead (&ConsoleErrMenu.Head);
+ InitializeListHead (&TerminalMenu.Head);
+ LocateSerialIo ();
+ GetAllConsoles ();
+}
+
+/**
+ Free up all Menu Option list.
+
+**/
+VOID
+FreeAllMenu (
+ VOID
+ )
+{
+ BOpt_FreeMenu (&DirectoryMenu);
+ BOpt_FreeMenu (&FsOptionMenu);
+ BOpt_FreeMenu (&BootOptionMenu);
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_FreeMenu (&DriverMenu);
+ BOpt_FreeLegacyOptions ();
+ FreeAllConsoles ();
+}
+
+/**
+ Initialize all the string depositories.
+
+**/
+VOID
+InitializeStringDepository (
+ VOID
+ )
+{
+ STRING_DEPOSITORY *StringDepository;
+ StringDepository = AllocateZeroPool (sizeof (STRING_DEPOSITORY) * STRING_DEPOSITORY_NUMBER);
+ FileOptionStrDepository = StringDepository++;
+ ConsoleOptionStrDepository = StringDepository++;
+ BootOptionStrDepository = StringDepository++;
+ BootOptionHelpStrDepository = StringDepository++;
+ DriverOptionStrDepository = StringDepository++;
+ DriverOptionHelpStrDepository = StringDepository++;
+ TerminalStrDepository = StringDepository;
+}
+
+/**
+ Fetch a usable string node from the string depository and return the string token.
+
+ @param CallbackData The BMM context data.
+ @param StringDepository The string repository.
+
+ @retval EFI_STRING_ID String token.
+
+**/
+EFI_STRING_ID
+GetStringTokenFromDepository (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN STRING_DEPOSITORY *StringDepository
+ )
+{
+ STRING_LIST_NODE *CurrentListNode;
+ STRING_LIST_NODE *NextListNode;
+
+ CurrentListNode = StringDepository->CurrentNode;
+
+ if ((NULL != CurrentListNode) && (NULL != CurrentListNode->Next)) {
+ //
+ // Fetch one reclaimed node from the list.
+ //
+ NextListNode = StringDepository->CurrentNode->Next;
+ } else {
+ //
+ // If there is no usable node in the list, update the list.
+ //
+ NextListNode = AllocateZeroPool (sizeof (STRING_LIST_NODE));
+ ASSERT (NextListNode != NULL);
+ NextListNode->StringToken = HiiSetString (CallbackData->BmmHiiHandle, 0, L" ", NULL);
+ ASSERT (NextListNode->StringToken != 0);
+
+ StringDepository->TotalNodeNumber++;
+
+ if (NULL == CurrentListNode) {
+ StringDepository->ListHead = NextListNode;
+ } else {
+ CurrentListNode->Next = NextListNode;
+ }
+ }
+
+ StringDepository->CurrentNode = NextListNode;
+
+ return StringDepository->CurrentNode->StringToken;
+}
+
+/**
+ Reclaim string depositories by moving the current node pointer to list head..
+
+**/
+VOID
+ReclaimStringDepository (
+ VOID
+ )
+{
+ UINTN DepositoryIndex;
+ STRING_DEPOSITORY *StringDepository;
+
+ StringDepository = FileOptionStrDepository;
+ for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
+ StringDepository->CurrentNode = StringDepository->ListHead;
+ StringDepository++;
+ }
+}
+
+/**
+ Release resource for all the string depositories.
+
+**/
+VOID
+CleanUpStringDepository (
+ VOID
+ )
+{
+ UINTN NodeIndex;
+ UINTN DepositoryIndex;
+ STRING_LIST_NODE *CurrentListNode;
+ STRING_LIST_NODE *NextListNode;
+ STRING_DEPOSITORY *StringDepository;
+
+ //
+ // Release string list nodes.
+ //
+ StringDepository = FileOptionStrDepository;
+ for (DepositoryIndex = 0; DepositoryIndex < STRING_DEPOSITORY_NUMBER; DepositoryIndex++) {
+ CurrentListNode = StringDepository->ListHead;
+ for (NodeIndex = 0; NodeIndex < StringDepository->TotalNodeNumber; NodeIndex++) {
+ NextListNode = CurrentListNode->Next;
+ FreePool (CurrentListNode);
+ CurrentListNode = NextListNode;
+ }
+
+ StringDepository++;
+ }
+ //
+ // Release string depository.
+ //
+ FreePool (FileOptionStrDepository);
+}
+
+/**
+ Start boot maintenance manager
+
+ @retval EFI_SUCCESS If BMM is invoked successfully.
+ @return Other value if BMM return unsuccessfully.
+
+**/
+EFI_STATUS
+BdsStartBootMaint (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ LIST_ENTRY BdsBootOptionList;
+
+ InitializeListHead (&BdsBootOptionList);
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+ //
+ // Have chance to enumerate boot device
+ //
+ BdsLibEnumerateAllBootOption (&BdsBootOptionList);
+
+ //
+ // Group the legacy boot options for the same device type
+ //
+ GroupMultipleLegacyBootOption4SameType ();
+
+ //
+ // Init the BMM
+ //
+ Status = InitializeBM ();
+
+ return Status;
+}
+
+/**
+ Dispatch BMM formset and FileExplorer formset.
+
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS If function complete successfully.
+ @return Other value if the Setup Browser process BMM's pages and
+ return unsuccessfully.
+
+**/
+EFI_STATUS
+FormSetDispatcher (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ while (TRUE) {
+ UpdatePageId (CallbackData, FORM_MAIN_ID);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &CallbackData->BmmHiiHandle,
+ 1,
+ &gBootMaintFormSetGuid,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ ReclaimStringDepository ();
+
+ //
+ // When this Formset returns, check if we are going to explore files.
+ //
+ if (FileExplorerStateInActive != CallbackData->FeCurrentState) {
+ UpdateFileExplorer (CallbackData, 0);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &CallbackData->FeHiiHandle,
+ 1,
+ &gFileExploreFormSetGuid,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ CallbackData->FeCurrentState = FileExplorerStateInActive;
+ CallbackData->FeDisplayContext = FileExplorerDisplayUnknown;
+ ReclaimStringDepository ();
+ } else {
+ break;
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Intall BootMaint and FileExplorer HiiPackages.
+
+**/
+EFI_STATUS
+InitBMPackage (
+ VOID
+ )
+{
+ BMM_CALLBACK_DATA *BmmCallbackInfo;
+ EFI_STATUS Status;
+ UINT8 *Ptr;
+
+ //
+ // Create CallbackData structures for Driver Callback
+ //
+ BmmCallbackInfo = AllocateZeroPool (sizeof (BMM_CALLBACK_DATA));
+ if (BmmCallbackInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Create LoadOption in BmmCallbackInfo for Driver Callback
+ //
+ Ptr = AllocateZeroPool (sizeof (BM_LOAD_CONTEXT) + sizeof (BM_FILE_CONTEXT) + sizeof (BM_HANDLE_CONTEXT) + sizeof (BM_MENU_ENTRY));
+ if (Ptr == NULL) {
+ FreePool (BmmCallbackInfo);
+ BmmCallbackInfo = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize Bmm callback data.
+ //
+ BmmCallbackInfo->LoadContext = (BM_LOAD_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_LOAD_CONTEXT);
+
+ BmmCallbackInfo->FileContext = (BM_FILE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_FILE_CONTEXT);
+
+ BmmCallbackInfo->HandleContext = (BM_HANDLE_CONTEXT *) Ptr;
+ Ptr += sizeof (BM_HANDLE_CONTEXT);
+
+ BmmCallbackInfo->MenuEntry = (BM_MENU_ENTRY *) Ptr;
+
+ BmmCallbackInfo->Signature = BMM_CALLBACK_DATA_SIGNATURE;
+ BmmCallbackInfo->BmmConfigAccess.ExtractConfig = BootMaintExtractConfig;
+ BmmCallbackInfo->BmmConfigAccess.RouteConfig = BootMaintRouteConfig;
+ BmmCallbackInfo->BmmConfigAccess.Callback = BootMaintCallback;
+ BmmCallbackInfo->FeConfigAccess.ExtractConfig = FakeExtractConfig;
+ BmmCallbackInfo->FeConfigAccess.RouteConfig = FileExplorerRouteConfig;
+ BmmCallbackInfo->FeConfigAccess.Callback = FileExplorerCallback;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BmmCallbackInfo->BmmDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBmmHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &BmmCallbackInfo->BmmConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &BmmCallbackInfo->FeDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mFeHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &BmmCallbackInfo->FeConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Post our Boot Maint VFR binary to the HII database.
+ //
+ BmmCallbackInfo->BmmHiiHandle = HiiAddPackages (
+ &gBootMaintFormSetGuid,
+ BmmCallbackInfo->BmmDriverHandle,
+ BmBin,
+ BdsDxeStrings,
+ NULL
+ );
+ ASSERT (BmmCallbackInfo->BmmHiiHandle != NULL);
+
+ //
+ // Post our File Explorer VFR binary to the HII database.
+ //
+ BmmCallbackInfo->FeHiiHandle = HiiAddPackages (
+ &gFileExploreFormSetGuid,
+ BmmCallbackInfo->FeDriverHandle,
+ FEBin,
+ BdsDxeStrings,
+ NULL
+ );
+ ASSERT (BmmCallbackInfo->FeHiiHandle != NULL);
+
+ mBmmCallbackInfo = BmmCallbackInfo;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remvoe the intalled BootMaint and FileExplorer HiiPackages.
+
+**/
+VOID
+FreeBMPackage (
+ VOID
+ )
+{
+ BMM_CALLBACK_DATA *BmmCallbackInfo;
+
+ BmmCallbackInfo = mBmmCallbackInfo;
+
+ //
+ // Remove our IFR data from HII database
+ //
+ HiiRemovePackages (BmmCallbackInfo->BmmHiiHandle);
+ HiiRemovePackages (BmmCallbackInfo->FeHiiHandle);
+
+ if (BmmCallbackInfo->FeDriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ BmmCallbackInfo->FeDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mFeHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &BmmCallbackInfo->FeConfigAccess,
+ NULL
+ );
+ }
+
+ if (BmmCallbackInfo->BmmDriverHandle != NULL) {
+ gBS->UninstallMultipleProtocolInterfaces (
+ BmmCallbackInfo->BmmDriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBmmHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &BmmCallbackInfo->BmmConfigAccess,
+ NULL
+ );
+ }
+
+ FreePool (BmmCallbackInfo->LoadContext);
+ FreePool (BmmCallbackInfo);
+
+ mBmmCallbackInfo = NULL;
+
+ return;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h
new file mode 100644
index 0000000000..098692fa53
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootMaint.h
@@ -0,0 +1,1679 @@
+/** @file
+ Header file for boot maintenance module.
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _BOOT_MAINT_H_
+#define _BOOT_MAINT_H_
+
+#include "Bds.h"
+#include "BBSsupport.h"
+#include "FormGuid.h"
+#include "FrontPage.h"
+
+//
+// Constants which are variable names used to access variables
+//
+#define VAR_CON_OUT_MODE L"ConOutMode"
+
+//
+// String Contant
+//
+#define STR_FLOPPY L"Floppy Drive #%02x"
+#define STR_HARDDISK L"HardDisk Drive #%02x"
+#define STR_CDROM L"ATAPI CDROM Drive #%02x"
+#define STR_NET L"NET Drive #%02x"
+#define STR_BEV L"BEV Drive #%02x"
+#define STR_FLOPPY_HELP L"Select Floppy Drive #%02x"
+#define STR_HARDDISK_HELP L"Select HardDisk Drive #%02x"
+#define STR_CDROM_HELP L"Select ATAPI CDROM Drive #%02x"
+#define STR_NET_HELP L"NET Drive #%02x"
+#define STR_BEV_HELP L"BEV Drive #%02x"
+
+extern CHAR16 mFileExplorerStorageName[];
+extern CHAR16 mBootMaintStorageName[];
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 BmBin[];
+extern UINT8 FEBin[];
+
+//
+// Below are the number of options in Baudrate, Databits,
+// Parity and Stopbits selection for serial ports.
+//
+#define BM_COM_ATTR_BUADRATE 19
+#define BM_COM_ATTR_DATABITS 4
+#define BM_COM_ATTR_PARITY 5
+#define BM_COM_ATTR_STOPBITS 3
+
+//
+// Callback function helper
+//
+#define BMM_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('C', 'b', 'c', 'k')
+#define BMM_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, BmmConfigAccess, BMM_CALLBACK_DATA_SIGNATURE)
+
+#define FE_CALLBACK_DATA_FROM_THIS(a) CR (a, BMM_CALLBACK_DATA, FeConfigAccess, BMM_CALLBACK_DATA_SIGNATURE)
+
+//
+// Enumeration type definition
+//
+typedef enum _TYPE_OF_TERMINAL {
+ TerminalTypePcAnsi = 0,
+ TerminalTypeVt100,
+ TerminalTypeVt100Plus,
+ TerminalTypeVtUtf8
+} TYPE_OF_TERMINAL;
+
+typedef enum _FILE_EXPLORER_STATE {
+ FileExplorerStateInActive = 0,
+ FileExplorerStateBootFromFile,
+ FileExplorerStateAddBootOption,
+ FileExplorerStateAddDriverOptionState,
+ FileExplorerStateUnknown
+} FILE_EXPLORER_STATE;
+
+typedef enum _FILE_EXPLORER_DISPLAY_CONTEXT {
+ FileExplorerDisplayFileSystem,
+ FileExplorerDisplayDirectory,
+ FileExplorerDisplayUnknown
+} FILE_EXPLORER_DISPLAY_CONTEXT;
+
+//
+// All of the signatures that will be used in list structure
+//
+#define BM_MENU_OPTION_SIGNATURE SIGNATURE_32 ('m', 'e', 'n', 'u')
+#define BM_LOAD_OPTION_SIGNATURE SIGNATURE_32 ('l', 'o', 'a', 'd')
+#define BM_CONSOLE_OPTION_SIGNATURE SIGNATURE_32 ('c', 'n', 's', 'l')
+#define BM_FILE_OPTION_SIGNATURE SIGNATURE_32 ('f', 'i', 'l', 'e')
+#define BM_HANDLE_OPTION_SIGNATURE SIGNATURE_32 ('h', 'n', 'd', 'l')
+#define BM_TERMINAL_OPTION_SIGNATURE SIGNATURE_32 ('t', 'r', 'm', 'l')
+#define BM_MENU_ENTRY_SIGNATURE SIGNATURE_32 ('e', 'n', 't', 'r')
+
+#define BM_LOAD_CONTEXT_SELECT 0x0
+#define BM_CONSOLE_CONTEXT_SELECT 0x1
+#define BM_FILE_CONTEXT_SELECT 0x2
+#define BM_HANDLE_CONTEXT_SELECT 0x3
+#define BM_TERMINAL_CONTEXT_SELECT 0x5
+
+#define BM_CONSOLE_IN_CONTEXT_SELECT 0x6
+#define BM_CONSOLE_OUT_CONTEXT_SELECT 0x7
+#define BM_CONSOLE_ERR_CONTEXT_SELECT 0x8
+#define BM_LEGACY_DEV_CONTEXT_SELECT 0x9
+
+//
+// Buffer size for update data
+//
+#define UPDATE_DATA_SIZE 0x100000
+
+//
+// Namespace of callback keys used in display and file system navigation
+//
+#define MAX_BBS_OFFSET 0xE000
+#define NET_OPTION_OFFSET 0xD800
+#define BEV_OPTION_OFFSET 0xD000
+#define FD_OPTION_OFFSET 0xC000
+#define HD_OPTION_OFFSET 0xB000
+#define CD_OPTION_OFFSET 0xA000
+#define FILE_OPTION_GOTO_OFFSET 0xC000
+#define FILE_OPTION_OFFSET 0x8000
+#define FILE_OPTION_MASK 0x3FFF
+#define HANDLE_OPTION_OFFSET 0x7000
+#define CONSOLE_OPTION_OFFSET 0x6000
+#define TERMINAL_OPTION_OFFSET 0x5000
+#define CONFIG_OPTION_OFFSET 0x1200
+#define KEY_VALUE_OFFSET 0x1100
+#define FORM_ID_OFFSET 0x1000
+
+//
+// VarOffset that will be used to create question
+// all these values are computed from the structure
+// defined below
+//
+#define VAR_OFFSET(Field) ((UINT16) ((UINTN) &(((BMM_FAKE_NV_DATA *) 0)->Field)))
+
+//
+// Question Id of Zero is invalid, so add an offset to it
+//
+#define QUESTION_ID(Field) (VAR_OFFSET (Field) + CONFIG_OPTION_OFFSET)
+
+#define BOOT_TIME_OUT_VAR_OFFSET VAR_OFFSET (BootTimeOut)
+#define BOOT_NEXT_VAR_OFFSET VAR_OFFSET (BootNext)
+#define COM1_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COM1BaudRate)
+#define COM1_DATA_RATE_VAR_OFFSET VAR_OFFSET (COM1DataRate)
+#define COM1_STOP_BITS_VAR_OFFSET VAR_OFFSET (COM1StopBits)
+#define COM1_PARITY_VAR_OFFSET VAR_OFFSET (COM1Parity)
+#define COM1_TERMINAL_VAR_OFFSET VAR_OFFSET (COM2TerminalType)
+#define COM2_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COM2BaudRate)
+#define COM2_DATA_RATE_VAR_OFFSET VAR_OFFSET (COM2DataRate)
+#define COM2_STOP_BITS_VAR_OFFSET VAR_OFFSET (COM2StopBits)
+#define COM2_PARITY_VAR_OFFSET VAR_OFFSET (COM2Parity)
+#define COM2_TERMINAL_VAR_OFFSET VAR_OFFSET (COM2TerminalType)
+#define DRV_ADD_HANDLE_DESC_VAR_OFFSET VAR_OFFSET (DriverAddHandleDesc)
+#define DRV_ADD_ACTIVE_VAR_OFFSET VAR_OFFSET (DriverAddActive)
+#define DRV_ADD_RECON_VAR_OFFSET VAR_OFFSET (DriverAddForceReconnect)
+#define CON_IN_COM1_VAR_OFFSET VAR_OFFSET (ConsoleInputCOM1)
+#define CON_IN_COM2_VAR_OFFSET VAR_OFFSET (ConsoleInputCOM2)
+#define CON_OUT_COM1_VAR_OFFSET VAR_OFFSET (ConsoleOutputCOM1)
+#define CON_OUT_COM2_VAR_OFFSET VAR_OFFSET (ConsoleOutputCOM2)
+#define CON_ERR_COM1_VAR_OFFSET VAR_OFFSET (ConsoleErrorCOM1)
+#define CON_ERR_COM2_VAR_OFFSET VAR_OFFSET (ConsoleErrorCOM2)
+#define CON_MODE_VAR_OFFSET VAR_OFFSET (ConsoleOutMode)
+#define CON_IN_DEVICE_VAR_OFFSET VAR_OFFSET (ConsoleInCheck)
+#define CON_OUT_DEVICE_VAR_OFFSET VAR_OFFSET (ConsoleOutCheck)
+#define CON_ERR_DEVICE_VAR_OFFSET VAR_OFFSET (ConsoleErrCheck)
+#define BOOT_OPTION_ORDER_VAR_OFFSET VAR_OFFSET (BootOptionOrder)
+#define DRIVER_OPTION_ORDER_VAR_OFFSET VAR_OFFSET (DriverOptionOrder)
+#define BOOT_OPTION_DEL_VAR_OFFSET VAR_OFFSET (BootOptionDel)
+#define DRIVER_OPTION_DEL_VAR_OFFSET VAR_OFFSET (DriverOptionDel)
+#define DRIVER_ADD_OPTION_VAR_OFFSET VAR_OFFSET (DriverAddHandleOptionalData)
+#define COM_BAUD_RATE_VAR_OFFSET VAR_OFFSET (COMBaudRate)
+#define COM_DATA_RATE_VAR_OFFSET VAR_OFFSET (COMDataRate)
+#define COM_STOP_BITS_VAR_OFFSET VAR_OFFSET (COMStopBits)
+#define COM_PARITY_VAR_OFFSET VAR_OFFSET (COMParity)
+#define COM_TERMINAL_VAR_OFFSET VAR_OFFSET (COMTerminalType)
+#define COM_FLOWCONTROL_VAR_OFFSET VAR_OFFSET (COMFlowControl)
+#define LEGACY_FD_VAR_OFFSET VAR_OFFSET (LegacyFD)
+#define LEGACY_HD_VAR_OFFSET VAR_OFFSET (LegacyHD)
+#define LEGACY_CD_VAR_OFFSET VAR_OFFSET (LegacyCD)
+#define LEGACY_NET_VAR_OFFSET VAR_OFFSET (LegacyNET)
+#define LEGACY_BEV_VAR_OFFSET VAR_OFFSET (LegacyBEV)
+
+#define BOOT_TIME_OUT_QUESTION_ID QUESTION_ID (BootTimeOut)
+#define BOOT_NEXT_QUESTION_ID QUESTION_ID (BootNext)
+#define COM1_BAUD_RATE_QUESTION_ID QUESTION_ID (COM1BaudRate)
+#define COM1_DATA_RATE_QUESTION_ID QUESTION_ID (COM1DataRate)
+#define COM1_STOP_BITS_QUESTION_ID QUESTION_ID (COM1StopBits)
+#define COM1_PARITY_QUESTION_ID QUESTION_ID (COM1Parity)
+#define COM1_TERMINAL_QUESTION_ID QUESTION_ID (COM2TerminalType)
+#define COM2_BAUD_RATE_QUESTION_ID QUESTION_ID (COM2BaudRate)
+#define COM2_DATA_RATE_QUESTION_ID QUESTION_ID (COM2DataRate)
+#define COM2_STOP_BITS_QUESTION_ID QUESTION_ID (COM2StopBits)
+#define COM2_PARITY_QUESTION_ID QUESTION_ID (COM2Parity)
+#define COM2_TERMINAL_QUESTION_ID QUESTION_ID (COM2TerminalType)
+#define DRV_ADD_HANDLE_DESC_QUESTION_ID QUESTION_ID (DriverAddHandleDesc)
+#define DRV_ADD_ACTIVE_QUESTION_ID QUESTION_ID (DriverAddActive)
+#define DRV_ADD_RECON_QUESTION_ID QUESTION_ID (DriverAddForceReconnect)
+#define CON_IN_COM1_QUESTION_ID QUESTION_ID (ConsoleInputCOM1)
+#define CON_IN_COM2_QUESTION_ID QUESTION_ID (ConsoleInputCOM2)
+#define CON_OUT_COM1_QUESTION_ID QUESTION_ID (ConsoleOutputCOM1)
+#define CON_OUT_COM2_QUESTION_ID QUESTION_ID (ConsoleOutputCOM2)
+#define CON_ERR_COM1_QUESTION_ID QUESTION_ID (ConsoleErrorCOM1)
+#define CON_ERR_COM2_QUESTION_ID QUESTION_ID (ConsoleErrorCOM2)
+#define CON_MODE_QUESTION_ID QUESTION_ID (ConsoleOutMode)
+#define CON_IN_DEVICE_QUESTION_ID QUESTION_ID (ConsoleInCheck)
+#define CON_OUT_DEVICE_QUESTION_ID QUESTION_ID (ConsoleOutCheck)
+#define CON_ERR_DEVICE_QUESTION_ID QUESTION_ID (ConsoleErrCheck)
+#define BOOT_OPTION_ORDER_QUESTION_ID QUESTION_ID (BootOptionOrder)
+#define DRIVER_OPTION_ORDER_QUESTION_ID QUESTION_ID (DriverOptionOrder)
+#define BOOT_OPTION_DEL_QUESTION_ID QUESTION_ID (BootOptionDel)
+#define DRIVER_OPTION_DEL_QUESTION_ID QUESTION_ID (DriverOptionDel)
+#define DRIVER_ADD_OPTION_QUESTION_ID QUESTION_ID (DriverAddHandleOptionalData)
+#define COM_BAUD_RATE_QUESTION_ID QUESTION_ID (COMBaudRate)
+#define COM_DATA_RATE_QUESTION_ID QUESTION_ID (COMDataRate)
+#define COM_STOP_BITS_QUESTION_ID QUESTION_ID (COMStopBits)
+#define COM_PARITY_QUESTION_ID QUESTION_ID (COMParity)
+#define COM_TERMINAL_QUESTION_ID QUESTION_ID (COMTerminalType)
+#define COM_FLOWCONTROL_QUESTION_ID QUESTION_ID (COMFlowControl)
+#define LEGACY_FD_QUESTION_ID QUESTION_ID (LegacyFD)
+#define LEGACY_HD_QUESTION_ID QUESTION_ID (LegacyHD)
+#define LEGACY_CD_QUESTION_ID QUESTION_ID (LegacyCD)
+#define LEGACY_NET_QUESTION_ID QUESTION_ID (LegacyNET)
+#define LEGACY_BEV_QUESTION_ID QUESTION_ID (LegacyBEV)
+
+#define STRING_DEPOSITORY_NUMBER 8
+
+///
+/// Serial Ports attributes, first one is the value for
+/// return from callback function, stringtoken is used to
+/// display the value properly
+///
+typedef struct {
+ UINTN Value;
+ UINT16 StringToken;
+} COM_ATTR;
+
+typedef struct {
+ UINT64 BaudRate;
+ UINT8 DataBits;
+ UINT8 Parity;
+ UINT8 StopBits;
+
+ UINT8 BaudRateIndex;
+ UINT8 DataBitsIndex;
+ UINT8 ParityIndex;
+ UINT8 StopBitsIndex;
+
+ UINT8 FlowControl;
+
+ UINT8 IsConIn;
+ UINT8 IsConOut;
+ UINT8 IsStdErr;
+ UINT8 TerminalType;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_TERMINAL_CONTEXT;
+
+typedef struct {
+ BOOLEAN IsBootNext;
+ BOOLEAN LoadOptionModified;
+ BOOLEAN Deleted;
+
+ BOOLEAN IsLegacy;
+ BOOLEAN IsActive;
+ BOOLEAN ForceReconnect;
+ UINTN OptionalDataSize;
+
+ UINTN LoadOptionSize;
+ UINT8 *LoadOption;
+
+ UINT32 Attributes;
+ UINT16 FilePathListLength;
+ UINT16 *Description;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathList;
+ UINT8 *OptionalData;
+
+ UINT16 BbsIndex;
+} BM_LOAD_CONTEXT;
+
+typedef struct {
+ BBS_TABLE *BbsEntry;
+ UINT16 BbsIndex;
+ UINT16 BbsCount;
+ CHAR16 *Description;
+} BM_LEGACY_DEVICE_CONTEXT;
+
+typedef struct {
+
+ BOOLEAN IsActive;
+
+ BOOLEAN IsTerminal;
+
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_CONSOLE_CONTEXT;
+
+typedef struct {
+ UINTN Column;
+ UINTN Row;
+} CONSOLE_OUT_MODE;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_FILE_HANDLE FHandle;
+ UINT16 *FileName;
+ EFI_FILE_SYSTEM_VOLUME_LABEL *Info;
+
+ BOOLEAN IsRoot;
+ BOOLEAN IsDir;
+ BOOLEAN IsRemovableMedia;
+ BOOLEAN IsLoadFile;
+ BOOLEAN IsBootLegacy;
+} BM_FILE_CONTEXT;
+
+typedef struct {
+ EFI_HANDLE Handle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} BM_HANDLE_CONTEXT;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Head;
+ UINTN MenuNumber;
+} BM_MENU_OPTION;
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+ UINTN OptionNumber;
+ UINT16 *DisplayString;
+ UINT16 *HelpString;
+ EFI_STRING_ID DisplayStringToken;
+ EFI_STRING_ID HelpStringToken;
+ UINTN ContextSelection;
+ VOID *VariableContext;
+} BM_MENU_ENTRY;
+
+typedef struct {
+ //
+ // Shared callback data.
+ //
+ UINTN Signature;
+
+ BM_MENU_ENTRY *MenuEntry;
+ BM_HANDLE_CONTEXT *HandleContext;
+ BM_FILE_CONTEXT *FileContext;
+ BM_LOAD_CONTEXT *LoadContext;
+ BM_TERMINAL_CONTEXT *TerminalContext;
+ UINTN CurrentTerminal;
+ BBS_TYPE BbsType;
+
+ //
+ // BMM main formset callback data.
+ //
+ EFI_HII_HANDLE BmmHiiHandle;
+ EFI_HANDLE BmmDriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL BmmConfigAccess;
+ EFI_FORM_ID BmmCurrentPageId;
+ EFI_FORM_ID BmmPreviousPageId;
+ BOOLEAN BmmAskSaveOrNot;
+ BMM_FAKE_NV_DATA BmmFakeNvData;
+ BMM_FAKE_NV_DATA BmmOldFakeNVData;
+
+ //
+ // File explorer formset callback data.
+ //
+ EFI_HII_HANDLE FeHiiHandle;
+ EFI_HANDLE FeDriverHandle;
+ EFI_HII_CONFIG_ACCESS_PROTOCOL FeConfigAccess;
+ FILE_EXPLORER_STATE FeCurrentState;
+ FILE_EXPLORER_DISPLAY_CONTEXT FeDisplayContext;
+ FILE_EXPLORER_NV_DATA FeFakeNvData;
+} BMM_CALLBACK_DATA;
+
+typedef struct _STRING_LIST_NODE STRING_LIST_NODE;
+
+struct _STRING_LIST_NODE {
+ EFI_STRING_ID StringToken;
+ STRING_LIST_NODE *Next;
+};
+
+typedef struct _STRING_DEPOSITORY {
+ UINTN TotalNodeNumber;
+ STRING_LIST_NODE *CurrentNode;
+ STRING_LIST_NODE *ListHead;
+} STRING_DEPOSITORY;
+
+//
+// #pragma pack()
+//
+// For initializing File System menu
+//
+
+/**
+ This function build the FsOptionMenu list which records all
+ available file system in the system. They includes all instances
+ of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
+ and all type of legacy boot device.
+
+ @param CallbackData BMM context data
+
+ @retval EFI_SUCCESS Success find the file system
+ @retval EFI_OUT_OF_RESOURCES Can not create menu entry
+
+**/
+EFI_STATUS
+BOpt_FindFileSystem (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Find files under current directory
+ All files and sub-directories in current directory
+ will be stored in DirectoryMenu for future use.
+
+ @param CallbackData The BMM context data.
+ @param MenuEntry The Menu Entry.
+
+ @retval EFI_SUCCESS Get files from current dir successfully.
+ @return Other value if can't get files from current dir.
+
+**/
+EFI_STATUS
+BOpt_FindFiles (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN BM_MENU_ENTRY *MenuEntry
+ );
+
+/**
+
+ Find drivers that will be added as Driver#### variables from handles
+ in current system environment
+ All valid handles in the system except those consume SimpleFs, LoadFile
+ are stored in DriverMenu for future use.
+
+ @retval EFI_SUCCESS The function complets successfully.
+ @return Other value if failed to build the DriverMenu.
+
+**/
+EFI_STATUS
+BOpt_FindDrivers (
+ VOID
+ );
+
+/**
+
+ Build the BootOptionMenu according to BootOrder Variable.
+ This Routine will access the Boot#### to get EFI_LOAD_OPTION.
+
+ @param CallbackData The BMM context data.
+
+ @return The number of the Var Boot####.
+
+**/
+EFI_STATUS
+BOpt_GetBootOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Build up all DriverOptionMenu
+
+ @param CallbackData The BMM context data.
+
+ @return EFI_SUCESS The functin completes successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
+
+
+**/
+EFI_STATUS
+BOpt_GetDriverOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+
+/**
+ Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
+
+**/
+EFI_STATUS
+BOpt_GetLegacyOptions (
+ VOID
+ );
+
+/**
+ Free out resouce allocated from Legacy Boot Options.
+
+**/
+VOID
+BOpt_FreeLegacyOptions (
+ VOID
+ );
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param FreeMenu Menu to be freed
+
+**/
+VOID
+BOpt_FreeMenu (
+ BM_MENU_OPTION *FreeMenu
+ );
+
+
+/**
+
+ Append file name to existing file name.
+
+ @param Str1 The existing file name
+ @param Str2 The file name to be appended
+
+ @return Allocate a new string to hold the appended result.
+ Caller is responsible to free the returned string.
+
+**/
+CHAR16*
+BOpt_AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ );
+
+/**
+
+ Check whether current FileName point to a valid
+ Efi Image File.
+
+ @param FileName File need to be checked.
+
+ @retval TRUE Is Efi Image
+ @retval FALSE Not a valid Efi Image
+
+**/
+BOOLEAN
+BOpt_IsEfiImageName (
+ IN UINT16 *FileName
+ );
+
+/**
+
+ Check whether current FileName point to a valid Efi Application
+
+ @param Dir Pointer to current Directory
+ @param FileName Pointer to current File name.
+
+ @retval TRUE Is a valid Efi Application
+ @retval FALSE not a valid Efi Application
+
+**/
+BOOLEAN
+BOpt_IsEfiApp (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT16 *FileName
+ );
+
+/**
+
+ Get the Option Number that has not been allocated for use.
+
+ @param Type The type of Option.
+
+ @return The available Option Number.
+
+**/
+UINT16
+BOpt_GetOptionNumber (
+ CHAR16 *Type
+ );
+
+/**
+
+ Get the Option Number for Boot#### that does not used.
+
+ @return The available Option Number.
+
+**/
+UINT16
+BOpt_GetBootOptionNumber (
+ VOID
+ );
+
+/**
+
+Get the Option Number for Driver#### that does not used.
+
+@return The unused Option Number.
+
+**/
+UINT16
+BOpt_GetDriverOptionNumber (
+ VOID
+ );
+
+/**
+ Create a menu entry give a Menu type.
+
+ @param MenuType The Menu type to be created.
+
+
+ @retval NULL If failed to create the menu.
+ @return The menu.
+
+**/
+BM_MENU_ENTRY *
+BOpt_CreateMenuEntry (
+ UINTN MenuType
+ );
+
+/**
+ Free up all resource allocated for a BM_MENU_ENTRY.
+
+ @param MenuEntry A pointer to BM_MENU_ENTRY.
+
+**/
+VOID
+BOpt_DestroyMenuEntry (
+ BM_MENU_ENTRY *MenuEntry
+ );
+
+/**
+ Get the Menu Entry from the list in Menu Entry List.
+
+ If MenuNumber is great or equal to the number of Menu
+ Entry in the list, then ASSERT.
+
+ @param MenuOption The Menu Entry List to read the menu entry.
+ @param MenuNumber The index of Menu Entry.
+
+ @return The Menu Entry.
+
+**/
+BM_MENU_ENTRY *
+BOpt_GetMenuEntry (
+ BM_MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ );
+
+//
+// Locate all serial io devices for console
+//
+/**
+ Build a list containing all serial devices.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_UNSUPPORTED No serial ports present.
+
+**/
+EFI_STATUS
+LocateSerialIo (
+ VOID
+ );
+
+//
+// Initializing Console menu
+//
+/**
+ Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+ @retval EFI_SUCCESS The function always complete successfully.
+
+**/
+EFI_STATUS
+GetAllConsoles(
+ VOID
+ );
+
+//
+// Get current mode information
+//
+/**
+ Get mode number according to column and row
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetConsoleOutMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// Cleaning up console menu
+//
+/**
+ Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+ @retval EFI_SUCCESS The function always complete successfully.
+**/
+EFI_STATUS
+FreeAllConsoles (
+ VOID
+ );
+
+/**
+ Update the device path that describing a terminal device
+ based on the new BaudRate, Data Bits, parity and Stop Bits
+ set.
+
+ @param DevicePath The devicepath protocol instance wanted to be updated.
+
+**/
+VOID
+ChangeVariableDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Update the multi-instance device path of Terminal Device based on
+ the global TerminalMenu. If ChangeTernimal is TRUE, the terminal
+ device path in the Terminal Device in TerminalMenu is also updated.
+
+ @param DevicePath The multi-instance device path.
+ @param ChangeTerminal TRUE, then device path in the Terminal Device
+ in TerminalMenu is also updated; FALSE, no update.
+
+ @return EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+ChangeTerminalDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ IN BOOLEAN ChangeTerminal
+ );
+
+//
+// Variable operation by menu selection
+//
+/**
+ This function create a currently loaded Boot Option from
+ the BMM. It then appends this Boot Option to the end of
+ the "BootOrder" list. It also append this Boot Opotion to the end
+ of BootOptionMenu.
+
+ @param CallbackData The BMM context data.
+ @param NvRamMap The file explorer formset internal state.
+
+ @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
+ @retval EFI_SUCCESS If function completes successfully.
+
+**/
+EFI_STATUS
+Var_UpdateBootOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN FILE_EXPLORER_NV_DATA *NvRamMap
+ );
+
+/**
+ Delete Boot Option that represent a Deleted state in BootOptionMenu.
+ After deleting this boot option, call Var_ChangeBootOrder to
+ make sure BootOrder is in valid state.
+
+ @retval EFI_SUCCESS If all boot load option EFI Variables corresponding to
+ BM_LOAD_CONTEXT marked for deletion is deleted
+ @return Others If failed to update the "BootOrder" variable after deletion.
+
+**/
+EFI_STATUS
+Var_DelBootOption (
+ VOID
+ );
+
+/**
+ After any operation on Boot####, there will be a discrepancy in BootOrder.
+ Since some are missing but in BootOrder, while some are present but are
+ not reflected by BootOrder. Then a function rebuild BootOrder from
+ scratch by content from BootOptionMenu is needed.
+
+ @retval EFI_SUCCESS The boot order is updated successfully.
+ @return other than EFI_SUCCESS if failed to change the "BootOrder" EFI Variable.
+
+**/
+EFI_STATUS
+Var_ChangeBootOrder (
+ VOID
+ );
+
+/**
+ This function create a currently loaded Drive Option from
+ the BMM. It then appends this Driver Option to the end of
+ the "DriverOrder" list. It append this Driver Opotion to the end
+ of DriverOptionMenu.
+
+ @param CallbackData The BMM context data.
+ @param HiiHandle The HII handle associated with the BMM formset.
+ @param DescriptionData The description of this driver option.
+ @param OptionalData The optional load option.
+ @param ForceReconnect If to force reconnect.
+
+ @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
+ @retval EFI_SUCCESS If function completes successfully.
+
+**/
+EFI_STATUS
+Var_UpdateDriverOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN UINT16 *DescriptionData,
+ IN UINT16 *OptionalData,
+ IN UINT8 ForceReconnect
+ );
+
+/**
+ Delete Load Option that represent a Deleted state in BootOptionMenu.
+ After deleting this Driver option, call Var_ChangeDriverOrder to
+ make sure DriverOrder is in valid state.
+
+ @retval EFI_SUCCESS Load Option is successfully updated.
+ @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
+ Variable.
+
+**/
+EFI_STATUS
+Var_DelDriverOption (
+ VOID
+ );
+
+/**
+ After any operation on Driver####, there will be a discrepancy in
+ DriverOrder. Since some are missing but in DriverOrder, while some
+ are present but are not reflected by DriverOrder. Then a function
+ rebuild DriverOrder from scratch by content from DriverOptionMenu is
+ needed.
+
+ @retval EFI_SUCCESS The driver order is updated successfully.
+ @return other than EFI_SUCCESS if failed to set the "DriverOrder" EFI Variable.
+
+**/
+EFI_STATUS
+Var_ChangeDriverOrder (
+ VOID
+ );
+
+/**
+ This function delete and build multi-instance device path ConIn
+ console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateConsoleInpOption (
+ VOID
+ );
+
+/**
+ This function delete and build multi-instance device path ConOut console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateConsoleOutOption (
+ VOID
+ );
+
+/**
+ This function delete and build multi-instance device path ErrOut console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateErrorOutOption (
+ VOID
+ );
+
+/**
+ Update the device path of "ConOut", "ConIn" and "ErrOut" based on the new BaudRate, Data Bits,
+ parity and stop Bits set.
+
+**/
+VOID
+Var_UpdateAllConsoleOption (
+ VOID
+ );
+
+/**
+ This function update the "BootNext" EFI Variable. If there is no "BootNex" specified in BMM,
+ this EFI Variable is deleted.
+ It also update the BMM context data specified the "BootNext" value.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateBootNext (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ This function update the "BootOrder" EFI Variable based on BMM Formset's NV map. It then refresh
+ BootOptionMenu with the new "BootOrder" list.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to complete the function.
+ @return not The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ This function update the "DriverOrder" EFI Variable based on
+ BMM Formset's NV map. It then refresh DriverOptionMenu
+ with the new "DriverOrder" list.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to complete the function.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable
+ is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
+ is also updated.
+
+ @param CallbackData The context data for BMM.
+ @param FormId The form id.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can not be found.
+
+**/
+EFI_STATUS
+Var_UpdateBBSOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_FORM_ID FormId
+ );
+
+/**
+ Update the Text Mode of Console.
+
+ @param CallbackData The context data for BMM.
+
+ @retval EFI_SUCCSS If the Text Mode of Console is updated.
+ @return Other value if the Text Mode of Console is not updated.
+
+**/
+EFI_STATUS
+Var_UpdateConMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+//
+// Following are page create and refresh functions
+//
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+RefreshUpdateData (
+ VOID
+ );
+
+/**
+ Clean up the dynamic opcode at label and form specified by
+ both LabelId.
+
+ @param LabelId It is both the Form ID and Label ID for
+ opcode deletion.
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create a lit of boot option from global BootOptionMenu. It
+ allow user to delete the boot option.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateBootDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create a lit of driver option from global DriverMenu.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateDrvAddHandlePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create a lit of driver option from global DriverOptionMenu. It
+ allow user to delete the driver option.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateDrvDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Prepare the page to allow user to add description for a Driver Option.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateDriverAddHandleDescPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Dispatch the correct update page function to call based on the UpdatePageId.
+
+ @param UpdatePageId The form ID.
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdatePageBody (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create the dynamic page to allow user to set the "BootNext" vaule.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateBootNextPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create the dynamic page to allow user to set the "TimeOut" vaule.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateTimeOutPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create the dynamic page which allows user to set the property such as Baud Rate, Data Bits,
+ Parity, Stop Bits, Terminal Type.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateTerminalPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Refresh the text mode page
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateConModePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create a list of Goto Opcode for all terminal devices logged
+ by TerminaMenu. This list will be inserted to form FORM_CON_COM_SETUP_ID.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateConCOMPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Create a dynamic page so that Legacy Device boot order
+ can be set for specified device type.
+
+ @param UpdatePageId The form ID. It also spefies the legacy device type.
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateSetLegacyDeviceOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+
+/**
+ Function opens and returns a file handle to the root directory of a volume.
+
+ @param DeviceHandle A handle for a device
+ @return A valid file handle or NULL is returned
+**/
+EFI_FILE_HANDLE
+EfiLibOpenRoot (
+ IN EFI_HANDLE DeviceHandle
+ );
+
+/**
+ Function gets the file system information from an open file descriptor,
+ and stores it in a buffer allocated from pool.
+
+ @param FHand The file handle.
+
+ @return A pointer to a buffer with file information.
+ NULL is returned if failed to get Vaolume Label Info.
+**/
+EFI_FILE_SYSTEM_VOLUME_LABEL *
+EfiLibFileSystemVolumeLabelInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+/**
+
+ Function gets the file information from an open file descriptor, and stores it
+ in a buffer allocated from pool.
+
+ @param FHand File Handle.
+
+ @return A pointer to a buffer with file information or NULL is returned
+
+**/
+EFI_FILE_INFO *
+EfiLibFileInfo (
+ IN EFI_FILE_HANDLE FHand
+ );
+
+/**
+ Adjusts the size of a previously allocated buffer.
+
+ @param OldPool A pointer to the buffer whose size is being adjusted.
+ @param OldSize The size of the current buffer.
+ @param NewSize The size of the new buffer.
+
+ @return The newly allocated buffer. if NULL, allocation failed.
+
+**/
+VOID*
+EfiReallocatePool (
+ IN VOID *OldPool,
+ IN UINTN OldSize,
+ IN UINTN NewSize
+ );
+
+/**
+ Function deletes the variable specified by VarName and VarGuid.
+
+
+ @param VarName A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+
+ @param VarGuid A unique identifier for the vendor.
+
+ @retval EFI_SUCCESS The variable was found and removed
+ @retval EFI_UNSUPPORTED The variable store was inaccessible
+ @retval EFI_OUT_OF_RESOURCES The temporary buffer was not available
+ @retval EFI_NOT_FOUND The variable was not found
+
+**/
+EFI_STATUS
+EfiLibDeleteVariable (
+ IN CHAR16 *VarName,
+ IN EFI_GUID *VarGuid
+ );
+
+/**
+ Duplicate a string.
+
+ @param Src The source.
+
+ @return A new string which is duplicated copy of the source.
+ @retval NULL If there is not enough memory.
+
+**/
+CHAR16 *
+EfiStrDuplicate (
+ IN CHAR16 *Src
+ );
+
+/**
+ Function is used to determine the number of device path instances
+ that exist in a device path.
+
+
+ @param DevicePath A pointer to a device path data structure.
+
+ @return This function counts and returns the number of device path instances
+ in DevicePath.
+
+**/
+UINTN
+EfiDevicePathInstanceCount (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Create string tokens for a menu from its help strings and display strings
+
+
+ @param CallbackData The BMM context data.
+ @param HiiHandle Hii Handle of the package to be updated.
+ @param MenuOption The Menu whose string tokens need to be created
+
+ @retval EFI_SUCCESS string tokens created successfully
+ @retval others contain some errors
+
+**/
+EFI_STATUS
+CreateMenuStringToken (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN BM_MENU_OPTION *MenuOption
+ );
+
+/**
+ Get a string from the Data Hub record based on
+ a device path.
+
+ @param DevPath The device Path.
+
+ @return A string located from the Data Hub records based on
+ the device path.
+ @retval NULL If failed to get the String from Data Hub.
+
+**/
+UINT16 *
+EfiLibStrFromDatahub (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevPath
+ );
+
+/**
+ Initialize the Boot Maintenance Utitliy.
+
+ @retval EFI_SUCCESS utility ended successfully.
+ @retval others contain some errors.
+
+**/
+EFI_STATUS
+InitializeBM (
+ VOID
+ );
+
+/**
+ Start boot maintenance manager
+
+ @retval EFI_SUCCESS If BMM is invoked successfully.
+ @return Other value if BMM return unsuccessfully.
+
+**/
+EFI_STATUS
+BdsStartBootMaint (
+ VOID
+ );
+
+/**
+ Intialize all the string depositories.
+
+**/
+VOID
+InitializeStringDepository (
+ VOID
+ );
+
+/**
+ Fetch a usable string node from the string depository and return the string token.
+
+
+ @param CallbackData The BMM context data.
+ @param StringDepository Pointer of the string depository.
+
+ @retval EFI_STRING_ID String token.
+
+**/
+EFI_STRING_ID
+GetStringTokenFromDepository (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN STRING_DEPOSITORY *StringDepository
+ );
+
+/**
+ Reclaim string depositories by moving the current node pointer to list head..
+**/
+VOID
+ReclaimStringDepository (
+ VOID
+ );
+
+/**
+ Release resource for all the string depositories.
+
+**/
+VOID
+CleanUpStringDepository (
+ VOID
+ );
+
+/**
+ Function handling request to apply changes for BMM pages.
+
+ @param Private Pointer to callback data buffer.
+ @param CurrentFakeNVMap Pointer to buffer holding data of various values used by BMM
+ @param FormId ID of the form which has sent the request to apply change.
+
+ @retval EFI_SUCCESS Change successfully applied.
+ @retval Other Error occurs while trying to apply changes.
+
+**/
+EFI_STATUS
+ApplyChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap,
+ IN EFI_FORM_ID FormId
+ );
+
+/**
+ Discard all changes done to the BMM pages such as Boot Order change,
+ Driver order change.
+
+ @param Private The BMM context data.
+ @param CurrentFakeNVMap The current Fack NV Map.
+
+**/
+VOID
+DiscardChangeHandler (
+ IN BMM_CALLBACK_DATA *Private,
+ IN BMM_FAKE_NV_DATA *CurrentFakeNVMap
+ );
+
+/**
+ Dispatch the display to the next page based on NewPageId.
+
+ @param Private The BMM context data.
+ @param NewPageId The original page ID.
+
+**/
+VOID
+UpdatePageId (
+ BMM_CALLBACK_DATA *Private,
+ UINT16 NewPageId
+ );
+
+/**
+ Boot a file selected by user at File Expoloer of BMM.
+
+ @param FileContext The file context data, which contains the device path
+ of the file to be boot from.
+
+ @retval EFI_SUCCESS The function completed successfull.
+ @return Other value if the boot from the file fails.
+
+**/
+EFI_STATUS
+BootThisFile (
+ IN BM_FILE_CONTEXT *FileContext
+ );
+
+/**
+ Update the file explower page with the refershed file system.
+
+
+ @param CallbackData BMM context data
+ @param KeyValue Key value to identify the type of data to expect.
+
+ @retval TRUE Inform the caller to create a callback packet to exit file explorer.
+ @retval FALSE Indicate that there is no need to exit file explorer.
+
+**/
+BOOLEAN
+UpdateFileExplorer (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN UINT16 KeyValue
+ );
+
+/**
+ This function processes the results of changes in configuration.
+ When user select a interactive opcode, this callback will be triggered.
+ Based on the Question(QuestionId) that triggers the callback, the corresponding
+ actions is performed. It handles:
+
+ 1) the addition of boot option.
+ 2) the addition of driver option.
+ 3) exit from file browser
+ 4) update of file content if a dir is selected.
+ 5) boot the file if a file is selected in "boot from file"
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
+
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+/**
+ This function applies changes in a driver's configuration.
+ Input is a Configuration, which has the routing data for this
+ driver followed by name / value configuration pairs. The driver
+ must apply those pairs to its configurable storage. If the
+ driver's configuration is stored in a linear block of data
+ and the driver's name / value pairs are in <BlockConfig>
+ format, it may use the ConfigToBlock helper function (above) to
+ simplify the job. Currently not implemented.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ <ConfigString> format.
+ @param[out] Progress A pointer to a string filled in with the
+ offset of the most recent '&' before the
+ first failing name / value pair (or the
+ beginn ing of the string if the failure
+ is in the first name / value pair) or
+ the terminating NULL if all was
+ successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are
+ awaiting distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
+ Results parameter would result
+ in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data
+ was not found.
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ Dispatch BMM formset and FileExplorer formset.
+
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS If function complete successfully.
+ @return Other value if the Setup Browser process BMM's pages and
+ return unsuccessfully.
+
+**/
+EFI_STATUS
+FormSetDispatcher (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Function returns the value of the specified variable.
+
+ @param Name A Null-terminated Unicode string that is
+ the name of the vendor's variable.
+ @param VendorGuid A unique identifier for the vendor.
+
+ @return The payload of the variable.
+ @retval NULL If the variable can't be read.
+
+**/
+VOID *
+EfiLibGetVariable (
+ IN CHAR16 *Name,
+ IN EFI_GUID *VendorGuid
+ );
+
+/**
+ Get option number according to Boot#### and BootOrder variable.
+ The value is saved as #### + 1.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Get driver option order from globalc DriverOptionMenu.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+ Intall BootMaint and FileExplorer HiiPackages.
+
+**/
+EFI_STATUS
+InitBMPackage (
+ VOID
+ );
+
+/**
+ Remvoe the intalled BootMaint and FileExplorer HiiPackages.
+
+**/
+VOID
+FreeBMPackage (
+ VOID
+ );
+
+/**
+ According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV
+ devices list .
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetLegacyDeviceOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Initialize console input device check box to ConsoleInCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleInCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Initialize console output device check box to ConsoleOutCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleOutCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Initialize standard error output device check box to ConsoleErrCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleErrCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Initialize terminal attributes (baudrate, data rate, stop bits, parity and terminal type)
+ to BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetTerminalAttribute (
+ IN BMM_CALLBACK_DATA *CallbackData
+ );
+
+/**
+
+ Find the first instance of this Protocol
+ in the system and return it's interface.
+
+
+ @param ProtocolGuid Provides the protocol to search for
+ @param Interface On return, a pointer to the first interface
+ that matches ProtocolGuid
+
+ @retval EFI_SUCCESS A protocol instance matching ProtocolGuid was found
+ @retval EFI_NOT_FOUND No protocol instances were found that match ProtocolGuid
+
+**/
+EFI_STATUS
+EfiLibLocateProtocol (
+ IN EFI_GUID *ProtocolGuid,
+ OUT VOID **Interface
+ );
+
+//
+// Global variable in this program (defined in data.c)
+//
+extern BM_MENU_OPTION BootOptionMenu;
+extern BM_MENU_OPTION DriverOptionMenu;
+extern BM_MENU_OPTION FsOptionMenu;
+extern BM_MENU_OPTION ConsoleInpMenu;
+extern BM_MENU_OPTION ConsoleOutMenu;
+extern BM_MENU_OPTION ConsoleErrMenu;
+extern BM_MENU_OPTION DirectoryMenu;
+extern BM_MENU_OPTION DriverMenu;
+extern BM_MENU_OPTION TerminalMenu;
+extern BM_MENU_OPTION LegacyFDMenu;
+extern BM_MENU_OPTION LegacyHDMenu;
+extern BM_MENU_OPTION LegacyCDMenu;
+extern BM_MENU_OPTION LegacyNETMenu;
+extern BM_MENU_OPTION LegacyBEVMenu;
+extern UINT16 TerminalType[];
+extern COM_ATTR BaudRateList[19];
+extern COM_ATTR DataBitsList[4];
+extern COM_ATTR ParityList[5];
+extern COM_ATTR StopBitsList[3];
+extern EFI_GUID TerminalTypeGuid[4];
+extern STRING_DEPOSITORY *FileOptionStrDepository;
+extern STRING_DEPOSITORY *ConsoleOptionStrDepository;
+extern STRING_DEPOSITORY *BootOptionStrDepository;
+extern STRING_DEPOSITORY *BootOptionHelpStrDepository;
+extern STRING_DEPOSITORY *DriverOptionStrDepository;
+extern STRING_DEPOSITORY *DriverOptionHelpStrDepository;
+extern STRING_DEPOSITORY *TerminalStrDepository;
+extern EFI_DEVICE_PATH_PROTOCOL EndDevicePath[];
+extern UINT16 mFlowControlType[2];
+extern UINT32 mFlowControlValue[2];
+//
+// Shared IFR form update data
+//
+extern VOID *mStartOpCodeHandle;
+extern VOID *mEndOpCodeHandle;
+extern EFI_IFR_GUID_LABEL *mStartLabel;
+extern EFI_IFR_GUID_LABEL *mEndLabel;
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
new file mode 100644
index 0000000000..56bcfab23f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/BootOption.c
@@ -0,0 +1,1823 @@
+/** @file
+ Provide boot option support for Application "BootMaint"
+
+ Include file system navigation, system handle selection
+
+ Boot option manipulation
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+#include "BBSsupport.h"
+
+/**
+ Create a menu entry by given menu type.
+
+ @param MenuType The Menu type to be created.
+
+ @retval NULL If failed to create the menu.
+ @return the new menu entry.
+
+**/
+BM_MENU_ENTRY *
+BOpt_CreateMenuEntry (
+ UINTN MenuType
+ )
+{
+ BM_MENU_ENTRY *MenuEntry;
+ UINTN ContextSize;
+
+ //
+ // Get context size according to menu type
+ //
+ switch (MenuType) {
+ case BM_LOAD_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_LOAD_CONTEXT);
+ break;
+
+ case BM_FILE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_FILE_CONTEXT);
+ break;
+
+ case BM_CONSOLE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_CONSOLE_CONTEXT);
+ break;
+
+ case BM_TERMINAL_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_TERMINAL_CONTEXT);
+ break;
+
+ case BM_HANDLE_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_HANDLE_CONTEXT);
+ break;
+
+ case BM_LEGACY_DEV_CONTEXT_SELECT:
+ ContextSize = sizeof (BM_LEGACY_DEVICE_CONTEXT);
+ break;
+
+ default:
+ ContextSize = 0;
+ break;
+ }
+
+ if (ContextSize == 0) {
+ return NULL;
+ }
+
+ //
+ // Create new menu entry
+ //
+ MenuEntry = AllocateZeroPool (sizeof (BM_MENU_ENTRY));
+ if (MenuEntry == NULL) {
+ return NULL;
+ }
+
+ MenuEntry->VariableContext = AllocateZeroPool (ContextSize);
+ if (MenuEntry->VariableContext == NULL) {
+ FreePool (MenuEntry);
+ return NULL;
+ }
+
+ MenuEntry->Signature = BM_MENU_ENTRY_SIGNATURE;
+ MenuEntry->ContextSelection = MenuType;
+ return MenuEntry;
+}
+
+/**
+ Free up all resource allocated for a BM_MENU_ENTRY.
+
+ @param MenuEntry A pointer to BM_MENU_ENTRY.
+
+**/
+VOID
+BOpt_DestroyMenuEntry (
+ BM_MENU_ENTRY *MenuEntry
+ )
+{
+ BM_LOAD_CONTEXT *LoadContext;
+ BM_FILE_CONTEXT *FileContext;
+ BM_CONSOLE_CONTEXT *ConsoleContext;
+ BM_TERMINAL_CONTEXT *TerminalContext;
+ BM_HANDLE_CONTEXT *HandleContext;
+ BM_LEGACY_DEVICE_CONTEXT *LegacyDevContext;
+
+ //
+ // Select by the type in Menu entry for current context type
+ //
+ switch (MenuEntry->ContextSelection) {
+ case BM_LOAD_CONTEXT_SELECT:
+ LoadContext = (BM_LOAD_CONTEXT *) MenuEntry->VariableContext;
+ FreePool (LoadContext->FilePathList);
+ FreePool (LoadContext->LoadOption);
+ if (LoadContext->OptionalData != NULL) {
+ FreePool (LoadContext->OptionalData);
+ }
+ FreePool (LoadContext);
+ break;
+
+ case BM_FILE_CONTEXT_SELECT:
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ if (!FileContext->IsRoot) {
+ FreePool (FileContext->DevicePath);
+ } else {
+ if (FileContext->FHandle != NULL) {
+ FileContext->FHandle->Close (FileContext->FHandle);
+ }
+ }
+
+ if (FileContext->FileName != NULL) {
+ FreePool (FileContext->FileName);
+ }
+ if (FileContext->Info != NULL) {
+ FreePool (FileContext->Info);
+ }
+ FreePool (FileContext);
+ break;
+
+ case BM_CONSOLE_CONTEXT_SELECT:
+ ConsoleContext = (BM_CONSOLE_CONTEXT *) MenuEntry->VariableContext;
+ FreePool (ConsoleContext->DevicePath);
+ FreePool (ConsoleContext);
+ break;
+
+ case BM_TERMINAL_CONTEXT_SELECT:
+ TerminalContext = (BM_TERMINAL_CONTEXT *) MenuEntry->VariableContext;
+ FreePool (TerminalContext->DevicePath);
+ FreePool (TerminalContext);
+ break;
+
+ case BM_HANDLE_CONTEXT_SELECT:
+ HandleContext = (BM_HANDLE_CONTEXT *) MenuEntry->VariableContext;
+ FreePool (HandleContext);
+ break;
+
+ case BM_LEGACY_DEV_CONTEXT_SELECT:
+ LegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) MenuEntry->VariableContext;
+ FreePool (LegacyDevContext);
+
+ default:
+ break;
+ }
+
+ FreePool (MenuEntry->DisplayString);
+ if (MenuEntry->HelpString != NULL) {
+ FreePool (MenuEntry->HelpString);
+ }
+
+ FreePool (MenuEntry);
+}
+
+/**
+ Get the Menu Entry from the list in Menu Entry List.
+
+ If MenuNumber is great or equal to the number of Menu
+ Entry in the list, then ASSERT.
+
+ @param MenuOption The Menu Entry List to read the menu entry.
+ @param MenuNumber The index of Menu Entry.
+
+ @return The Menu Entry.
+
+**/
+BM_MENU_ENTRY *
+BOpt_GetMenuEntry (
+ BM_MENU_OPTION *MenuOption,
+ UINTN MenuNumber
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINTN Index;
+ LIST_ENTRY *List;
+
+ ASSERT (MenuNumber < MenuOption->MenuNumber);
+
+ List = MenuOption->Head.ForwardLink;
+ for (Index = 0; Index < MenuNumber; Index++) {
+ List = List->ForwardLink;
+ }
+
+ NewMenuEntry = CR (List, BM_MENU_ENTRY, Link, BM_MENU_ENTRY_SIGNATURE);
+
+ return NewMenuEntry;
+}
+
+/**
+ This function build the FsOptionMenu list which records all
+ available file system in the system. They includes all instances
+ of EFI_SIMPLE_FILE_SYSTEM_PROTOCOL, all instances of EFI_LOAD_FILE_SYSTEM
+ and all type of legacy boot device.
+
+ @param CallbackData BMM context data
+
+ @retval EFI_SUCCESS Success find the file system
+ @retval EFI_OUT_OF_RESOURCES Can not create menu entry
+
+**/
+EFI_STATUS
+BOpt_FindFileSystem (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN NoBlkIoHandles;
+ UINTN NoSimpleFsHandles;
+ UINTN NoLoadFileHandles;
+ EFI_HANDLE *BlkIoHandle;
+ EFI_HANDLE *SimpleFsHandle;
+ EFI_HANDLE *LoadFileHandle;
+ UINT16 *VolumeLabel;
+ EFI_BLOCK_IO_PROTOCOL *BlkIo;
+ UINTN Index;
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *MenuEntry;
+ BM_FILE_CONTEXT *FileContext;
+ UINT16 *TempStr;
+ UINTN OptionNumber;
+ VOID *Buffer;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 DeviceType;
+ BBS_BBS_DEVICE_PATH BbsDevicePathNode;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ BOOLEAN RemovableMedia;
+
+
+ NoSimpleFsHandles = 0;
+ NoLoadFileHandles = 0;
+ OptionNumber = 0;
+ InitializeListHead (&FsOptionMenu.Head);
+
+ //
+ // Locate Handles that support BlockIo protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiBlockIoProtocolGuid,
+ NULL,
+ &NoBlkIoHandles,
+ &BlkIoHandle
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = 0; Index < NoBlkIoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ BlkIoHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Issue a dummy read to trigger reinstall of BlockIo protocol for removable media
+ //
+ if (BlkIo->Media->RemovableMedia) {
+ Buffer = AllocateZeroPool (BlkIo->Media->BlockSize);
+ if (NULL == Buffer) {
+ FreePool (BlkIoHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ BlkIo->ReadBlocks (
+ BlkIo,
+ BlkIo->Media->MediaId,
+ 0,
+ BlkIo->Media->BlockSize,
+ Buffer
+ );
+ FreePool (Buffer);
+ }
+ }
+ FreePool (BlkIoHandle);
+ }
+
+ //
+ // Locate Handles that support Simple File System protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleFileSystemProtocolGuid,
+ NULL,
+ &NoSimpleFsHandles,
+ &SimpleFsHandle
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Find all the instances of the File System prototocol
+ //
+ for (Index = 0; Index < NoSimpleFsHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ SimpleFsHandle[Index],
+ &gEfiBlockIoProtocolGuid,
+ (VOID **) &BlkIo
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no block IO exists assume it's NOT a removable media
+ //
+ RemovableMedia = FALSE;
+ } else {
+ //
+ // If block IO exists check to see if it's remobable media
+ //
+ RemovableMedia = BlkIo->Media->RemovableMedia;
+ }
+
+ //
+ // Allocate pool for this load option
+ //
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ FreePool (SimpleFsHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ FileContext->Handle = SimpleFsHandle[Index];
+ MenuEntry->OptionNumber = Index;
+ FileContext->FHandle = EfiLibOpenRoot (FileContext->Handle);
+ if (FileContext->FHandle == NULL) {
+ BOpt_DestroyMenuEntry (MenuEntry);
+ continue;
+ }
+
+ MenuEntry->HelpString = DevicePathToStr (DevicePathFromHandle (FileContext->Handle));
+ FileContext->Info = EfiLibFileSystemVolumeLabelInfo (FileContext->FHandle);
+ FileContext->FileName = EfiStrDuplicate (L"\\");
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+ FileContext->IsDir = TRUE;
+ FileContext->IsRoot = TRUE;
+ FileContext->IsRemovableMedia = RemovableMedia;
+ FileContext->IsLoadFile = FALSE;
+
+ //
+ // Get current file system's Volume Label
+ //
+ if (FileContext->Info == NULL) {
+ VolumeLabel = L"NO FILE SYSTEM INFO";
+ } else {
+ VolumeLabel = FileContext->Info->VolumeLabel;
+ if (*VolumeLabel == 0x0000) {
+ VolumeLabel = L"NO VOLUME LABEL";
+ }
+ }
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"%s, [%s]",
+ VolumeLabel,
+ TempStr
+ );
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoSimpleFsHandles != 0) {
+ FreePool (SimpleFsHandle);
+ }
+ //
+ // Searching for handles that support Load File protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiLoadFileProtocolGuid,
+ NULL,
+ &NoLoadFileHandles,
+ &LoadFileHandle
+ );
+
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < NoLoadFileHandles; Index++) {
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ FreePool (LoadFileHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+ FileContext->IsRemovableMedia = FALSE;
+ FileContext->IsLoadFile = TRUE;
+ FileContext->Handle = LoadFileHandle[Index];
+ FileContext->IsRoot = TRUE;
+
+ FileContext->DevicePath = DevicePathFromHandle (FileContext->Handle);
+ FileContext->FileName = DevicePathToStr (FileContext->DevicePath);
+
+ MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"Load File [%s]",
+ TempStr
+ );
+
+ MenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+
+ if (NoLoadFileHandles != 0) {
+ FreePool (LoadFileHandle);
+ }
+
+ //
+ // Add Legacy Boot Option Support Here
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+ if (!EFI_ERROR (Status)) {
+
+ for (Index = BBS_TYPE_FLOPPY; Index <= BBS_TYPE_EMBEDDED_NETWORK; Index++) {
+ MenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == MenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+
+ FileContext->IsRemovableMedia = FALSE;
+ FileContext->IsLoadFile = TRUE;
+ FileContext->IsBootLegacy = TRUE;
+ DeviceType = (UINT16) Index;
+ BbsDevicePathNode.Header.Type = BBS_DEVICE_PATH;
+ BbsDevicePathNode.Header.SubType = BBS_BBS_DP;
+ SetDevicePathNodeLength (
+ &BbsDevicePathNode.Header,
+ sizeof (BBS_BBS_DEVICE_PATH)
+ );
+ BbsDevicePathNode.DeviceType = DeviceType;
+ BbsDevicePathNode.StatusFlag = 0;
+ BbsDevicePathNode.String[0] = 0;
+ DevicePath = AppendDevicePathNode (
+ EndDevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &BbsDevicePathNode
+ );
+
+ FileContext->DevicePath = DevicePath;
+ MenuEntry->HelpString = DevicePathToStr (FileContext->DevicePath);
+
+ TempStr = MenuEntry->HelpString;
+ MenuEntry->DisplayString = AllocateZeroPool (MAX_CHAR);
+ ASSERT (MenuEntry->DisplayString != NULL);
+ UnicodeSPrint (
+ MenuEntry->DisplayString,
+ MAX_CHAR,
+ L"Boot Legacy [%s]",
+ TempStr
+ );
+ MenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&FsOptionMenu.Head, &MenuEntry->Link);
+ }
+ }
+ //
+ // Remember how many file system options are here
+ //
+ FsOptionMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+/**
+ Free resources allocated in Allocate Rountine.
+
+ @param FreeMenu Menu to be freed
+**/
+VOID
+BOpt_FreeMenu (
+ BM_MENU_OPTION *FreeMenu
+ )
+{
+ BM_MENU_ENTRY *MenuEntry;
+ while (!IsListEmpty (&FreeMenu->Head)) {
+ MenuEntry = CR (
+ FreeMenu->Head.ForwardLink,
+ BM_MENU_ENTRY,
+ Link,
+ BM_MENU_ENTRY_SIGNATURE
+ );
+ RemoveEntryList (&MenuEntry->Link);
+ BOpt_DestroyMenuEntry (MenuEntry);
+ }
+ FreeMenu->MenuNumber = 0;
+}
+
+/**
+ Find files under current directory
+ All files and sub-directories in current directory
+ will be stored in DirectoryMenu for future use.
+
+ @param CallbackData The BMM context data.
+ @param MenuEntry The Menu Entry.
+
+ @retval EFI_SUCCESS Get files from current dir successfully.
+ @return Other value if can't get files from current dir.
+
+**/
+EFI_STATUS
+BOpt_FindFiles (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN BM_MENU_ENTRY *MenuEntry
+ )
+{
+ EFI_FILE_HANDLE NewDir;
+ EFI_FILE_HANDLE Dir;
+ EFI_FILE_INFO *DirInfo;
+ UINTN BufferSize;
+ UINTN DirBufferSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *FileContext;
+ BM_FILE_CONTEXT *NewFileContext;
+ UINTN Pass;
+ EFI_STATUS Status;
+ UINTN OptionNumber;
+
+ FileContext = (BM_FILE_CONTEXT *) MenuEntry->VariableContext;
+ Dir = FileContext->FHandle;
+ OptionNumber = 0;
+ //
+ // Open current directory to get files from it
+ //
+ Status = Dir->Open (
+ Dir,
+ &NewDir,
+ FileContext->FileName,
+ EFI_FILE_READ_ONLY,
+ 0
+ );
+ if (!FileContext->IsRoot) {
+ Dir->Close (Dir);
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DirInfo = EfiLibFileInfo (NewDir);
+ if (DirInfo == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FileContext->DevicePath = FileDevicePath (
+ FileContext->Handle,
+ FileContext->FileName
+ );
+
+ DirBufferSize = sizeof (EFI_FILE_INFO) + 1024;
+ DirInfo = AllocateZeroPool (DirBufferSize);
+ if (DirInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Get all files in current directory
+ // Pass 1 to get Directories
+ // Pass 2 to get files that are EFI images
+ //
+ for (Pass = 1; Pass <= 2; Pass++) {
+ NewDir->SetPosition (NewDir, 0);
+ for (;;) {
+ BufferSize = DirBufferSize;
+ Status = NewDir->Read (NewDir, &BufferSize, DirInfo);
+ if (EFI_ERROR (Status) || BufferSize == 0) {
+ break;
+ }
+
+ if (((DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0 && Pass == 2) ||
+ ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == 0 && Pass == 1)
+ ) {
+ //
+ // Pass 1 is for Directories
+ // Pass 2 is for file names
+ //
+ continue;
+ }
+
+ if (!(BOpt_IsEfiImageName (DirInfo->FileName) || (DirInfo->Attribute & EFI_FILE_DIRECTORY) != 0)) {
+ //
+ // Slip file unless it is a directory entry or a .EFI file
+ //
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_FILE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewFileContext->Handle = FileContext->Handle;
+ NewFileContext->FileName = BOpt_AppendFileName (
+ FileContext->FileName,
+ DirInfo->FileName
+ );
+ NewFileContext->FHandle = NewDir;
+ NewFileContext->DevicePath = FileDevicePath (
+ NewFileContext->Handle,
+ NewFileContext->FileName
+ );
+ NewMenuEntry->HelpString = NULL;
+
+ MenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ FileOptionStrDepository
+ );
+
+ NewFileContext->IsDir = (BOOLEAN) ((DirInfo->Attribute & EFI_FILE_DIRECTORY) == EFI_FILE_DIRECTORY);
+
+ if (NewFileContext->IsDir) {
+ BufferSize = StrLen (DirInfo->FileName) * 2 + 6;
+ NewMenuEntry->DisplayString = AllocateZeroPool (BufferSize);
+
+ UnicodeSPrint (
+ NewMenuEntry->DisplayString,
+ BufferSize,
+ L"<%s>",
+ DirInfo->FileName
+ );
+
+ } else {
+ NewMenuEntry->DisplayString = EfiStrDuplicate (DirInfo->FileName);
+ }
+
+ NewFileContext->IsRoot = FALSE;
+ NewFileContext->IsLoadFile = FALSE;
+ NewFileContext->IsRemovableMedia = FALSE;
+
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DirectoryMenu.Head, &NewMenuEntry->Link);
+ }
+ }
+
+ DirectoryMenu.MenuNumber = OptionNumber;
+ FreePool (DirInfo);
+ return EFI_SUCCESS;
+}
+
+/**
+ Build the LegacyFDMenu LegacyHDMenu LegacyCDMenu according to LegacyBios.GetBbsInfo().
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES No enough memory to complete this function.
+
+**/
+EFI_STATUS
+BOpt_GetLegacyOptions (
+ VOID
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LEGACY_DEVICE_CONTEXT *NewLegacyDevContext;
+ EFI_STATUS Status;
+ EFI_LEGACY_BIOS_PROTOCOL *LegacyBios;
+ UINT16 HddCount;
+ HDD_INFO *HddInfo;
+ UINT16 BbsCount;
+ BBS_TABLE *BbsTable;
+ UINT16 Index;
+ CHAR16 DescString[100];
+ UINTN FDNum;
+ UINTN HDNum;
+ UINTN CDNum;
+ UINTN NETNum;
+ UINTN BEVNum;
+
+ NewMenuEntry = NULL;
+ HddInfo = NULL;
+ BbsTable = NULL;
+ BbsCount = 0;
+
+ //
+ // Initialize Bbs Table Context from BBS info data
+ //
+ InitializeListHead (&LegacyFDMenu.Head);
+ InitializeListHead (&LegacyHDMenu.Head);
+ InitializeListHead (&LegacyCDMenu.Head);
+ InitializeListHead (&LegacyNETMenu.Head);
+ InitializeListHead (&LegacyBEVMenu.Head);
+
+ Status = gBS->LocateProtocol (
+ &gEfiLegacyBiosProtocolGuid,
+ NULL,
+ (VOID **) &LegacyBios
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = LegacyBios->GetBbsInfo (
+ LegacyBios,
+ &HddCount,
+ &HddInfo,
+ &BbsCount,
+ &BbsTable
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ FDNum = 0;
+ HDNum = 0;
+ CDNum = 0;
+ NETNum = 0;
+ BEVNum = 0;
+
+ for (Index = 0; Index < BbsCount; Index++) {
+ if ((BBS_IGNORE_ENTRY == BbsTable[Index].BootPriority) ||
+ (BBS_DO_NOT_BOOT_FROM == BbsTable[Index].BootPriority)
+ ) {
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LEGACY_DEV_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ break;
+ }
+
+ NewLegacyDevContext = (BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLegacyDevContext->BbsEntry = &BbsTable[Index];
+ NewLegacyDevContext->BbsIndex = Index;
+ NewLegacyDevContext->BbsCount = BbsCount;
+ BdsBuildLegacyDevNameString (
+ &BbsTable[Index],
+ Index,
+ sizeof (DescString),
+ DescString
+ );
+ NewLegacyDevContext->Description = AllocateCopyPool (StrSize (DescString), DescString);
+ if (NULL == NewLegacyDevContext->Description) {
+ break;
+ }
+
+ NewMenuEntry->DisplayString = NewLegacyDevContext->Description;
+ NewMenuEntry->HelpString = NULL;
+
+ switch (BbsTable[Index].DeviceType) {
+ case BBS_FLOPPY:
+ InsertTailList (&LegacyFDMenu.Head, &NewMenuEntry->Link);
+ FDNum++;
+ break;
+
+ case BBS_HARDDISK:
+ InsertTailList (&LegacyHDMenu.Head, &NewMenuEntry->Link);
+ HDNum++;
+ break;
+
+ case BBS_CDROM:
+ InsertTailList (&LegacyCDMenu.Head, &NewMenuEntry->Link);
+ CDNum++;
+ break;
+
+ case BBS_EMBED_NETWORK:
+ InsertTailList (&LegacyNETMenu.Head, &NewMenuEntry->Link);
+ NETNum++;
+ break;
+
+ case BBS_BEV_DEVICE:
+ InsertTailList (&LegacyBEVMenu.Head, &NewMenuEntry->Link);
+ BEVNum++;
+ break;
+ }
+ }
+
+ if (Index != BbsCount) {
+ BOpt_FreeLegacyOptions ();
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LegacyFDMenu.MenuNumber = FDNum;
+ LegacyHDMenu.MenuNumber = HDNum;
+ LegacyCDMenu.MenuNumber = CDNum;
+ LegacyNETMenu.MenuNumber = NETNum;
+ LegacyBEVMenu.MenuNumber = BEVNum;
+ return EFI_SUCCESS;
+}
+
+/**
+ Free out resouce allocated from Legacy Boot Options.
+
+**/
+VOID
+BOpt_FreeLegacyOptions (
+ VOID
+ )
+{
+ BOpt_FreeMenu (&LegacyFDMenu);
+ BOpt_FreeMenu (&LegacyHDMenu);
+ BOpt_FreeMenu (&LegacyCDMenu);
+ BOpt_FreeMenu (&LegacyNETMenu);
+ BOpt_FreeMenu (&LegacyBEVMenu);
+}
+
+/**
+
+ Build the BootOptionMenu according to BootOrder Variable.
+ This Routine will access the Boot#### to get EFI_LOAD_OPTION.
+
+ @param CallbackData The BMM context data.
+
+ @return EFI_NOT_FOUND Fail to find "BootOrder" variable.
+ @return EFI_SUCESS Success build boot option menu.
+
+**/
+EFI_STATUS
+BOpt_GetBootOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Index;
+ UINT16 BootString[10];
+ UINT8 *LoadOptionFromVar;
+ UINT8 *LoadOption;
+ UINTN BootOptionSize;
+ BOOLEAN BootNextFlag;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 *BootNext;
+ UINTN BootNextSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT8 *LoadOptionPtr;
+ UINTN StringSize;
+ UINTN OptionalDataSize;
+ UINT8 *LoadOptionEnd;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ UINTN MenuCount;
+ UINT8 *Ptr;
+
+ MenuCount = 0;
+ BootOrderListSize = 0;
+ BootNextSize = 0;
+ BootOrderList = NULL;
+ BootNext = NULL;
+ LoadOptionFromVar = NULL;
+ BOpt_FreeMenu (&BootOptionMenu);
+ InitializeListHead (&BootOptionMenu.Head);
+
+ //
+ // Get the BootOrder from the Var
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+ if (BootOrderList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the BootNext from the Var
+ //
+ BootNext = BdsLibGetVariableAndSize (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ &BootNextSize
+ );
+
+ if (BootNext != NULL) {
+ if (BootNextSize != sizeof (UINT16)) {
+ FreePool (BootNext);
+ BootNext = NULL;
+ }
+ }
+
+ for (Index = 0; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", BootOrderList[Index]);
+ //
+ // Get all loadoptions from the VAR
+ //
+ LoadOptionFromVar = BdsLibGetVariableAndSize (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+ if (LoadOptionFromVar == NULL) {
+ continue;
+ }
+
+ LoadOption = AllocateZeroPool (BootOptionSize);
+ if (LoadOption == NULL) {
+ continue;
+ }
+
+ CopyMem (LoadOption, LoadOptionFromVar, BootOptionSize);
+ FreePool (LoadOptionFromVar);
+
+ if (BootNext != NULL) {
+ BootNextFlag = (BOOLEAN) (*BootNext == BootOrderList[Index]);
+ } else {
+ BootNextFlag = FALSE;
+ }
+
+ if (0 == (*((UINT32 *) LoadOption) & LOAD_OPTION_ACTIVE)) {
+ FreePool (LoadOption);
+ continue;
+ }
+ //
+ // BUGBUG: could not return EFI_OUT_OF_RESOURCES here directly.
+ // the buffer allocated already should be freed before returning.
+ //
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ LoadOptionPtr = LoadOption;
+ LoadOptionEnd = LoadOption + BootOptionSize;
+
+ NewMenuEntry->OptionNumber = BootOrderList[Index];
+ NewLoadContext->LoadOptionModified = FALSE;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->IsBootNext = BootNextFlag;
+
+ //
+ // Is a Legacy Device?
+ //
+ Ptr = (UINT8 *) LoadOption;
+
+ //
+ // Attribute = *(UINT32 *)Ptr;
+ //
+ Ptr += sizeof (UINT32);
+
+ //
+ // FilePathSize = *(UINT16 *)Ptr;
+ //
+ Ptr += sizeof (UINT16);
+
+ //
+ // Description = (CHAR16 *)Ptr;
+ //
+ Ptr += StrSize ((CHAR16 *) Ptr);
+
+ //
+ // Now Ptr point to Device Path
+ //
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Ptr;
+ if ((BBS_DEVICE_PATH == DevicePath->Type) && (BBS_BBS_DP == DevicePath->SubType)) {
+ NewLoadContext->IsLegacy = TRUE;
+ } else {
+ NewLoadContext->IsLegacy = FALSE;
+ }
+ //
+ // LoadOption is a pointer type of UINT8
+ // for easy use with following LOAD_OPTION
+ // embedded in this struct
+ //
+ NewLoadContext->LoadOption = LoadOption;
+ NewLoadContext->LoadOptionSize = BootOptionSize;
+
+ NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
+ NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
+
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ LoadOptionPtr += sizeof (UINT32);
+
+ NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
+ LoadOptionPtr += sizeof (UINT16);
+
+ StringSize = StrSize((UINT16*)LoadOptionPtr);
+
+ NewLoadContext->Description = AllocateCopyPool (StrSize((UINT16*)LoadOptionPtr), LoadOptionPtr);
+ ASSERT (NewLoadContext->Description != NULL);
+
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionStrDepository
+ );
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionHelpStrDepository
+ );
+ LoadOptionPtr += NewLoadContext->FilePathListLength;
+
+ if (LoadOptionPtr < LoadOptionEnd) {
+ OptionalDataSize = BootOptionSize -
+ sizeof (UINT32) -
+ sizeof (UINT16) -
+ StringSize -
+ NewLoadContext->FilePathListLength;
+
+ NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOptionPtr,
+ OptionalDataSize
+ );
+
+ NewLoadContext->OptionalDataSize = OptionalDataSize;
+ }
+
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ MenuCount++;
+ }
+
+ if (BootNext != NULL) {
+ FreePool (BootNext);
+ }
+ if (BootOrderList != NULL) {
+ FreePool (BootOrderList);
+ }
+ BootOptionMenu.MenuNumber = MenuCount;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Append file name to existing file name.
+
+ @param Str1 The existing file name
+ @param Str2 The file name to be appended
+
+ @return Allocate a new string to hold the appended result.
+ Caller is responsible to free the returned string.
+
+**/
+CHAR16 *
+BOpt_AppendFileName (
+ IN CHAR16 *Str1,
+ IN CHAR16 *Str2
+ )
+{
+ UINTN Size1;
+ UINTN Size2;
+ UINTN MaxLen;
+ CHAR16 *Str;
+ CHAR16 *TmpStr;
+ CHAR16 *Ptr;
+ CHAR16 *LastSlash;
+
+ Size1 = StrSize (Str1);
+ Size2 = StrSize (Str2);
+ MaxLen = (Size1 + Size2 + sizeof (CHAR16)) / sizeof (CHAR16);
+ Str = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (Str != NULL);
+
+ TmpStr = AllocateZeroPool (MaxLen * sizeof (CHAR16));
+ ASSERT (TmpStr != NULL);
+
+ StrCatS (Str, MaxLen, Str1);
+ if (!((*Str == '\\') && (*(Str + 1) == 0))) {
+ StrCatS (Str, MaxLen, L"\\");
+ }
+
+ StrCatS (Str, MaxLen, Str2);
+
+ Ptr = Str;
+ LastSlash = Str;
+ while (*Ptr != 0) {
+ if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '.' && *(Ptr + 3) == L'\\') {
+ //
+ // Convert "\Name\..\" to "\"
+ // DO NOT convert the .. if it is at the end of the string. This will
+ // break the .. behavior in changing directories.
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpyS (TmpStr, MaxLen, Ptr + 3);
+ StrCpyS (LastSlash, MaxLen - (UINTN) (LastSlash - Str), TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\' && *(Ptr + 1) == '.' && *(Ptr + 2) == '\\') {
+ //
+ // Convert a "\.\" to a "\"
+ //
+
+ //
+ // Use TmpStr as a backup, as StrCpyS in BaseLib does not handle copy of two strings
+ // that overlap.
+ //
+ StrCpyS (TmpStr, MaxLen, Ptr + 2);
+ StrCpyS (Ptr, MaxLen - (UINTN) (Ptr - Str), TmpStr);
+ Ptr = LastSlash;
+ } else if (*Ptr == '\\') {
+ LastSlash = Ptr;
+ }
+
+ Ptr++;
+ }
+
+ FreePool (TmpStr);
+
+ return Str;
+}
+
+/**
+
+ Check whether current FileName point to a valid
+ Efi Image File.
+
+ @param FileName File need to be checked.
+
+ @retval TRUE Is Efi Image
+ @retval FALSE Not a valid Efi Image
+
+**/
+BOOLEAN
+BOpt_IsEfiImageName (
+ IN UINT16 *FileName
+ )
+{
+ //
+ // Search for ".efi" extension
+ //
+ while (*FileName != L'\0') {
+ if (FileName[0] == '.') {
+ if (FileName[1] == 'e' || FileName[1] == 'E') {
+ if (FileName[2] == 'f' || FileName[2] == 'F') {
+ if (FileName[3] == 'i' || FileName[3] == 'I') {
+ return TRUE;
+ } else if (FileName[3] == 0x0000) {
+ return FALSE;
+ }
+ } else if (FileName[2] == 0x0000) {
+ return FALSE;
+ }
+ } else if (FileName[1] == 0x0000) {
+ return FALSE;
+ }
+ }
+
+ FileName += 1;
+ }
+
+ return FALSE;
+}
+
+/**
+
+ Check whether current FileName point to a valid Efi Application
+
+ @param Dir Pointer to current Directory
+ @param FileName Pointer to current File name.
+
+ @retval TRUE Is a valid Efi Application
+ @retval FALSE not a valid Efi Application
+
+**/
+BOOLEAN
+BOpt_IsEfiApp (
+ IN EFI_FILE_HANDLE Dir,
+ IN UINT16 *FileName
+ )
+{
+ UINTN BufferSize;
+ EFI_IMAGE_DOS_HEADER DosHdr;
+ UINT16 Subsystem;
+ EFI_FILE_HANDLE File;
+ EFI_STATUS Status;
+ EFI_IMAGE_OPTIONAL_HEADER_UNION PeHdr;
+
+ Status = Dir->Open (Dir, &File, FileName, EFI_FILE_MODE_READ, 0);
+
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ BufferSize = sizeof (EFI_IMAGE_DOS_HEADER);
+ File->Read (File, &BufferSize, &DosHdr);
+ if (DosHdr.e_magic != EFI_IMAGE_DOS_SIGNATURE) {
+ File->Close (File);
+ return FALSE;
+ }
+
+ File->SetPosition (File, DosHdr.e_lfanew);
+ BufferSize = sizeof (EFI_IMAGE_OPTIONAL_HEADER_UNION);
+ File->Read (File, &BufferSize, &PeHdr);
+ if (PeHdr.Pe32.Signature != EFI_IMAGE_NT_SIGNATURE) {
+ File->Close (File);
+ return FALSE;
+ }
+ //
+ // Determine PE type and read subsytem
+ //
+ if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR32_MAGIC) {
+ Subsystem = PeHdr.Pe32.OptionalHeader.Subsystem;
+ } else if (PeHdr.Pe32.OptionalHeader.Magic == EFI_IMAGE_NT_OPTIONAL_HDR64_MAGIC) {
+ Subsystem = PeHdr.Pe32Plus.OptionalHeader.Subsystem;
+ } else {
+ return FALSE;
+ }
+
+ if (Subsystem == EFI_IMAGE_SUBSYSTEM_EFI_APPLICATION) {
+ File->Close (File);
+ return TRUE;
+ } else {
+ File->Close (File);
+ return FALSE;
+ }
+}
+
+/**
+
+ Find drivers that will be added as Driver#### variables from handles
+ in current system environment
+ All valid handles in the system except those consume SimpleFs, LoadFile
+ are stored in DriverMenu for future use.
+
+ @retval EFI_SUCCESS The function complets successfully.
+ @return Other value if failed to build the DriverMenu.
+
+**/
+EFI_STATUS
+BOpt_FindDrivers (
+ VOID
+ )
+{
+ UINTN NoDevicePathHandles;
+ EFI_HANDLE *DevicePathHandle;
+ UINTN Index;
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_HANDLE_CONTEXT *NewHandleContext;
+ EFI_HANDLE CurHandle;
+ UINTN OptionNumber;
+ EFI_SIMPLE_FILE_SYSTEM_PROTOCOL *SimpleFs;
+ EFI_LOAD_FILE_PROTOCOL *LoadFile;
+
+ SimpleFs = NULL;
+ LoadFile = NULL;
+
+ InitializeListHead (&DriverMenu.Head);
+
+ //
+ // At first, get all handles that support Device Path
+ // protocol which is the basic requirement for
+ // Driver####
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDevicePathProtocolGuid,
+ NULL,
+ &NoDevicePathHandles,
+ &DevicePathHandle
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ OptionNumber = 0;
+ for (Index = 0; Index < NoDevicePathHandles; Index++) {
+ CurHandle = DevicePathHandle[Index];
+
+ Status = gBS->HandleProtocol (
+ CurHandle,
+ &gEfiSimpleFileSystemProtocolGuid,
+ (VOID **) &SimpleFs
+ );
+ if (Status == EFI_SUCCESS) {
+ continue;
+ }
+
+ Status = gBS->HandleProtocol (
+ CurHandle,
+ &gEfiLoadFileProtocolGuid,
+ (VOID **) &LoadFile
+ );
+ if (Status == EFI_SUCCESS) {
+ continue;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_HANDLE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ FreePool (DevicePathHandle);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewHandleContext = (BM_HANDLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewHandleContext->Handle = CurHandle;
+ NewHandleContext->DevicePath = DevicePathFromHandle (CurHandle);
+ NewMenuEntry->DisplayString = DevicePathToStr (NewHandleContext->DevicePath);
+ NewMenuEntry->HelpString = NULL;
+ NewMenuEntry->OptionNumber = OptionNumber;
+ OptionNumber++;
+ InsertTailList (&DriverMenu.Head, &NewMenuEntry->Link);
+
+ }
+
+ if (DevicePathHandle != NULL) {
+ FreePool (DevicePathHandle);
+ }
+
+ DriverMenu.MenuNumber = OptionNumber;
+ return EFI_SUCCESS;
+}
+
+/**
+
+ Get the Option Number that has not been allocated for use.
+
+ @param Type The type of Option.
+
+ @return The available Option Number.
+
+**/
+UINT16
+BOpt_GetOptionNumber (
+ CHAR16 *Type
+ )
+{
+ UINT16 *OrderList;
+ UINTN OrderListSize;
+ UINTN Index;
+ CHAR16 StrTemp[20];
+ UINT16 *OptionBuffer;
+ UINT16 OptionNumber;
+ UINTN OptionSize;
+
+ OrderListSize = 0;
+ OrderList = NULL;
+ OptionNumber = 0;
+ Index = 0;
+
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%sOrder", Type);
+
+ OrderList = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ &OrderListSize
+ );
+
+ for (OptionNumber = 0; ; OptionNumber++) {
+ if (OrderList != NULL) {
+ for (Index = 0; Index < OrderListSize / sizeof (UINT16); Index++) {
+ if (OptionNumber == OrderList[Index]) {
+ break;
+ }
+ }
+ }
+
+ if (Index < OrderListSize / sizeof (UINT16)) {
+ //
+ // The OptionNumber occurs in the OrderList, continue to use next one
+ //
+ continue;
+ }
+ UnicodeSPrint (StrTemp, sizeof (StrTemp), L"%s%04x", Type, (UINTN) OptionNumber);
+ DEBUG((EFI_D_ERROR,"Option = %s\n", StrTemp));
+ OptionBuffer = BdsLibGetVariableAndSize (
+ StrTemp,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (NULL == OptionBuffer) {
+ //
+ // The Boot[OptionNumber] / Driver[OptionNumber] NOT occurs, we found it
+ //
+ break;
+ }
+ }
+
+ return OptionNumber;
+}
+
+/**
+
+ Get the Option Number for Boot#### that does not used.
+
+ @return The available Option Number.
+
+**/
+UINT16
+BOpt_GetBootOptionNumber (
+ VOID
+ )
+{
+ return BOpt_GetOptionNumber (L"Boot");
+}
+
+/**
+
+ Get the Option Number for Driver#### that does not used.
+
+ @return The unused Option Number.
+
+**/
+UINT16
+BOpt_GetDriverOptionNumber (
+ VOID
+ )
+{
+ return BOpt_GetOptionNumber (L"Driver");
+}
+
+/**
+
+ Build up all DriverOptionMenu
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCESS The functin completes successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to compete the operation.
+ @retval EFI_NOT_FOUND Fail to get "DriverOrder" variable.
+
+**/
+EFI_STATUS
+BOpt_GetDriverOptions (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Index;
+ UINT16 DriverString[12];
+ UINT8 *LoadOptionFromVar;
+ UINT8 *LoadOption;
+ UINTN DriverOptionSize;
+
+ UINT16 *DriverOrderList;
+ UINTN DriverOrderListSize;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT8 *LoadOptionPtr;
+ UINTN StringSize;
+ UINTN OptionalDataSize;
+ UINT8 *LoadOptionEnd;
+
+ DriverOrderListSize = 0;
+ DriverOrderList = NULL;
+ DriverOptionSize = 0;
+ LoadOptionFromVar = NULL;
+ BOpt_FreeMenu (&DriverOptionMenu);
+ InitializeListHead (&DriverOptionMenu.Head);
+ //
+ // Get the DriverOrder from the Var
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+ if (DriverOrderList == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < DriverOrderListSize / sizeof (UINT16); Index++) {
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ DriverOrderList[Index]
+ );
+ //
+ // Get all loadoptions from the VAR
+ //
+ LoadOptionFromVar = BdsLibGetVariableAndSize (
+ DriverString,
+ &gEfiGlobalVariableGuid,
+ &DriverOptionSize
+ );
+ if (LoadOptionFromVar == NULL) {
+ continue;
+ }
+
+ LoadOption = AllocateZeroPool (DriverOptionSize);
+ if (LoadOption == NULL) {
+ continue;
+ }
+
+ CopyMem (LoadOption, LoadOptionFromVar, DriverOptionSize);
+ FreePool (LoadOptionFromVar);
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ LoadOptionPtr = LoadOption;
+ LoadOptionEnd = LoadOption + DriverOptionSize;
+ NewMenuEntry->OptionNumber = DriverOrderList[Index];
+ NewLoadContext->LoadOptionModified = FALSE;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->IsLegacy = FALSE;
+
+ //
+ // LoadOption is a pointer type of UINT8
+ // for easy use with following LOAD_OPTION
+ // embedded in this struct
+ //
+ NewLoadContext->LoadOption = LoadOption;
+ NewLoadContext->LoadOptionSize = DriverOptionSize;
+
+ NewLoadContext->Attributes = *(UINT32 *) LoadOptionPtr;
+ NewLoadContext->IsActive = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_ACTIVE);
+
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ LoadOptionPtr += sizeof (UINT32);
+
+ NewLoadContext->FilePathListLength = *(UINT16 *) LoadOptionPtr;
+ LoadOptionPtr += sizeof (UINT16);
+
+ StringSize = StrSize ((UINT16 *) LoadOptionPtr);
+ NewLoadContext->Description = AllocateZeroPool (StringSize);
+ ASSERT (NewLoadContext->Description != NULL);
+ CopyMem (
+ NewLoadContext->Description,
+ (UINT16 *) LoadOptionPtr,
+ StringSize
+ );
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+
+ LoadOptionPtr += StringSize;
+
+ NewLoadContext->FilePathList = AllocateZeroPool (NewLoadContext->FilePathListLength);
+ ASSERT (NewLoadContext->FilePathList != NULL);
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (EFI_DEVICE_PATH_PROTOCOL *) LoadOptionPtr,
+ NewLoadContext->FilePathListLength
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionStrDepository
+ );
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionHelpStrDepository
+ );
+ LoadOptionPtr += NewLoadContext->FilePathListLength;
+
+ if (LoadOptionPtr < LoadOptionEnd) {
+ OptionalDataSize = DriverOptionSize -
+ sizeof (UINT32) -
+ sizeof (UINT16) -
+ StringSize -
+ NewLoadContext->FilePathListLength;
+
+ NewLoadContext->OptionalData = AllocateZeroPool (OptionalDataSize);
+ ASSERT (NewLoadContext->OptionalData != NULL);
+ CopyMem (
+ NewLoadContext->OptionalData,
+ LoadOptionPtr,
+ OptionalDataSize
+ );
+
+ NewLoadContext->OptionalDataSize = OptionalDataSize;
+ }
+
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+
+ }
+
+ if (DriverOrderList != NULL) {
+ FreePool (DriverOrderList);
+ }
+ DriverOptionMenu.MenuNumber = Index;
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Get option number according to Boot#### and BootOrder variable.
+ The value is saved as #### + 1.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BMM_FAKE_NV_DATA *BmmConfig;
+ UINT16 Index;
+ UINT16 OptionOrderIndex;
+ UINTN DeviceType;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+
+ ASSERT (CallbackData != NULL);
+
+ DeviceType = (UINTN) -1;
+ BmmConfig = &CallbackData->BmmFakeNvData;
+ ZeroMem (BmmConfig->BootOptionOrder, sizeof (BmmConfig->BootOptionOrder));
+
+ for (Index = 0, OptionOrderIndex = 0; ((Index < BootOptionMenu.MenuNumber) &&
+ (OptionOrderIndex < (sizeof (BmmConfig->BootOptionOrder) / sizeof (BmmConfig->BootOptionOrder[0]))));
+ Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewLoadContext->IsLegacy) {
+ if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
+ DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
+ } else {
+ //
+ // Only show one legacy boot option for the same device type
+ // assuming the boot options are grouped by the device type
+ //
+ continue;
+ }
+ }
+ BmmConfig->BootOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
+ }
+}
+
+/**
+ According to LegacyDevOrder variable to get legacy FD\HD\CD\NET\BEV
+ devices list .
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetLegacyDeviceOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Index;
+ UINTN OptionIndex;
+ UINT16 PageIdList[5];
+ UINTN PageNum;
+ UINTN VarSize;
+ UINT8 *VarData;
+ UINT8 *WorkingVarData;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ UINT16 VarDevOrder;
+ UINT8 *DisMap;
+ BM_MENU_OPTION *OptionMenu;
+ BBS_TYPE BbsType;
+ UINT8 *LegacyOrder;
+ UINT8 *OldData;
+ UINTN Pos;
+ UINTN Bit;
+
+ ASSERT (CallbackData != NULL);
+
+ PageIdList[0] = FORM_SET_FD_ORDER_ID;
+ PageIdList[1] = FORM_SET_HD_ORDER_ID;
+ PageIdList[2] = FORM_SET_CD_ORDER_ID;
+ PageIdList[3] = FORM_SET_NET_ORDER_ID;
+ PageIdList[4] = FORM_SET_BEV_ORDER_ID;
+ OptionMenu = NULL;
+ BbsType = 0;
+ LegacyOrder = NULL;
+ OldData = NULL;
+ DisMap = ZeroMem (CallbackData->BmmFakeNvData.DisableMap, sizeof (CallbackData->BmmFakeNvData.DisableMap));
+ PageNum = sizeof (PageIdList) / sizeof (PageIdList[0]);
+ VarData = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &VarSize
+ );
+
+ for (Index = 0; Index < PageNum; Index++) {
+ switch (PageIdList[Index]) {
+
+ case FORM_SET_FD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
+ BbsType = BBS_FLOPPY;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
+ break;
+
+ case FORM_SET_HD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
+ BbsType = BBS_HARDDISK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
+ break;
+
+ case FORM_SET_CD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
+ BbsType = BBS_CDROM;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
+ break;
+
+ case FORM_SET_NET_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
+ BbsType = BBS_EMBED_NETWORK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
+ break;
+
+ default:
+ ASSERT (PageIdList[Index] == FORM_SET_BEV_ORDER_ID);
+ OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
+ BbsType = BBS_BEV_DEVICE;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
+ break;
+ }
+
+ if (NULL != VarData) {
+ WorkingVarData = VarData;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
+ while (WorkingVarData < VarData + VarSize) {
+ if (DevOrder->BbsType == BbsType) {
+ break;
+ }
+
+ WorkingVarData = (UINT8 *)((UINTN)WorkingVarData + sizeof (BBS_TYPE));
+ WorkingVarData += *(UINT16 *) WorkingVarData;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) WorkingVarData;
+ }
+ for (OptionIndex = 0; OptionIndex < OptionMenu->MenuNumber; OptionIndex++) {
+ VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + OptionIndex * sizeof (UINT16));
+ if (0xFF00 == (VarDevOrder & 0xFF00)) {
+ LegacyOrder[OptionIndex] = 0xFF;
+ Pos = (VarDevOrder & 0xFF) / 8;
+ Bit = 7 - ((VarDevOrder & 0xFF) % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ } else {
+ LegacyOrder[OptionIndex] = (UINT8) (VarDevOrder & 0xFF);
+ }
+ }
+ CopyMem (OldData, LegacyOrder, 100);
+ }
+ }
+}
+
+/**
+ Get driver option order from globalc DriverOptionMenu.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BMM_FAKE_NV_DATA *BmmConfig;
+ UINT16 Index;
+ UINT16 OptionOrderIndex;
+ UINTN DeviceType;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+
+ ASSERT (CallbackData != NULL);
+
+ DeviceType = (UINTN) -1;
+ BmmConfig = &CallbackData->BmmFakeNvData;
+ ZeroMem (BmmConfig->DriverOptionOrder, sizeof (BmmConfig->DriverOptionOrder));
+
+ for (Index = 0, OptionOrderIndex = 0; ((Index < DriverOptionMenu.MenuNumber) &&
+ (OptionOrderIndex < (sizeof (BmmConfig->DriverOptionOrder) / sizeof (BmmConfig->DriverOptionOrder[0]))));
+ Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewLoadContext->IsLegacy) {
+ if (((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType != DeviceType) {
+ DeviceType = ((BBS_BBS_DEVICE_PATH *) NewLoadContext->FilePathList)->DeviceType;
+ } else {
+ //
+ // Only show one legacy boot option for the same device type
+ // assuming the boot options are grouped by the device type
+ //
+ continue;
+ }
+ }
+ BmmConfig->DriverOptionOrder[OptionOrderIndex++] = (UINT32) (NewMenuEntry->OptionNumber + 1);
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c
new file mode 100644
index 0000000000..1854b98c36
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/ConsoleOption.c
@@ -0,0 +1,1198 @@
+/** @file
+ handles console redirection from boot manager
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+UART_FLOW_CONTROL_DEVICE_PATH mFlowControlDevicePath =
+{
+ {
+ MESSAGING_DEVICE_PATH,
+ MSG_VENDOR_DP,
+ {
+ (UINT8)(sizeof(UART_FLOW_CONTROL_DEVICE_PATH)),
+ (UINT8)((sizeof(UART_FLOW_CONTROL_DEVICE_PATH)) >> 8)
+ }
+ },
+ DEVICE_PATH_MESSAGING_UART_FLOW_CONTROL,
+ UART_FLOW_CONTROL_HARDWARE
+};
+
+/**
+ Check the device path node whether it's the Flow Control node or not.
+
+ @param[in] FlowControl The device path node to be checked.
+
+ @retval TRUE It's the Flow Control node.
+ @retval FALSE It's not.
+
+**/
+BOOLEAN
+IsUartFlowControlNode (
+ IN UART_FLOW_CONTROL_DEVICE_PATH *FlowControl
+ )
+{
+ return (BOOLEAN) (
+ (DevicePathType (FlowControl) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (FlowControl) == MSG_VENDOR_DP) &&
+ (CompareGuid (&FlowControl->Guid, &gEfiUartDevicePathGuid))
+ );
+}
+
+/**
+ Check whether the device path node is ISA Serial Node.
+
+ @param Acpi Device path node to be checked
+
+ @retval TRUE It's ISA Serial Node.
+ @retval FALSE It's NOT ISA Serial Node.
+
+**/
+BOOLEAN
+IsIsaSerialNode (
+ IN ACPI_HID_DEVICE_PATH *Acpi
+ )
+{
+ return (BOOLEAN) (
+ (DevicePathType (Acpi) == ACPI_DEVICE_PATH) &&
+ (DevicePathSubType (Acpi) == ACPI_DP) &&
+ (ReadUnaligned32 (&Acpi->HID) == EISA_PNP_ID (0x0501))
+ );
+}
+
+/**
+ Update Com Ports attributes from DevicePath
+
+ @param DevicePath DevicePath that contains Com ports
+
+ @retval EFI_SUCCESS The update is successful.
+
+**/
+EFI_STATUS
+UpdateComAttributeFromVariable (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ );
+
+/**
+ Update the multi-instance device path of Terminal Device based on
+ the global TerminalMenu. If ChangeTernimal is TRUE, the terminal
+ device path in the Terminal Device in TerminalMenu is also updated.
+
+ @param DevicePath The multi-instance device path.
+ @param ChangeTerminal TRUE, then device path in the Terminal Device
+ in TerminalMenu is also updated; FALSE, no update.
+
+ @return EFI_SUCCESS The function completes successfully.
+
+**/
+EFI_STATUS
+ChangeTerminalDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL **DevicePath,
+ IN BOOLEAN ChangeTerminal
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *Node1;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UART_DEVICE_PATH *Uart1;
+ UINTN Com;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
+
+ Node = *DevicePath;
+ Node = NextDevicePathNode (Node);
+ Com = 0;
+ while (!IsDevicePathEnd (Node)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (IsIsaSerialNode (Acpi)) {
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
+ }
+
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Com);
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ Uart = (UART_DEVICE_PATH *) Node;
+ CopyMem (
+ &Uart->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+
+ FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node);
+ if (IsUartFlowControlNode (FlowControlNode)) {
+ FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl;
+ } else {
+ //
+ // Append the Flow control device node when user enable flow control.
+ //
+ if (NewTerminalContext->FlowControl != 0) {
+ mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl;
+ *DevicePath = AppendDevicePathNode (
+ *DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath)
+ );
+ }
+ }
+
+ //
+ // Change the device path in the ComPort
+ //
+ if (ChangeTerminal) {
+ Node1 = NewTerminalContext->DevicePath;
+ Node1 = NextDevicePathNode (Node1);
+ while (!IsDevicePathEnd (Node1)) {
+ if ((DevicePathType (Node1) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node1) == MSG_UART_DP)) {
+ Uart1 = (UART_DEVICE_PATH *) Node1;
+ CopyMem (
+ &Uart1->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart1->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart1->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart1->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+ break;
+ }
+ //
+ // end if
+ //
+ Node1 = NextDevicePathNode (Node1);
+ }
+ //
+ // end while
+ //
+ break;
+ }
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ Update the device path that describing a terminal device
+ based on the new BaudRate, Data Bits, parity and Stop Bits
+ set.
+
+ @param DevicePath terminal device's path
+
+**/
+VOID
+ChangeVariableDevicePath (
+ IN OUT EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UINTN Com;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ Node = DevicePath;
+ Node = NextDevicePathNode (Node);
+ Com = 0;
+ while (!IsDevicePathEnd (Node)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (IsIsaSerialNode (Acpi)) {
+ CopyMem (&Com, &Acpi->UID, sizeof (UINT32));
+ }
+
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &TerminalMenu,
+ Com
+ );
+ ASSERT (NewMenuEntry != NULL);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ Uart = (UART_DEVICE_PATH *) Node;
+ CopyMem (
+ &Uart->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &Uart->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+}
+
+/**
+ Retrieve ACPI UID of UART from device path
+
+ @param Handle The handle for the UART device.
+ @param AcpiUid The ACPI UID on output.
+
+ @retval TRUE Find valid UID from device path
+ @retval FALSE Can't find
+
+**/
+BOOLEAN
+RetrieveUartUid (
+ IN EFI_HANDLE Handle,
+ IN OUT UINT32 *AcpiUid
+ )
+{
+ EFI_STATUS Status;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ Acpi = NULL;
+ for (; !IsDevicePathEnd (DevicePath); DevicePath = NextDevicePathNode (DevicePath)) {
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (DevicePath) == MSG_UART_DP)) {
+ break;
+ }
+ //
+ // Acpi points to the node before the Uart node
+ //
+ Acpi = (ACPI_HID_DEVICE_PATH *) DevicePath;
+ }
+
+ if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
+ if (AcpiUid != NULL) {
+ CopyMem (AcpiUid, &Acpi->UID, sizeof (UINT32));
+ }
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Sort Uart handles array with Acpi->UID from low to high.
+
+ @param Handles EFI_SERIAL_IO_PROTOCOL handle buffer
+ @param NoHandles EFI_SERIAL_IO_PROTOCOL handle count
+**/
+VOID
+SortedUartHandle (
+ IN EFI_HANDLE *Handles,
+ IN UINTN NoHandles
+ )
+{
+ UINTN Index1;
+ UINTN Index2;
+ UINTN Position;
+ UINT32 AcpiUid1;
+ UINT32 AcpiUid2;
+ UINT32 TempAcpiUid;
+ EFI_HANDLE TempHandle;
+
+ for (Index1 = 0; Index1 < NoHandles-1; Index1++) {
+ if (!RetrieveUartUid (Handles[Index1], &AcpiUid1)) {
+ continue;
+ }
+ TempHandle = Handles[Index1];
+ Position = Index1;
+ TempAcpiUid = AcpiUid1;
+
+ for (Index2 = Index1+1; Index2 < NoHandles; Index2++) {
+ if (!RetrieveUartUid (Handles[Index2], &AcpiUid2)) {
+ continue;
+ }
+ if (AcpiUid2 < TempAcpiUid) {
+ TempAcpiUid = AcpiUid2;
+ TempHandle = Handles[Index2];
+ Position = Index2;
+ }
+ }
+ Handles[Position] = Handles[Index1];
+ Handles[Index1] = TempHandle;
+ }
+}
+
+/**
+ Test whether DevicePath is a valid Terminal
+
+
+ @param DevicePath DevicePath to be checked
+ @param Termi If DevicePath is valid Terminal, terminal type is returned.
+ @param Com If DevicePath is valid Terminal, Com Port type is returned.
+
+ @retval TRUE If DevicePath point to a Terminal.
+ @retval FALSE If DevicePath does not point to a Terminal.
+
+**/
+BOOLEAN
+IsTerminalDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT TYPE_OF_TERMINAL *Termi,
+ OUT UINTN *Com
+ );
+
+/**
+ Build a list containing all serial devices.
+
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_UNSUPPORTED No serial ports present.
+
+**/
+EFI_STATUS
+LocateSerialIo (
+ VOID
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+ UINTN NoHandles;
+ EFI_HANDLE *Handles;
+ EFI_STATUS Status;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_SERIAL_IO_PROTOCOL *SerialIo;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ EFI_DEVICE_PATH_PROTOCOL *NewDevicePath;
+ VENDOR_DEVICE_PATH Vendor;
+ UINT32 FlowControl;
+ //
+ // Get all handles that have SerialIo protocol installed
+ //
+ InitializeListHead (&TerminalMenu.Head);
+ TerminalMenu.MenuNumber = 0;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSerialIoProtocolGuid,
+ NULL,
+ &NoHandles,
+ &Handles
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // No serial ports present
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Sort Uart handles array with Acpi->UID from low to high
+ // then Terminal menu can be built from low Acpi->UID to high Acpi->UID
+ //
+ SortedUartHandle (Handles, NoHandles);
+
+ for (Index = 0; Index < NoHandles; Index++) {
+ //
+ // Check to see whether the handle has DevicePath Protocol installed
+ //
+ gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+
+ Acpi = NULL;
+ for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ break;
+ }
+ //
+ // Acpi points to the node before Uart node
+ //
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ }
+
+ if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_TERMINAL_CONTEXT_SELECT);
+ if (NewMenuEntry == NULL) {
+ FreePool (Handles);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ CopyMem (&NewMenuEntry->OptionNumber, &Acpi->UID, sizeof (UINT32));
+ NewTerminalContext->DevicePath = DuplicateDevicePath (DevicePath);
+ //
+ // BugBug: I have no choice, calling EfiLibStrFromDatahub will hang the system!
+ // coz' the misc data for each platform is not correct, actually it's the device path stored in
+ // datahub which is not completed, so a searching for end of device path will enter a
+ // dead-loop.
+ //
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (DevicePath);
+ if (NULL == NewMenuEntry->DisplayString) {
+ NewMenuEntry->DisplayString = DevicePathToStr (DevicePath);
+ }
+
+ NewMenuEntry->HelpString = NULL;
+
+ gBS->HandleProtocol (
+ Handles[Index],
+ &gEfiSerialIoProtocolGuid,
+ (VOID **) &SerialIo
+ );
+
+ CopyMem (
+ &NewTerminalContext->BaudRate,
+ &SerialIo->Mode->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &NewTerminalContext->DataBits,
+ &SerialIo->Mode->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->Parity,
+ &SerialIo->Mode->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->StopBits,
+ &SerialIo->Mode->StopBits,
+ sizeof (UINT8)
+ );
+
+ NewTerminalContext->FlowControl = 0;
+ SerialIo->GetControl(SerialIo, &FlowControl);
+ if ((FlowControl & EFI_SERIAL_HARDWARE_FLOW_CONTROL_ENABLE) != 0) {
+ NewTerminalContext->FlowControl = UART_FLOW_CONTROL_HARDWARE;
+ }
+
+ InsertTailList (&TerminalMenu.Head, &NewMenuEntry->Link);
+ TerminalMenu.MenuNumber++;
+ }
+ }
+ if (Handles != NULL) {
+ FreePool (Handles);
+ }
+
+ //
+ // Get L"ConOut", L"ConIn" and L"ErrOut" from the Var
+ //
+ OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
+ InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
+ ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
+ if (OutDevicePath != NULL) {
+ UpdateComAttributeFromVariable (OutDevicePath);
+ }
+
+ if (InpDevicePath != NULL) {
+ UpdateComAttributeFromVariable (InpDevicePath);
+ }
+
+ if (ErrDevicePath != NULL) {
+ UpdateComAttributeFromVariable (ErrDevicePath);
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+
+ NewTerminalContext->TerminalType = 0;
+ NewTerminalContext->IsConIn = FALSE;
+ NewTerminalContext->IsConOut = FALSE;
+ NewTerminalContext->IsStdErr = FALSE;
+
+ Vendor.Header.Type = MESSAGING_DEVICE_PATH;
+ Vendor.Header.SubType = MSG_VENDOR_DP;
+
+ for (Index2 = 0; Index2 < 4; Index2++) {
+ CopyMem (&Vendor.Guid, &TerminalTypeGuid[Index2], sizeof (EFI_GUID));
+ SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
+ NewDevicePath = AppendDevicePathNode (
+ NewTerminalContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
+ );
+ if (NewMenuEntry->HelpString != NULL) {
+ FreePool (NewMenuEntry->HelpString);
+ }
+ //
+ // NewMenuEntry->HelpString = DevicePathToStr (NewDevicePath);
+ // NewMenuEntry->DisplayString = NewMenuEntry->HelpString;
+ //
+ NewMenuEntry->HelpString = NULL;
+
+ if (BdsLibMatchDevicePaths (OutDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConOut = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (BdsLibMatchDevicePaths (InpDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsConIn = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+
+ if (BdsLibMatchDevicePaths (ErrDevicePath, NewDevicePath)) {
+ NewTerminalContext->IsStdErr = TRUE;
+ NewTerminalContext->TerminalType = (UINT8) Index2;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update Com Ports attributes from DevicePath
+
+ @param DevicePath DevicePath that contains Com ports
+
+ @retval EFI_SUCCESS The update is successful.
+ @retval EFI_NOT_FOUND Can not find specific menu entry
+**/
+EFI_STATUS
+UpdateComAttributeFromVariable (
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ EFI_DEVICE_PATH_PROTOCOL *SerialNode;
+ ACPI_HID_DEVICE_PATH *Acpi;
+ UART_DEVICE_PATH *Uart;
+ UART_DEVICE_PATH *Uart1;
+ UINTN TerminalNumber;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ UINTN Index;
+ UART_FLOW_CONTROL_DEVICE_PATH *FlowControlNode;
+ BOOLEAN HasFlowControlNode;
+
+ HasFlowControlNode = FALSE;
+ Node = DevicePath;
+ Node = NextDevicePathNode (Node);
+ TerminalNumber = 0;
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ while (!IsDevicePathEnd (Node)) {
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ if (IsIsaSerialNode (Acpi)) {
+ CopyMem (&TerminalNumber, &Acpi->UID, sizeof (UINT32));
+ }
+
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ Uart = (UART_DEVICE_PATH *) Node;
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalNumber);
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ CopyMem (
+ &NewTerminalContext->BaudRate,
+ &Uart->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &NewTerminalContext->DataBits,
+ &Uart->DataBits,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->Parity,
+ &Uart->Parity,
+ sizeof (UINT8)
+ );
+
+ CopyMem (
+ &NewTerminalContext->StopBits,
+ &Uart->StopBits,
+ sizeof (UINT8)
+ );
+
+ FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (Node);
+ if (IsUartFlowControlNode (FlowControlNode)) {
+ HasFlowControlNode = TRUE;
+ NewTerminalContext->FlowControl = (UINT8) ReadUnaligned32 (&FlowControlNode->FlowControlMap);
+ } else if (NewTerminalContext->FlowControl != 0) {
+ //
+ // No Flow Control device path node, assumption no Flow control
+ //
+ NewTerminalContext->FlowControl = 0;
+ }
+
+ SerialNode = NewTerminalContext->DevicePath;
+ SerialNode = NextDevicePathNode (SerialNode);
+ while (!IsDevicePathEnd (SerialNode)) {
+ if ((DevicePathType (SerialNode) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (SerialNode) == MSG_UART_DP)) {
+ //
+ // Update following device paths according to
+ // previous acquired uart attributes
+ //
+ Uart1 = (UART_DEVICE_PATH *) SerialNode;
+ CopyMem (
+ &Uart1->BaudRate,
+ &NewTerminalContext->BaudRate,
+ sizeof (UINT64)
+ );
+
+ CopyMem (
+ &Uart1->DataBits,
+ &NewTerminalContext->DataBits,
+ sizeof (UINT8)
+ );
+ CopyMem (
+ &Uart1->Parity,
+ &NewTerminalContext->Parity,
+ sizeof (UINT8)
+ );
+ CopyMem (
+ &Uart1->StopBits,
+ &NewTerminalContext->StopBits,
+ sizeof (UINT8)
+ );
+
+ FlowControlNode = (UART_FLOW_CONTROL_DEVICE_PATH *) NextDevicePathNode (SerialNode);
+ if (IsUartFlowControlNode (FlowControlNode)) {
+ FlowControlNode->FlowControlMap = NewTerminalContext->FlowControl;
+ } else {
+ if (HasFlowControlNode) {
+ mFlowControlDevicePath.FlowControlMap = NewTerminalContext->FlowControl;
+ NewTerminalContext->DevicePath = AppendDevicePathNode (
+ NewTerminalContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) (&mFlowControlDevicePath)
+ );
+ }
+ }
+ break;
+ }
+
+ SerialNode = NextDevicePathNode (SerialNode);
+ }
+ //
+ // end while
+ //
+ }
+
+ Node = NextDevicePathNode (Node);
+ }
+ //
+ // end while
+ //
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build up Console Menu based on types passed in. The type can
+ be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
+ and BM_CONSOLE_ERR_CONTEXT_SELECT.
+
+ @param ConsoleMenuType Can be BM_CONSOLE_IN_CONTEXT_SELECT, BM_CONSOLE_OUT_CONTEXT_SELECT
+ and BM_CONSOLE_ERR_CONTEXT_SELECT.
+
+ @retval EFI_UNSUPPORTED The type passed in is not in the 3 types defined.
+ @retval EFI_NOT_FOUND If the EFI Variable defined in UEFI spec with name "ConOutDev",
+ "ConInDev" or "ConErrDev" doesn't exists.
+ @retval EFI_OUT_OF_RESOURCES Not enough resource to complete the operations.
+ @retval EFI_SUCCESS Function completes successfully.
+
+**/
+EFI_STATUS
+GetConsoleMenu (
+ IN UINTN ConsoleMenuType
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *AllDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *MultiDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePathInst;
+ UINTN Size;
+ UINTN AllCount;
+ UINTN Index;
+ UINTN Index2;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ TYPE_OF_TERMINAL Terminal;
+ UINTN Com;
+ BM_MENU_OPTION *ConsoleMenu;
+
+ DevicePath = NULL;
+ AllDevicePath = NULL;
+ AllCount = 0;
+ switch (ConsoleMenuType) {
+ case BM_CONSOLE_IN_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleInpMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ConIn",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ConInDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ case BM_CONSOLE_OUT_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleOutMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ConOut",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ConOutDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ case BM_CONSOLE_ERR_CONTEXT_SELECT:
+ ConsoleMenu = &ConsoleErrMenu;
+ DevicePath = EfiLibGetVariable (
+ L"ErrOut",
+ &gEfiGlobalVariableGuid
+ );
+
+ AllDevicePath = EfiLibGetVariable (
+ L"ErrOutDev",
+ &gEfiGlobalVariableGuid
+ );
+ break;
+
+ default:
+ return EFI_UNSUPPORTED;
+ }
+
+ if (NULL == AllDevicePath) {
+ return EFI_NOT_FOUND;
+ }
+
+ InitializeListHead (&ConsoleMenu->Head);
+
+ AllCount = EfiDevicePathInstanceCount (AllDevicePath);
+ ConsoleMenu->MenuNumber = 0;
+ //
+ // Following is menu building up for Console Devices selected.
+ //
+ MultiDevicePath = AllDevicePath;
+ Index2 = 0;
+ for (Index = 0; Index < AllCount; Index++) {
+ DevicePathInst = GetNextDevicePathInstance (&MultiDevicePath, &Size);
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_CONSOLE_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ NewMenuEntry->OptionNumber = Index2;
+
+ NewConsoleContext->DevicePath = DuplicateDevicePath (DevicePathInst);
+ ASSERT (NewConsoleContext->DevicePath != NULL);
+ NewMenuEntry->DisplayString = EfiLibStrFromDatahub (NewConsoleContext->DevicePath);
+ if (NULL == NewMenuEntry->DisplayString) {
+ NewMenuEntry->DisplayString = DevicePathToStr (NewConsoleContext->DevicePath);
+ }
+
+ NewConsoleContext->IsTerminal = IsTerminalDevicePath (
+ NewConsoleContext->DevicePath,
+ &Terminal,
+ &Com
+ );
+
+ NewConsoleContext->IsActive = BdsLibMatchDevicePaths (
+ DevicePath,
+ NewConsoleContext->DevicePath
+ );
+
+ if (NewConsoleContext->IsTerminal) {
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ } else {
+ Index2++;
+ ConsoleMenu->MenuNumber++;
+ InsertTailList (&ConsoleMenu->Head, &NewMenuEntry->Link);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Build up ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+ @retval EFI_SUCCESS The function always complete successfully.
+
+**/
+EFI_STATUS
+GetAllConsoles (
+ VOID
+ )
+{
+ GetConsoleMenu (BM_CONSOLE_IN_CONTEXT_SELECT);
+ GetConsoleMenu (BM_CONSOLE_OUT_CONTEXT_SELECT);
+ GetConsoleMenu (BM_CONSOLE_ERR_CONTEXT_SELECT);
+ return EFI_SUCCESS;
+}
+
+/**
+ Free ConsoleOutMenu, ConsoleInpMenu and ConsoleErrMenu
+
+ @retval EFI_SUCCESS The function always complete successfully.
+**/
+EFI_STATUS
+FreeAllConsoles (
+ VOID
+ )
+{
+ BOpt_FreeMenu (&ConsoleOutMenu);
+ BOpt_FreeMenu (&ConsoleInpMenu);
+ BOpt_FreeMenu (&ConsoleErrMenu);
+ BOpt_FreeMenu (&TerminalMenu);
+ return EFI_SUCCESS;
+}
+
+/**
+ Test whether DevicePath is a valid Terminal
+
+
+ @param DevicePath DevicePath to be checked
+ @param Termi If DevicePath is valid Terminal, terminal type is returned.
+ @param Com If DevicePath is valid Terminal, Com Port type is returned.
+
+ @retval TRUE If DevicePath point to a Terminal.
+ @retval FALSE If DevicePath does not point to a Terminal.
+
+**/
+BOOLEAN
+IsTerminalDevicePath (
+ IN EFI_DEVICE_PATH_PROTOCOL *DevicePath,
+ OUT TYPE_OF_TERMINAL *Termi,
+ OUT UINTN *Com
+ )
+{
+ BOOLEAN IsTerminal;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ VENDOR_DEVICE_PATH *Vendor;
+ UART_DEVICE_PATH *Uart;
+ ACPI_HID_DEVICE_PATH *Acpi;
+
+ IsTerminal = FALSE;
+
+ Uart = NULL;
+ Vendor = NULL;
+ Acpi = NULL;
+ for (Node = DevicePath; !IsDevicePathEnd (Node); Node = NextDevicePathNode (Node)) {
+ //
+ // Vendor points to the node before the End node
+ //
+ Vendor = (VENDOR_DEVICE_PATH *) Node;
+
+ if ((DevicePathType (Node) == MESSAGING_DEVICE_PATH) && (DevicePathSubType (Node) == MSG_UART_DP)) {
+ Uart = (UART_DEVICE_PATH *) Node;
+ }
+
+ if (Uart == NULL) {
+ //
+ // Acpi points to the node before the UART node
+ //
+ Acpi = (ACPI_HID_DEVICE_PATH *) Node;
+ }
+ }
+
+ if (Vendor == NULL ||
+ DevicePathType (Vendor) != MESSAGING_DEVICE_PATH ||
+ DevicePathSubType (Vendor) != MSG_VENDOR_DP ||
+ Uart == NULL) {
+ return FALSE;
+ }
+
+ //
+ // There are four kinds of Terminal types
+ // check to see whether this devicepath
+ // is one of that type
+ //
+ if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[0])) {
+ *Termi = TerminalTypePcAnsi;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[1])) {
+ *Termi = TerminalTypeVt100;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[2])) {
+ *Termi = TerminalTypeVt100Plus;
+ IsTerminal = TRUE;
+ } else {
+ if (CompareGuid (&Vendor->Guid, &TerminalTypeGuid[3])) {
+ *Termi = TerminalTypeVtUtf8;
+ IsTerminal = TRUE;
+ } else {
+ IsTerminal = FALSE;
+ }
+ }
+ }
+ }
+
+ if (!IsTerminal) {
+ return FALSE;
+ }
+
+ if ((Acpi != NULL) && IsIsaSerialNode (Acpi)) {
+ CopyMem (Com, &Acpi->UID, sizeof (UINT32));
+ } else {
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get mode number according to column and row
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+GetConsoleOutMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Col;
+ UINTN Row;
+ UINTN CurrentCol;
+ UINTN CurrentRow;
+ UINTN Mode;
+ UINTN MaxMode;
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+
+ ConOut = gST->ConOut;
+ MaxMode = (UINTN) (ConOut->Mode->MaxMode);
+
+ CurrentCol = PcdGet32 (PcdSetupConOutColumn);
+ CurrentRow = PcdGet32 (PcdSetupConOutRow);
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (!EFI_ERROR(Status)) {
+ if (CurrentCol == Col && CurrentRow == Row) {
+ CallbackData->BmmFakeNvData.ConsoleOutMode = (UINT16) Mode;
+ break;
+ }
+ }
+ }
+}
+
+/**
+
+ Initialize console input device check box to ConsoleInCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleInCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT8 *ConInCheck;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+
+ ASSERT (CallbackData != NULL);
+
+ ConInCheck = &CallbackData->BmmFakeNvData.ConsoleInCheck[0];
+ for (Index = 0; ((Index < ConsoleInpMenu.MenuNumber) && \
+ (Index < MAX_MENU_NUMBER)) ; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleInpMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ConInCheck[Index] = NewConsoleContext->IsActive;
+ }
+}
+
+/**
+
+ Initialize console output device check box to ConsoleOutCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleOutCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT8 *ConOutCheck;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+
+ ASSERT (CallbackData != NULL);
+ ConOutCheck = &CallbackData->BmmFakeNvData.ConsoleOutCheck[0];
+ for (Index = 0; ((Index < ConsoleOutMenu.MenuNumber) && \
+ (Index < MAX_MENU_NUMBER)) ; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleOutMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ConOutCheck[Index] = NewConsoleContext->IsActive;
+ }
+}
+
+/**
+
+ Initialize standard error output device check box to ConsoleErrCheck[MAX_MENU_NUMBER]
+ in BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetConsoleErrCheck (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT8 *ConErrCheck;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+
+ ASSERT (CallbackData != NULL);
+ ConErrCheck = &CallbackData->BmmFakeNvData.ConsoleErrCheck[0];
+ for (Index = 0; ((Index < ConsoleErrMenu.MenuNumber) && \
+ (Index < MAX_MENU_NUMBER)) ; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&ConsoleErrMenu, Index);
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ ConErrCheck[Index] = NewConsoleContext->IsActive;
+ }
+}
+
+/**
+
+ Initialize terminal attributes (baudrate, data rate, stop bits, parity and terminal type)
+ to BMM_FAKE_NV_DATA structure.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+GetTerminalAttribute (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BMM_FAKE_NV_DATA *CurrentFakeNVMap;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ UINT16 TerminalIndex;
+ UINT8 AttributeIndex;
+
+ ASSERT (CallbackData != NULL);
+
+ CurrentFakeNVMap = &CallbackData->BmmFakeNvData;
+ for (TerminalIndex = 0; ((TerminalIndex < TerminalMenu.MenuNumber) && \
+ (TerminalIndex < MAX_MENU_NUMBER)); TerminalIndex++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, TerminalIndex);
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ for (AttributeIndex = 0; AttributeIndex < sizeof (BaudRateList) / sizeof (BaudRateList [0]); AttributeIndex++) {
+ if (NewTerminalContext->BaudRate == (UINT64) (BaudRateList[AttributeIndex].Value)) {
+ NewTerminalContext->BaudRateIndex = AttributeIndex;
+ break;
+ }
+ }
+ for (AttributeIndex = 0; AttributeIndex < sizeof (DataBitsList) / sizeof (DataBitsList[0]); AttributeIndex++) {
+ if (NewTerminalContext->DataBits == (UINT64) (DataBitsList[AttributeIndex].Value)) {
+ NewTerminalContext->DataBitsIndex = AttributeIndex;
+ break;
+ }
+ }
+
+ for (AttributeIndex = 0; AttributeIndex < sizeof (ParityList) / sizeof (ParityList[0]); AttributeIndex++) {
+ if (NewTerminalContext->Parity == (UINT64) (ParityList[AttributeIndex].Value)) {
+ NewTerminalContext->ParityIndex = AttributeIndex;
+ break;
+ }
+ }
+
+ for (AttributeIndex = 0; AttributeIndex < sizeof (StopBitsList) / sizeof (StopBitsList[0]); AttributeIndex++) {
+ if (NewTerminalContext->StopBits == (UINT64) (StopBitsList[AttributeIndex].Value)) {
+ NewTerminalContext->StopBitsIndex = AttributeIndex;
+ break;
+ }
+ }
+ CurrentFakeNVMap->COMBaudRate[TerminalIndex] = NewTerminalContext->BaudRateIndex;
+ CurrentFakeNVMap->COMDataRate[TerminalIndex] = NewTerminalContext->DataBitsIndex;
+ CurrentFakeNVMap->COMStopBits[TerminalIndex] = NewTerminalContext->StopBitsIndex;
+ CurrentFakeNVMap->COMParity[TerminalIndex] = NewTerminalContext->ParityIndex;
+ CurrentFakeNVMap->COMTerminalType[TerminalIndex] = NewTerminalContext->TerminalType;
+ CurrentFakeNVMap->COMFlowControl[TerminalIndex] = NewTerminalContext->FlowControl;
+ }
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Data.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Data.c
new file mode 100644
index 0000000000..0a3ffbcc30
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Data.c
@@ -0,0 +1,332 @@
+/** @file
+ Define some data used for Boot Maint
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+VOID *mStartOpCodeHandle = NULL;
+VOID *mEndOpCodeHandle = NULL;
+EFI_IFR_GUID_LABEL *mStartLabel = NULL;
+EFI_IFR_GUID_LABEL *mEndLabel = NULL;
+
+STRING_DEPOSITORY *FileOptionStrDepository;
+STRING_DEPOSITORY *ConsoleOptionStrDepository;
+STRING_DEPOSITORY *BootOptionStrDepository;
+STRING_DEPOSITORY *BootOptionHelpStrDepository;
+STRING_DEPOSITORY *DriverOptionStrDepository;
+STRING_DEPOSITORY *DriverOptionHelpStrDepository;
+STRING_DEPOSITORY *TerminalStrDepository;
+
+///
+/// Terminal type string token storage
+///
+UINT16 TerminalType[] = {
+ STRING_TOKEN(STR_COM_TYPE_0),
+ STRING_TOKEN(STR_COM_TYPE_1),
+ STRING_TOKEN(STR_COM_TYPE_2),
+ STRING_TOKEN(STR_COM_TYPE_3),
+};
+
+///
+/// Flow Control type string token storage
+///
+UINT16 mFlowControlType[2] = {
+ STRING_TOKEN(STR_NONE_FLOW_CONTROL),
+ STRING_TOKEN(STR_HARDWARE_FLOW_CONTROL)
+};
+
+UINT32 mFlowControlValue[2] = {
+ 0,
+ UART_FLOW_CONTROL_HARDWARE
+};
+
+///
+/// File system selection menu
+///
+BM_MENU_OPTION FsOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Console Input Device Selection Menu
+///
+BM_MENU_OPTION ConsoleInpMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Console Output Device Selection Menu
+///
+BM_MENU_OPTION ConsoleOutMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Error Output Device Selection Menu
+///
+BM_MENU_OPTION ConsoleErrMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Boot Option from variable Menu
+///
+BM_MENU_OPTION BootOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Driver Option from variable menu
+///
+BM_MENU_OPTION DriverOptionMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy FD Info from LegacyBios.GetBbsInfo()
+///
+BM_MENU_OPTION LegacyFDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy HD Info from LegacyBios.GetBbsInfo()
+///
+BM_MENU_OPTION LegacyHDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy CD Info from LegacyBios.GetBbsInfo()
+///
+BM_MENU_OPTION LegacyCDMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy NET Info from LegacyBios.GetBbsInfo()
+///
+BM_MENU_OPTION LegacyNETMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Legacy NET Info from LegacyBios.GetBbsInfo()
+///
+BM_MENU_OPTION LegacyBEVMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Files and sub-directories in current directory menu
+///
+BM_MENU_OPTION DirectoryMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Handles in current system selection menu
+///
+BM_MENU_OPTION DriverMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+BM_MENU_OPTION TerminalMenu = {
+ BM_MENU_OPTION_SIGNATURE,
+ {NULL},
+ 0
+};
+
+///
+/// Value and string token correspondency for BaudRate
+///
+COM_ATTR BaudRateList[19] = {
+ {
+ 115200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_0)
+ },
+ {
+ 57600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_1)
+ },
+ {
+ 38400,
+ STRING_TOKEN(STR_COM_BAUD_RATE_2)
+ },
+ {
+ 19200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_3)
+ },
+ {
+ 9600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_4)
+ },
+ {
+ 7200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_5)
+ },
+ {
+ 4800,
+ STRING_TOKEN(STR_COM_BAUD_RATE_6)
+ },
+ {
+ 3600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_7)
+ },
+ {
+ 2400,
+ STRING_TOKEN(STR_COM_BAUD_RATE_8)
+ },
+ {
+ 2000,
+ STRING_TOKEN(STR_COM_BAUD_RATE_9)
+ },
+ {
+ 1800,
+ STRING_TOKEN(STR_COM_BAUD_RATE_10)
+ },
+ {
+ 1200,
+ STRING_TOKEN(STR_COM_BAUD_RATE_11)
+ },
+ {
+ 600,
+ STRING_TOKEN(STR_COM_BAUD_RATE_12)
+ },
+ {
+ 300,
+ STRING_TOKEN(STR_COM_BAUD_RATE_13)
+ },
+ {
+ 150,
+ STRING_TOKEN(STR_COM_BAUD_RATE_14)
+ },
+ {
+ 134,
+ STRING_TOKEN(STR_COM_BAUD_RATE_15)
+ },
+ {
+ 110,
+ STRING_TOKEN(STR_COM_BAUD_RATE_16)
+ },
+ {
+ 75,
+ STRING_TOKEN(STR_COM_BAUD_RATE_17)
+ },
+ {
+ 50,
+ STRING_TOKEN(STR_COM_BAUD_RATE_18)
+ }
+};
+
+///
+/// Value and string token correspondency for DataBits
+///
+COM_ATTR DataBitsList[4] = {
+ {
+ 5,
+ STRING_TOKEN(STR_COM_DATA_BITS_0)
+ },
+ {
+ 6,
+ STRING_TOKEN(STR_COM_DATA_BITS_1)
+ },
+ {
+ 7,
+ STRING_TOKEN(STR_COM_DATA_BITS_2)
+ },
+ {
+ 8,
+ STRING_TOKEN(STR_COM_DATA_BITS_3)
+ }
+};
+
+///
+/// Value and string token correspondency for Parity
+///
+COM_ATTR ParityList[5] = {
+ {
+ NoParity,
+ STRING_TOKEN(STR_COM_PAR_0)
+ },
+ {
+ EvenParity,
+ STRING_TOKEN(STR_COM_PAR_1)
+ },
+ {
+ OddParity,
+ STRING_TOKEN(STR_COM_PAR_2)
+ },
+ {
+ MarkParity,
+ STRING_TOKEN(STR_COM_PAR_3)
+ },
+ {
+ SpaceParity,
+ STRING_TOKEN(STR_COM_PAR_4)
+ }
+};
+
+///
+/// Value and string token correspondency for Baudreate
+///
+COM_ATTR StopBitsList[3] = {
+ {
+ OneStopBit,
+ STRING_TOKEN(STR_COM_STOP_BITS_0)
+ },
+ {
+ OneFiveStopBits,
+ STRING_TOKEN(STR_COM_STOP_BITS_1)
+ },
+ {
+ TwoStopBits,
+ STRING_TOKEN(STR_COM_STOP_BITS_2)
+ }
+};
+
+///
+/// Guid for messaging path, used in Serial port setting.
+///
+EFI_GUID TerminalTypeGuid[4] = {
+ DEVICE_PATH_MESSAGING_PC_ANSI,
+ DEVICE_PATH_MESSAGING_VT_100,
+ DEVICE_PATH_MESSAGING_VT_100_PLUS,
+ DEVICE_PATH_MESSAGING_VT_UTF8
+};
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FE.vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FE.vfr
new file mode 100644
index 0000000000..056694ebef
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FE.vfr
@@ -0,0 +1,127 @@
+///** @file
+//
+// File Explorer Formset
+//
+// Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include "FormGuid.h"
+
+formset
+ guid = FILE_EXPLORE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = FILE_EXPLORE_FORMSET_GUID,
+
+ varstore FILE_EXPLORER_NV_DATA,
+ varid = VARSTORE_ID_BOOT_MAINT,
+ name = FeData,
+ guid = FILE_EXPLORE_FORMSET_GUID;
+
+ form formid = FORM_FILE_EXPLORER_ID,
+ title = STRING_TOKEN(STR_FILE_EXPLORER_TITLE);
+
+ label FORM_FILE_EXPLORER_ID;
+ label LABEL_END;
+ endform;
+
+ form formid = FORM_BOOT_ADD_DESCRIPTION_ID,
+ title = STRING_TOKEN(STR_FORM_BOOT_ADD_DESC_TITLE);
+
+ label FORM_BOOT_ADD_DESCRIPTION_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = FeData.BootDescriptionData,
+ questionid = KEY_VALUE_BOOT_DESCRIPTION,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ minsize = 6,
+ maxsize = 75,
+ endstring;
+
+ string varid = FeData.BootOptionalData,
+ questionid = KEY_VALUE_BOOT_OPTION,
+ prompt = STRING_TOKEN(STR_OPTIONAL_DATA),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ minsize = 0,
+ maxsize = 120,
+ endstring;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_BOOT;
+
+ text
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_BOOT;
+
+ endform;
+
+ form formid = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID,
+ title = STRING_TOKEN(STR_FORM_DRV_ADD_DESC_TITLE);
+
+ label FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ string varid = FeData.DriverDescriptionData,
+ questionid = KEY_VALUE_DRIVER_DESCRIPTION,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_DESC),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ minsize = 6,
+ maxsize = 75,
+ endstring;
+
+ string varid = FeData.DriverOptionalData,
+ questionid = KEY_VALUE_DRIVER_OPTION,
+ prompt = STRING_TOKEN(STR_OPTIONAL_DATA),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ flags = INTERACTIVE,
+ minsize = 0,
+ maxsize = 120,
+ endstring;
+
+ checkbox varid = FeData.ForceReconnect,
+ prompt = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON),
+ help = STRING_TOKEN(STR_LOAD_OPTION_FORCE_RECON),
+ flags = CHECKBOX_DEFAULT,
+ key = 0,
+ endcheckbox;
+
+ subtitle text = STRING_TOKEN(STR_NULL_STRING);
+
+ text
+ help = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_SAVE_AND_EXIT_DRIVER; //BUGBUB: allow duplicate key in one formset???
+
+ text
+ help = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ text = STRING_TOKEN(STR_NO_SAVE_AND_EXIT),
+ flags = INTERACTIVE,
+ key = KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER;
+
+ endform;
+
+endformset; \ No newline at end of file
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c
new file mode 100644
index 0000000000..f804984fa9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FileExplorer.c
@@ -0,0 +1,469 @@
+/** @file
+ File explorer related functions.
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+/**
+ Update the File Explore page.
+
+ @param CallbackData The BMM context data.
+ @param MenuOption Pointer to menu options to display.
+
+**/
+VOID
+UpdateFileExplorePage (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ BM_MENU_OPTION *MenuOption
+ )
+{
+ UINTN Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ FormId = 0;
+
+ RefreshUpdateData ();
+ mStartLabel->Number = FORM_FILE_EXPLORER_ID;
+
+ for (Index = 0; Index < MenuOption->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (MenuOption, Index);
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewFileContext->IsBootLegacy) {
+ continue;
+ }
+
+ if ((NewFileContext->IsDir) || (FileExplorerStateBootFromFile == CallbackData->FeCurrentState)) {
+ //
+ // Create Text opcode for directory, also create Text opcode for file in FileExplorerStateBootFromFile.
+ //
+ HiiCreateActionOpCode (
+ mStartOpCodeHandle,
+ (UINT16) (FILE_OPTION_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ } else {
+ //
+ // Create Goto opcode for file in FileExplorerStateAddBootOption or FileExplorerStateAddDriverOptionState.
+ //
+ if (FileExplorerStateAddBootOption == CallbackData->FeCurrentState) {
+ FormId = FORM_BOOT_ADD_DESCRIPTION_ID;
+ } else if (FileExplorerStateAddDriverOptionState == CallbackData->FeCurrentState) {
+ FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ }
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FormId,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (FILE_OPTION_GOTO_OFFSET + Index)
+ );
+ }
+ }
+
+ HiiUpdateForm (
+ CallbackData->FeHiiHandle,
+ &gFileExploreFormSetGuid,
+ FORM_FILE_EXPLORER_ID,
+ mStartOpCodeHandle, // Label FORM_FILE_EXPLORER_ID
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Update the file explower page with the refershed file system.
+
+
+ @param CallbackData BMM context data
+ @param KeyValue Key value to identify the type of data to expect.
+
+ @retval TRUE Inform the caller to create a callback packet to exit file explorer.
+ @retval FALSE Indicate that there is no need to exit file explorer.
+
+**/
+BOOLEAN
+UpdateFileExplorer (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN UINT16 KeyValue
+ )
+{
+ UINT16 FileOptionMask;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_FILE_CONTEXT *NewFileContext;
+ EFI_FORM_ID FormId;
+ BOOLEAN ExitFileExplorer;
+ EFI_STATUS Status;
+
+ NewMenuEntry = NULL;
+ NewFileContext = NULL;
+ ExitFileExplorer = FALSE;
+
+ FileOptionMask = (UINT16) (FILE_OPTION_MASK & KeyValue);
+
+ if (FileExplorerDisplayUnknown == CallbackData->FeDisplayContext) {
+ //
+ // First in, display file system.
+ //
+ BOpt_FreeMenu (&FsOptionMenu);
+ BOpt_FindFileSystem (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &FsOptionMenu);
+
+ UpdateFileExplorePage (CallbackData, &FsOptionMenu);
+
+ CallbackData->FeDisplayContext = FileExplorerDisplayFileSystem;
+ } else {
+ if (FileExplorerDisplayFileSystem == CallbackData->FeDisplayContext) {
+ NewMenuEntry = BOpt_GetMenuEntry (&FsOptionMenu, FileOptionMask);
+ } else if (FileExplorerDisplayDirectory == CallbackData->FeDisplayContext) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DirectoryMenu, FileOptionMask);
+ }
+
+ NewFileContext = (BM_FILE_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewFileContext->IsDir ) {
+ CallbackData->FeDisplayContext = FileExplorerDisplayDirectory;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_FreeMenu (&DirectoryMenu);
+ Status = BOpt_FindFiles (CallbackData, NewMenuEntry);
+ if (EFI_ERROR (Status)) {
+ ExitFileExplorer = TRUE;
+ goto exit;
+ }
+ CreateMenuStringToken (CallbackData, CallbackData->FeHiiHandle, &DirectoryMenu);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+
+ UpdateFileExplorePage (CallbackData, &DirectoryMenu);
+
+ } else {
+ switch (CallbackData->FeCurrentState) {
+ case FileExplorerStateBootFromFile:
+ //
+ // Restore to original mode before launching boot option.
+ //
+ BdsSetConsoleMode (FALSE);
+
+ //
+ // Here boot from file
+ //
+ BootThisFile (NewFileContext);
+ //
+ // Set proper video resolution and text mode for setup.
+ //
+ BdsSetConsoleMode (TRUE);
+ ExitFileExplorer = TRUE;
+ break;
+
+ case FileExplorerStateAddBootOption:
+ case FileExplorerStateAddDriverOptionState:
+ if (FileExplorerStateAddBootOption == CallbackData->FeCurrentState) {
+ FormId = FORM_BOOT_ADD_DESCRIPTION_ID;
+ if (!CallbackData->FeFakeNvData.BootOptionChanged) {
+ ZeroMem (CallbackData->FeFakeNvData.BootOptionalData, sizeof (CallbackData->FeFakeNvData.BootOptionalData));
+ ZeroMem (CallbackData->FeFakeNvData.BootDescriptionData, sizeof (CallbackData->FeFakeNvData.BootDescriptionData));
+ }
+ } else {
+ FormId = FORM_DRIVER_ADD_FILE_DESCRIPTION_ID;
+ if (!CallbackData->FeFakeNvData.DriverOptionChanged) {
+ ZeroMem (CallbackData->FeFakeNvData.DriverOptionalData, sizeof (CallbackData->FeFakeNvData.DriverOptionalData));
+ ZeroMem (CallbackData->FeFakeNvData.DriverDescriptionData, sizeof (CallbackData->FeFakeNvData.DriverDescriptionData));
+ }
+ }
+
+ CallbackData->MenuEntry = NewMenuEntry;
+ CallbackData->LoadContext->FilePathList = ((BM_FILE_CONTEXT *) (CallbackData->MenuEntry->VariableContext))->DevicePath;
+
+ //
+ // Create Subtitle op-code for the display string of the option.
+ //
+ RefreshUpdateData ();
+ mStartLabel->Number = FormId;
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiUpdateForm (
+ CallbackData->FeHiiHandle,
+ &gFileExploreFormSetGuid,
+ FormId,
+ mStartOpCodeHandle, // Label FormId
+ mEndOpCodeHandle // LABEL_END
+ );
+ break;
+
+ default:
+ break;
+ }
+ }
+ }
+ exit:
+ return ExitFileExplorer;
+}
+
+/**
+ This function applies changes in a driver's configuration.
+ Input is a Configuration, which has the routing data for this
+ driver followed by name / value configuration pairs. The driver
+ must apply those pairs to its configurable storage. If the
+ driver's configuration is stored in a linear block of data
+ and the driver's name / value pairs are in <BlockConfig>
+ format, it may use the ConfigToBlock helper function (above) to
+ simplify the job. Currently not implemented.
+
+ @param[in] This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param[in] Configuration A null-terminated Unicode string in
+ <ConfigString> format.
+ @param[out] Progress A pointer to a string filled in with the
+ offset of the most recent '&' before the
+ first failing name / value pair (or the
+ beginn ing of the string if the failure
+ is in the first name / value pair) or
+ the terminating NULL if all was
+ successful.
+
+ @retval EFI_SUCCESS The results have been distributed or are
+ awaiting distribution.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the
+ parts of the results that must be
+ stored awaiting possible future
+ protocols.
+ @retval EFI_INVALID_PARAMETERS Passing in a NULL for the
+ Results parameter would result
+ in this type of error.
+ @retval EFI_NOT_FOUND Target for the specified routing data
+ was not found.
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HII_CONFIG_ROUTING_PROTOCOL *ConfigRouting;
+ FILE_EXPLORER_NV_DATA *FeData;
+ BMM_CALLBACK_DATA *Private;
+
+ if (Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Configuration;
+
+ if (Configuration == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check routing data in <ConfigHdr>.
+ // Note: there is no name for Name/Value storage, only GUID will be checked
+ //
+ if (!HiiIsConfigHdrMatch (Configuration, &gFileExploreFormSetGuid, mFileExplorerStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ Status = gBS->LocateProtocol (
+ &gEfiHiiConfigRoutingProtocolGuid,
+ NULL,
+ (VOID**) &ConfigRouting
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ Private = FE_CALLBACK_DATA_FROM_THIS (This);
+ //
+ // Get Buffer Storage data from EFI variable
+ //
+ BufferSize = sizeof (FILE_EXPLORER_NV_DATA );
+ FeData = &Private->FeFakeNvData;
+
+ //
+ // Convert <ConfigResp> to buffer data by helper function ConfigToBlock()
+ //
+ Status = ConfigRouting->ConfigToBlock (
+ ConfigRouting,
+ Configuration,
+ (UINT8 *) FeData,
+ &BufferSize,
+ Progress
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (FeData->BootDescriptionData[0] != 0x00 || FeData->BootOptionalData[0] != 0x00) {
+ Status = Var_UpdateBootOption (Private, FeData);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_GetBootOptions (Private);
+ CreateMenuStringToken (Private, Private->FeHiiHandle, &BootOptionMenu);
+ }
+
+ if (FeData->DriverDescriptionData[0] != 0x00 || FeData->DriverOptionalData[0] != 0x00) {
+ Status = Var_UpdateDriverOption (
+ Private,
+ Private->FeHiiHandle,
+ FeData->DriverDescriptionData,
+ FeData->DriverOptionalData,
+ FeData->ForceReconnect
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ BOpt_GetDriverOptions (Private);
+ CreateMenuStringToken (Private, Private->FeHiiHandle, &DriverOptionMenu);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+ When user select a interactive opcode, this callback will be triggered.
+ Based on the Question(QuestionId) that triggers the callback, the corresponding
+ actions is performed. It handles:
+
+ 1) the addition of boot option.
+ 2) the addition of driver option.
+ 3) exit from file browser
+ 4) update of file content if a dir is selected.
+ 5) boot the file if a file is selected in "boot from file"
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
+ @retval EFI_INVALID_PARAMETER If paramter Value or ActionRequest is NULL.
+**/
+EFI_STATUS
+EFIAPI
+FileExplorerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ BMM_CALLBACK_DATA *Private;
+ FILE_EXPLORER_NV_DATA *NvRamMap;
+ EFI_STATUS Status;
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+ Private = FE_CALLBACK_DATA_FROM_THIS (This);
+
+ //
+ // Retrieve uncommitted data from Form Browser
+ //
+ NvRamMap = &Private->FeFakeNvData;
+ HiiGetBrowserData (&gFileExploreFormSetGuid, mFileExplorerStorageName, sizeof (FILE_EXPLORER_NV_DATA), (UINT8 *) NvRamMap);
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_BOOT) {
+ NvRamMap->BootOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ } else if (QuestionId == KEY_VALUE_SAVE_AND_EXIT_DRIVER) {
+ NvRamMap->DriverOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_SUBMIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER) {
+ //
+ // Discard changes and exit formset
+ //
+ NvRamMap->DriverOptionalData[0] = 0x0000;
+ NvRamMap->DriverDescriptionData[0] = 0x0000;
+ NvRamMap->DriverOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else if (QuestionId == KEY_VALUE_NO_SAVE_AND_EXIT_BOOT) {
+ //
+ // Discard changes and exit formset
+ //
+ NvRamMap->BootOptionalData[0] = 0x0000;
+ NvRamMap->BootDescriptionData[0] = 0x0000;
+ NvRamMap->BootOptionChanged = FALSE;
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else if (QuestionId == KEY_VALUE_BOOT_DESCRIPTION || QuestionId == KEY_VALUE_BOOT_OPTION) {
+ NvRamMap->BootOptionChanged = TRUE;
+ } else if (QuestionId == KEY_VALUE_DRIVER_DESCRIPTION || QuestionId == KEY_VALUE_DRIVER_OPTION) {
+ NvRamMap->DriverOptionChanged = TRUE;
+ } else if (QuestionId < FILE_OPTION_OFFSET) {
+ //
+ // Exit File Explorer formset
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ } else if (QuestionId >= FILE_OPTION_OFFSET && QuestionId < FILE_OPTION_GOTO_OFFSET) {
+ //
+ // Update forms may return TRUE or FALSE, need to check here.
+ //
+ if (UpdateFileExplorer (Private, QuestionId)) {
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ }
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (QuestionId >= FILE_OPTION_GOTO_OFFSET) {
+ //
+ // function will always return FALSE, no need to check here.
+ //
+ UpdateFileExplorer (Private, QuestionId);
+ }
+ }
+
+ //
+ // Pass changed uncommitted data back to Form Browser
+ //
+ HiiSetBrowserData (&gFileExploreFormSetGuid, mFileExplorerStorageName, sizeof (FILE_EXPLORER_NV_DATA), (UINT8 *) NvRamMap, NULL);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h
new file mode 100644
index 0000000000..bf99999760
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/FormGuid.h
@@ -0,0 +1,243 @@
+/** @file
+ Formset guids, form id and VarStore data structure for Boot Maintenance Manager.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#ifndef _FORM_GUID_H_
+#define _FORM_GUID_H_
+
+#include <Guid/BdsHii.h>
+
+#define FORM_MAIN_ID 0x1001
+#define FORM_BOOT_ADD_ID 0x1002
+#define FORM_BOOT_DEL_ID 0x1003
+#define FORM_BOOT_CHG_ID 0x1004
+#define FORM_DRV_ADD_ID 0x1005
+#define FORM_DRV_DEL_ID 0x1006
+#define FORM_DRV_CHG_ID 0x1007
+#define FORM_CON_MAIN_ID 0x1008
+#define FORM_CON_IN_ID 0x1009
+#define FORM_CON_OUT_ID 0x100A
+#define FORM_CON_ERR_ID 0x100B
+#define FORM_FILE_SEEK_ID 0x100C
+#define FORM_FILE_NEW_SEEK_ID 0x100D
+#define FORM_DRV_ADD_FILE_ID 0x100E
+#define FORM_DRV_ADD_HANDLE_ID 0x100F
+#define FORM_DRV_ADD_HANDLE_DESC_ID 0x1010
+#define FORM_BOOT_NEXT_ID 0x1011
+#define FORM_TIME_OUT_ID 0x1012
+#define FORM_RESET 0x1013
+#define FORM_BOOT_SETUP_ID 0x1014
+#define FORM_DRIVER_SETUP_ID 0x1015
+#define FORM_BOOT_LEGACY_DEVICE_ID 0x1016
+#define FORM_CON_COM_ID 0x1017
+#define FORM_CON_COM_SETUP_ID 0x1018
+#define FORM_SET_FD_ORDER_ID 0x1019
+#define FORM_SET_HD_ORDER_ID 0x101A
+#define FORM_SET_CD_ORDER_ID 0x101B
+#define FORM_SET_NET_ORDER_ID 0x101C
+#define FORM_SET_BEV_ORDER_ID 0x101D
+#define FORM_FILE_EXPLORER_ID 0x101E
+#define FORM_BOOT_ADD_DESCRIPTION_ID 0x101F
+#define FORM_DRIVER_ADD_FILE_DESCRIPTION_ID 0x1020
+#define FORM_CON_MODE_ID 0x1021
+#define FORM_BOOT_FROM_FILE_ID 0x1022
+
+#define MAXIMUM_FORM_ID 0x10FF
+
+#define KEY_VALUE_COM_SET_BAUD_RATE 0x1101
+#define KEY_VALUE_COM_SET_DATA_BITS 0x1102
+#define KEY_VALUE_COM_SET_STOP_BITS 0x1103
+#define KEY_VALUE_COM_SET_PARITY 0x1104
+#define KEY_VALUE_COM_SET_TERMI_TYPE 0x1105
+#define KEY_VALUE_MAIN_BOOT_NEXT 0x1106
+#define KEY_VALUE_BOOT_ADD_DESC_DATA 0x1107
+#define KEY_VALUE_BOOT_ADD_OPT_DATA 0x1108
+#define KEY_VALUE_DRIVER_ADD_DESC_DATA 0x1109
+#define KEY_VALUE_DRIVER_ADD_OPT_DATA 0x110A
+#define KEY_VALUE_SAVE_AND_EXIT 0x110B
+#define KEY_VALUE_NO_SAVE_AND_EXIT 0x110C
+#define KEY_VALUE_BOOT_FROM_FILE 0x110D
+#define KEY_VALUE_BOOT_DESCRIPTION 0x110E
+#define KEY_VALUE_BOOT_OPTION 0x110F
+#define KEY_VALUE_DRIVER_DESCRIPTION 0x1110
+#define KEY_VALUE_DRIVER_OPTION 0x1111
+
+#define MAXIMUM_NORMAL_KEY_VALUE 0x11FF
+
+//
+// Varstore ID defined for Buffer Storage
+//
+#define VARSTORE_ID_BOOT_MAINT 0x1000
+#define VARSTORE_ID_FILE_EXPLORER 0x1001
+
+//
+// End Label
+//
+#define LABEL_END 0xffff
+#define MAX_MENU_NUMBER 100
+
+///
+/// This is the structure that will be used to store the
+/// question's current value. Use it at initialize time to
+/// set default value for each question. When using at run
+/// time, this map is returned by the callback function,
+/// so dynamically changing the question's value will be
+/// possible through this mechanism
+///
+typedef struct {
+ //
+ // Three questions displayed at the main page
+ // for Timeout, BootNext Variables respectively
+ //
+ UINT16 BootTimeOut;
+ UINT16 BootNext;
+
+ //
+ // This is the COM1 Attributes value storage
+ //
+ UINT8 COM1BaudRate;
+ UINT8 COM1DataRate;
+ UINT8 COM1StopBits;
+ UINT8 COM1Parity;
+ UINT8 COM1TerminalType;
+
+ //
+ // This is the COM2 Attributes value storage
+ //
+ UINT8 COM2BaudRate;
+ UINT8 COM2DataRate;
+ UINT8 COM2StopBits;
+ UINT8 COM2Parity;
+ UINT8 COM2TerminalType;
+
+ //
+ // Driver Option Add Handle page storage
+ //
+ UINT16 DriverAddHandleDesc[MAX_MENU_NUMBER];
+ UINT16 DriverAddHandleOptionalData[MAX_MENU_NUMBER];
+ UINT8 DriverAddActive;
+ UINT8 DriverAddForceReconnect;
+
+ //
+ // Console Input/Output/Errorout using COM port check storage
+ //
+ UINT8 ConsoleInputCOM1;
+ UINT8 ConsoleInputCOM2;
+ UINT8 ConsoleOutputCOM1;
+ UINT8 ConsoleOutputCOM2;
+ UINT8 ConsoleErrorCOM1;
+ UINT8 ConsoleErrorCOM2;
+
+ //
+ // At most 100 input/output/errorout device for console storage
+ //
+ UINT8 ConsoleCheck[MAX_MENU_NUMBER];
+ //
+ // At most 100 input/output/errorout device for console storage
+ //
+ UINT8 ConsoleInCheck[MAX_MENU_NUMBER];
+ UINT8 ConsoleOutCheck[MAX_MENU_NUMBER];
+ UINT8 ConsoleErrCheck[MAX_MENU_NUMBER];
+
+ //
+ // Boot Option Order storage
+ // The value is the OptionNumber+1 because the order list value cannot be 0
+ // Use UINT32 to hold the potential value 0xFFFF+1=0x10000
+ //
+ UINT32 BootOptionOrder[MAX_MENU_NUMBER];
+
+ //
+ // Driver Option Order storage
+ // The value is the OptionNumber+1 because the order list value cannot be 0
+ // Use UINT32 to hold the potential value 0xFFFF+1=0x10000
+ //
+ UINT32 DriverOptionOrder[MAX_MENU_NUMBER];
+
+ //
+ // Boot Option Delete storage
+ //
+ BOOLEAN BootOptionDel[MAX_MENU_NUMBER];
+ BOOLEAN BootOptionDelMark[MAX_MENU_NUMBER];
+
+ //
+ // Driver Option Delete storage
+ //
+ BOOLEAN DriverOptionDel[MAX_MENU_NUMBER];
+ BOOLEAN DriverOptionDelMark[MAX_MENU_NUMBER];
+
+ //
+ // This is the Terminal Attributes value storage
+ //
+ UINT8 COMBaudRate[MAX_MENU_NUMBER];
+ UINT8 COMDataRate[MAX_MENU_NUMBER];
+ UINT8 COMStopBits[MAX_MENU_NUMBER];
+ UINT8 COMParity[MAX_MENU_NUMBER];
+ UINT8 COMTerminalType[MAX_MENU_NUMBER];
+ UINT8 COMFlowControl[MAX_MENU_NUMBER];
+
+ //
+ // Legacy Device Order Selection Storage
+ //
+ UINT8 LegacyFD[MAX_MENU_NUMBER];
+ UINT8 LegacyHD[MAX_MENU_NUMBER];
+ UINT8 LegacyCD[MAX_MENU_NUMBER];
+ UINT8 LegacyNET[MAX_MENU_NUMBER];
+ UINT8 LegacyBEV[MAX_MENU_NUMBER];
+
+ //
+ // We use DisableMap array to record the enable/disable state of each boot device
+ // It should be taken as a bit array, from left to right there are totally 256 bits
+ // the most left one stands for BBS table item 0, and the most right one stands for item 256
+ // If the bit is 1, it means the boot device has been disabled.
+ //
+ UINT8 DisableMap[32];
+
+ //
+ // Console Output Text Mode
+ //
+ UINT16 ConsoleOutMode;
+
+ //
+ // UINT16 PadArea[10];
+ //
+} BMM_FAKE_NV_DATA;
+
+//
+// Key used by File Explorer forms
+//
+#define KEY_VALUE_SAVE_AND_EXIT_BOOT 0x1000
+#define KEY_VALUE_NO_SAVE_AND_EXIT_BOOT 0x1001
+#define KEY_VALUE_SAVE_AND_EXIT_DRIVER 0x1002
+#define KEY_VALUE_NO_SAVE_AND_EXIT_DRIVER 0x1003
+
+//
+// Description data and optional data size
+//
+#define DESCRIPTION_DATA_SIZE 75
+#define OPTIONAL_DATA_SIZE 127
+
+///
+/// This is the data structure used by File Explorer formset
+///
+typedef struct {
+ UINT16 BootDescriptionData[DESCRIPTION_DATA_SIZE];
+ UINT16 BootOptionalData[OPTIONAL_DATA_SIZE];
+ UINT16 DriverDescriptionData[DESCRIPTION_DATA_SIZE];
+ UINT16 DriverOptionalData[OPTIONAL_DATA_SIZE];
+ BOOLEAN BootOptionChanged;
+ BOOLEAN DriverOptionChanged;
+ UINT8 Active;
+ UINT8 ForceReconnect;
+} FILE_EXPLORER_NV_DATA;
+
+#endif
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c
new file mode 100644
index 0000000000..b13ed11630
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/UpdatePage.c
@@ -0,0 +1,1391 @@
+/** @file
+Dynamically update the pages.
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+/**
+ Refresh the global UpdateData structure.
+
+**/
+VOID
+RefreshUpdateData (
+ VOID
+ )
+{
+ //
+ // Free current updated date
+ //
+ if (mStartOpCodeHandle != NULL) {
+ HiiFreeOpCodeHandle (mStartOpCodeHandle);
+ }
+
+ //
+ // Create new OpCode Handle
+ //
+ mStartOpCodeHandle = HiiAllocateOpCodeHandle ();
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ mStartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (mStartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ mStartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+
+}
+
+/**
+ Add a "Go back to main page" tag in front of the form when there are no
+ "Apply changes" and "Discard changes" tags in the end of the form.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdatePageStart (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ RefreshUpdateData ();
+ mStartLabel->Number = CallbackData->BmmCurrentPageId;
+
+ if (!(CallbackData->BmmAskSaveOrNot)) {
+ //
+ // Add a "Go back to main page" tag in front of the form when there are no
+ // "Apply changes" and "Discard changes" tags in the end of the form.
+ //
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_MAIN_ID,
+ STRING_TOKEN (STR_FORM_GOTO_MAIN),
+ STRING_TOKEN (STR_FORM_GOTO_MAIN),
+ 0,
+ FORM_MAIN_ID
+ );
+ }
+
+}
+
+/**
+ Create the "Apply changes" and "Discard changes" tags. And
+ ensure user can return to the main page.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdatePageEnd (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ //
+ // Create the "Apply changes" and "Discard changes" tags.
+ //
+ if (CallbackData->BmmAskSaveOrNot) {
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 0
+ );
+
+ HiiCreateActionOpCode (
+ mStartOpCodeHandle,
+ KEY_VALUE_SAVE_AND_EXIT,
+ STRING_TOKEN (STR_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ }
+
+ //
+ // Ensure user can return to the main page.
+ //
+ HiiCreateActionOpCode (
+ mStartOpCodeHandle,
+ KEY_VALUE_NO_SAVE_AND_EXIT,
+ STRING_TOKEN (STR_NO_SAVE_AND_EXIT),
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+
+ HiiUpdateForm (
+ CallbackData->BmmHiiHandle,
+ &gBootMaintFormSetGuid,
+ CallbackData->BmmCurrentPageId,
+ mStartOpCodeHandle, // Label CallbackData->BmmCurrentPageId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Clean up the dynamic opcode at label and form specified by both LabelId.
+
+ @param LabelId It is both the Form ID and Label ID for opcode deletion.
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+CleanUpPage (
+ IN UINT16 LabelId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ RefreshUpdateData ();
+
+ //
+ // Remove all op-codes from dynamic page
+ //
+ mStartLabel->Number = LabelId;
+ HiiUpdateForm (
+ CallbackData->BmmHiiHandle,
+ &gBootMaintFormSetGuid,
+ LabelId,
+ mStartOpCodeHandle, // Label LabelId
+ mEndOpCodeHandle // LABEL_END
+ );
+}
+
+/**
+ Boot a file selected by user at File Expoloer of BMM.
+
+ @param FileContext The file context data, which contains the device path
+ of the file to be boot from.
+
+ @retval EFI_SUCCESS The function completed successfull.
+ @return Other value if the boot from the file fails.
+
+**/
+EFI_STATUS
+BootThisFile (
+ IN BM_FILE_CONTEXT *FileContext
+ )
+{
+ EFI_STATUS Status;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+ BDS_COMMON_OPTION *Option;
+
+ Option = (BDS_COMMON_OPTION *) AllocatePool (sizeof (BDS_COMMON_OPTION));
+ ASSERT (Option != NULL);
+ Option->Description = (CHAR16 *) AllocateCopyPool (StrSize (FileContext->FileName), FileContext->FileName);
+ Option->DevicePath = FileContext->DevicePath;
+ Option->LoadOptionsSize = 0;
+ Option->LoadOptions = NULL;
+
+ //
+ // Since current no boot from removable media directly is allowed */
+ //
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ ExitDataSize = 0;
+
+ Status = BdsLibBootViaBootOption (Option, Option->DevicePath, &ExitDataSize, &ExitData);
+
+ return Status;
+
+}
+
+/**
+ Create a list of Goto Opcode for all terminal devices logged
+ by TerminaMenu. This list will be inserted to form FORM_CON_COM_SETUP_ID.
+
+ @param CallbackData The BMM context data.
+**/
+VOID
+UpdateConCOMPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = FALSE;
+
+ UpdatePageStart (CallbackData);
+
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_CON_COM_SETUP_ID,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (TERMINAL_OPTION_OFFSET + Index)
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create a lit of boot option from global BootOptionMenu. It
+ allow user to delete the boot option.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateBootDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
+
+ ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionDel) / sizeof (CallbackData->BmmFakeNvData.BootOptionDel[0])));
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewLoadContext->IsLegacy) {
+ continue;
+ }
+
+ NewLoadContext->Deleted = FALSE;
+
+ if (CallbackData->BmmFakeNvData.BootOptionDel[Index] && !CallbackData->BmmFakeNvData.BootOptionDelMark[Index]) {
+ //
+ // CallbackData->BmmFakeNvData.BootOptionDel[Index] == TRUE means browser knows this boot option is selected
+ // CallbackData->BmmFakeNvData.BootOptionDelMark[Index] = FALSE means BDS knows the selected boot option has
+ // deleted, browser maintains old useless info. So clear this info here, and later update this info to browser
+ // through HiiSetBrowserData function.
+ //
+ CallbackData->BmmFakeNvData.BootOptionDel[Index] = FALSE;
+ }
+
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (BOOT_OPTION_DEL_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (BOOT_OPTION_DEL_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ NULL
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create a lit of driver option from global DriverMenu.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateDrvAddHandlePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = FALSE;
+
+ UpdatePageStart (CallbackData);
+
+ for (Index = 0; Index < DriverMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverMenu, Index);
+
+ HiiCreateGotoOpCode (
+ mStartOpCodeHandle,
+ FORM_DRV_ADD_HANDLE_DESC_ID,
+ NewMenuEntry->DisplayStringToken,
+ STRING_TOKEN (STR_NULL_STRING),
+ EFI_IFR_FLAG_CALLBACK,
+ (UINT16) (HANDLE_OPTION_OFFSET + Index)
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create a lit of driver option from global DriverOptionMenu. It
+ allow user to delete the driver option.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateDrvDelPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 Index;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &DriverOptionMenu);
+
+ ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionDel) / sizeof (CallbackData->BmmFakeNvData.DriverOptionDel[0])));
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+
+ if (CallbackData->BmmFakeNvData.DriverOptionDel[Index] && !CallbackData->BmmFakeNvData.DriverOptionDelMark[Index]) {
+ //
+ // CallbackData->BmmFakeNvData.BootOptionDel[Index] == TRUE means browser knows this boot option is selected
+ // CallbackData->BmmFakeNvData.BootOptionDelMark[Index] = FALSE means BDS knows the selected boot option has
+ // deleted, browser maintains old useless info. So clear this info here, and later update this info to browser
+ // through HiiSetBrowserData function.
+ //
+ CallbackData->BmmFakeNvData.DriverOptionDel[Index] = FALSE;
+ }
+
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (DRIVER_OPTION_DEL_QUESTION_ID + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (DRIVER_OPTION_DEL_VAR_OFFSET + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ EFI_IFR_FLAG_CALLBACK,
+ 0,
+ NULL
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Prepare the page to allow user to add description for
+ a Driver Option.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateDriverAddHandleDescPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+
+ CallbackData->BmmFakeNvData.DriverAddActive = 0x01;
+ CallbackData->BmmFakeNvData.DriverAddForceReconnect = 0x00;
+ CallbackData->BmmAskSaveOrNot = TRUE;
+ NewMenuEntry = CallbackData->MenuEntry;
+
+ UpdatePageStart (CallbackData);
+
+ HiiCreateSubTitleOpCode (
+ mStartOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ 0,
+ 0
+ );
+
+ HiiCreateStringOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) DRV_ADD_HANDLE_DESC_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRV_ADD_HANDLE_DESC_VAR_OFFSET,
+ STRING_TOKEN (STR_LOAD_OPTION_DESC),
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 6,
+ 75,
+ NULL
+ );
+
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) DRV_ADD_RECON_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRV_ADD_RECON_VAR_OFFSET,
+ STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
+ STRING_TOKEN (STR_LOAD_OPTION_FORCE_RECON),
+ 0,
+ 0,
+ NULL
+ );
+
+ HiiCreateStringOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) DRIVER_ADD_OPTION_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ DRIVER_ADD_OPTION_VAR_OFFSET,
+ STRING_TOKEN (STR_OPTIONAL_DATA),
+ STRING_TOKEN (STR_NULL_STRING),
+ 0,
+ 0,
+ 6,
+ 75,
+ NULL
+ );
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Update console page.
+
+ @param UpdatePageId The form ID to be updated.
+ @param ConsoleMenu The console menu list.
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateConsolePage (
+ IN UINT16 UpdatePageId,
+ IN BM_MENU_OPTION *ConsoleMenu,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+ UINT8 CheckFlags;
+ UINT8 *ConsoleCheck;
+ EFI_QUESTION_ID QuestionIdBase;
+ UINT16 VariableOffsetBase;
+
+ UpdatePageStart (CallbackData);
+
+ ConsoleCheck = NULL;
+ QuestionIdBase = 0;
+ VariableOffsetBase = 0;
+
+ switch (UpdatePageId) {
+ case FORM_CON_IN_ID:
+ ConsoleCheck = &CallbackData->BmmFakeNvData.ConsoleInCheck[0];
+ QuestionIdBase = CON_IN_DEVICE_QUESTION_ID;
+ VariableOffsetBase = CON_IN_DEVICE_VAR_OFFSET;
+ break;
+
+ case FORM_CON_OUT_ID:
+ ConsoleCheck = &CallbackData->BmmFakeNvData.ConsoleOutCheck[0];
+ QuestionIdBase = CON_OUT_DEVICE_QUESTION_ID;
+ VariableOffsetBase = CON_OUT_DEVICE_VAR_OFFSET;
+ break;
+
+ case FORM_CON_ERR_ID:
+ ConsoleCheck = &CallbackData->BmmFakeNvData.ConsoleErrCheck[0];
+ QuestionIdBase = CON_ERR_DEVICE_QUESTION_ID;
+ VariableOffsetBase = CON_ERR_DEVICE_VAR_OFFSET;
+ break;
+ }
+ ASSERT (ConsoleCheck != NULL);
+
+ for (Index = 0; ((Index < ConsoleMenu->MenuNumber) && \
+ (Index < MAX_MENU_NUMBER)) ; Index++) {
+ CheckFlags = 0;
+ if (UpdatePageId != FORM_CON_ERR_ID) {
+ CheckFlags |= EFI_IFR_CHECKBOX_DEFAULT;
+ }
+ NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
+ HiiCreateCheckBoxOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (QuestionIdBase + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (VariableOffsetBase + Index),
+ NewMenuEntry->DisplayStringToken,
+ NewMenuEntry->HelpStringToken,
+ 0,
+ CheckFlags,
+ NULL
+ );
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Update the page's NV Map if user has changed the order
+ a list. This list can be Boot Order or Driver Order.
+
+ @param UpdatePageId The form ID to be updated.
+ @param OptionMenu The new list.
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BM_MENU_OPTION *OptionMenu,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 Index;
+ UINT16 OptionIndex;
+ VOID *OptionsOpCodeHandle;
+ BOOLEAN BootOptionFound;
+ UINT32 *OptionOrder;
+ EFI_QUESTION_ID QuestionId;
+ UINT16 VarOffset;
+
+
+ UpdatePageStart (CallbackData);
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
+
+ OptionOrder = NULL;
+ QuestionId = 0;
+ VarOffset = 0;
+ switch (UpdatePageId) {
+
+ case FORM_BOOT_CHG_ID:
+ //GetBootOrder (CallbackData);
+ OptionOrder = CallbackData->BmmFakeNvData.BootOptionOrder;
+ QuestionId = BOOT_OPTION_ORDER_QUESTION_ID;
+ VarOffset = BOOT_OPTION_ORDER_VAR_OFFSET;
+ break;
+
+ case FORM_DRV_CHG_ID:
+ //GetDriverOrder (CallbackData);
+ OptionOrder = CallbackData->BmmFakeNvData.DriverOptionOrder;
+ QuestionId = DRIVER_OPTION_ORDER_QUESTION_ID;
+ VarOffset = DRIVER_OPTION_ORDER_VAR_OFFSET;
+ break;
+ }
+ ASSERT (OptionOrder != NULL);
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ NewMenuEntry = NULL;
+ for (OptionIndex = 0; (OptionIndex < MAX_MENU_NUMBER && OptionOrder[OptionIndex] != 0); OptionIndex++) {
+ BootOptionFound = FALSE;
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
+ if ((UINT32) (NewMenuEntry->OptionNumber + 1) == OptionOrder[OptionIndex]) {
+ BootOptionFound = TRUE;
+ break;
+ }
+ }
+ if (BootOptionFound) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_32,
+ OptionOrder[OptionIndex]
+ );
+ }
+ }
+
+ if (OptionMenu->MenuNumber > 0) {
+ HiiCreateOrderedListOpCode (
+ mStartOpCodeHandle, // Container for dynamic created opcodes
+ QuestionId, // Question ID
+ VARSTORE_ID_BOOT_MAINT, // VarStore ID
+ VarOffset, // Offset in Buffer Storage
+ STRING_TOKEN (STR_CHANGE_ORDER), // Question prompt text
+ STRING_TOKEN (STR_CHANGE_ORDER), // Question help text
+ 0, // Question flag
+ 0, // Ordered list flag, e.g. EFI_IFR_UNIQUE_SET
+ EFI_IFR_TYPE_NUM_SIZE_32, // Data type of Question value
+ 100, // Maximum container
+ OptionsOpCodeHandle, // Option Opcode list
+ NULL // Default Opcode is NULL
+ );
+ }
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create the dynamic page to allow user to set
+ the "BootNext" value.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateBootNextPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINTN NumberOfOptions;
+ UINT16 Index;
+ VOID *OptionsOpCodeHandle;
+
+ NumberOfOptions = BootOptionMenu.MenuNumber;
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, &BootOptionMenu);
+
+ if (NumberOfOptions > 0) {
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ //CallbackData->BmmFakeNvData.BootNext = (UINT16) (BootOptionMenu.MenuNumber);
+
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+
+ if (NewLoadContext->IsBootNext) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ Index
+ );
+ //CallbackData->BmmFakeNvData.BootNext = Index;
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ Index
+ );
+ }
+ }
+
+ if (CallbackData->BmmFakeNvData.BootNext == Index) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NONE),
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ Index
+ );
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_NONE),
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) BOOT_NEXT_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ BOOT_NEXT_VAR_OFFSET,
+ STRING_TOKEN (STR_BOOT_NEXT),
+ STRING_TOKEN (STR_BOOT_NEXT_HELP),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_2,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ }
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create the dynamic page to allow user to set the "TimeOut" value.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateTimeOutPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT16 BootTimeOut;
+ VOID *DefaultOpCodeHandle;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ BootTimeOut = PcdGet16 (PcdPlatformBootTimeOut);
+
+ DefaultOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (DefaultOpCodeHandle != NULL);
+ HiiCreateDefaultOpCode (DefaultOpCodeHandle, EFI_HII_DEFAULT_CLASS_STANDARD, EFI_IFR_TYPE_NUM_SIZE_16, BootTimeOut);
+
+ HiiCreateNumericOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) BOOT_TIME_OUT_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ BOOT_TIME_OUT_VAR_OFFSET,
+ STRING_TOKEN (STR_NUM_AUTO_BOOT),
+ STRING_TOKEN (STR_HLP_AUTO_BOOT),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_2 | EFI_IFR_DISPLAY_UINT_DEC,
+ 0,
+ 65535,
+ 0,
+ DefaultOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (DefaultOpCodeHandle);
+
+ //CallbackData->BmmFakeNvData.BootTimeOut = BootTimeOut;
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Refresh the text mode page.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateConModePage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINTN Mode;
+ UINTN Index;
+ UINTN Col;
+ UINTN Row;
+ CHAR16 ModeString[50];
+ CHAR16 *PStr;
+ UINTN MaxMode;
+ UINTN ValidMode;
+ EFI_STRING_ID *ModeToken;
+ EFI_STATUS Status;
+ VOID *OptionsOpCodeHandle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *ConOut;
+
+ ConOut = gST->ConOut;
+ Index = 0;
+ ValidMode = 0;
+ MaxMode = (UINTN) (ConOut->Mode->MaxMode);
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+
+ UpdatePageStart (CallbackData);
+
+ //
+ // Check valid mode
+ //
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ValidMode++;
+ }
+
+ if (ValidMode == 0) {
+ return;
+ }
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ ModeToken = AllocateZeroPool (sizeof (EFI_STRING_ID) * ValidMode);
+ ASSERT(ModeToken != NULL);
+
+ //
+ // Determin which mode should be the first entry in menu
+ //
+ // GetConsoleOutMode (CallbackData);
+
+ //
+ // Build text mode options
+ //
+ for (Mode = 0; Mode < MaxMode; Mode++) {
+ Status = ConOut->QueryMode (ConOut, Mode, &Col, &Row);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Build mode string Column x Row
+ //
+ UnicodeValueToString (ModeString, 0, Col, 0);
+ PStr = &ModeString[0];
+ StrCatS (PStr, sizeof (ModeString) / sizeof (ModeString[0]), L" x ");
+ PStr = PStr + StrLen (PStr);
+ UnicodeValueToString (PStr , 0, Row, 0);
+
+ ModeToken[Index] = HiiSetString (CallbackData->BmmHiiHandle, 0, ModeString, NULL);
+
+ if (Mode == CallbackData->BmmFakeNvData.ConsoleOutMode) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ ModeToken[Index],
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ (UINT16) Mode
+ );
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ ModeToken[Index],
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_16,
+ (UINT16) Mode
+ );
+ }
+ Index++;
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) CON_MODE_QUESTION_ID,
+ VARSTORE_ID_BOOT_MAINT,
+ CON_MODE_VAR_OFFSET,
+ STRING_TOKEN (STR_CON_MODE_SETUP),
+ STRING_TOKEN (STR_CON_MODE_SETUP),
+ EFI_IFR_FLAG_RESET_REQUIRED,
+ EFI_IFR_NUMERIC_SIZE_2,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ FreePool (ModeToken);
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Create the dynamic page which allows user to set the property such as Baud Rate, Data Bits,
+ Parity, Stop Bits, Terminal Type.
+
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdateTerminalPage (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ UINT8 Index;
+ UINT8 CheckFlags;
+ BM_MENU_ENTRY *NewMenuEntry;
+ VOID *OptionsOpCodeHandle;
+ UINTN CurrentTerminal;
+
+ UpdatePageStart (CallbackData);
+
+ CurrentTerminal = CallbackData->CurrentTerminal;
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &TerminalMenu,
+ CurrentTerminal
+ );
+
+ if (NewMenuEntry == NULL) {
+ return ;
+ }
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < sizeof (BaudRateList) / sizeof (BaudRateList [0]); Index++) {
+ CheckFlags = 0;
+ if (BaudRateList[Index].Value == 115200) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ BaudRateList[Index].StringToken,
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_BAUD_RATE_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_BAUD_RATE_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_BAUD_RATE),
+ STRING_TOKEN (STR_COM_BAUD_RATE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < sizeof (DataBitsList) / sizeof (DataBitsList[0]); Index++) {
+ CheckFlags = 0;
+
+ if (DataBitsList[Index].Value == 8) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ DataBitsList[Index].StringToken,
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_DATA_RATE_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_DATA_RATE_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_DATA_BITS),
+ STRING_TOKEN (STR_COM_DATA_BITS),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < sizeof (ParityList) / sizeof (ParityList[0]); Index++) {
+ CheckFlags = 0;
+ if (ParityList[Index].Value == NoParity) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ ParityList[Index].StringToken,
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_PARITY_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_PARITY_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_PARITY),
+ STRING_TOKEN (STR_COM_PARITY),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < sizeof (StopBitsList) / sizeof (StopBitsList[0]); Index++) {
+ CheckFlags = 0;
+ if (StopBitsList[Index].Value == OneStopBit) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ StopBitsList[Index].StringToken,
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_STOP_BITS_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_STOP_BITS_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_STOP_BITS),
+ STRING_TOKEN (STR_COM_STOP_BITS),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < 4; Index++) {
+ CheckFlags = 0;
+ if (Index == 0) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ (EFI_STRING_ID) TerminalType[Index],
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ Index
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_TERMINAL_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_TERMINAL_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_TERMI_TYPE),
+ STRING_TOKEN (STR_COM_TERMI_TYPE),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < sizeof (mFlowControlType) / sizeof (mFlowControlType[0]); Index++) {
+ CheckFlags = 0;
+ if (Index == 0) {
+ CheckFlags |= EFI_IFR_OPTION_DEFAULT;
+ }
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ (EFI_STRING_ID) mFlowControlType[Index],
+ CheckFlags,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ mFlowControlValue[Index]
+ );
+ }
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (COM_FLOWCONTROL_QUESTION_ID + CurrentTerminal),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (COM_FLOWCONTROL_VAR_OFFSET + CurrentTerminal),
+ STRING_TOKEN (STR_COM_FLOW_CONTROL),
+ STRING_TOKEN (STR_COM_FLOW_CONTROL),
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ UpdatePageEnd (CallbackData);
+}
+
+/**
+ Dispatch the correct update page function to call based on
+ the UpdatePageId.
+
+ @param UpdatePageId The form ID.
+ @param CallbackData The BMM context data.
+
+**/
+VOID
+UpdatePageBody (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ CleanUpPage (UpdatePageId, CallbackData);
+ switch (UpdatePageId) {
+ case FORM_CON_IN_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleInpMenu, CallbackData);
+ break;
+
+ case FORM_CON_OUT_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleOutMenu, CallbackData);
+ break;
+
+ case FORM_CON_ERR_ID:
+ UpdateConsolePage (UpdatePageId, &ConsoleErrMenu, CallbackData);
+ break;
+
+ case FORM_BOOT_CHG_ID:
+ UpdateOrderPage (UpdatePageId, &BootOptionMenu, CallbackData);
+ break;
+
+ case FORM_DRV_CHG_ID:
+ UpdateOrderPage (UpdatePageId, &DriverOptionMenu, CallbackData);
+ break;
+
+ default:
+ break;
+ }
+}
+
+/**
+ Create a dynamic page so that Legacy Device boot order
+ can be set for specified device type.
+
+ @param UpdatePageId The form ID. It also spefies the legacy device type.
+ @param CallbackData The BMM context data.
+
+
+**/
+VOID
+UpdateSetLegacyDeviceOrderPage (
+ IN UINT16 UpdatePageId,
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ BM_MENU_OPTION *OptionMenu;
+ BM_MENU_ENTRY *NewMenuEntry;
+ EFI_STRING_ID StrRef;
+ EFI_STRING_ID StrRefHelp;
+ BBS_TYPE BbsType;
+ UINTN VarSize;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 Index;
+ UINT16 Key;
+ CHAR16 String[100];
+ CHAR16 *TypeStr;
+ CHAR16 *TypeStrHelp;
+ UINT16 VarDevOrder;
+ UINT8 *VarData;
+ UINT8 *LegacyOrder;
+ UINT8 *OldData;
+ UINT8 *DisMap;
+ VOID *OptionsOpCodeHandle;
+
+ OptionMenu = NULL;
+ Key = 0;
+ StrRef = 0;
+ StrRefHelp = 0;
+ TypeStr = NULL;
+ TypeStrHelp = NULL;
+ BbsType = BBS_FLOPPY;
+ LegacyOrder = NULL;
+ OldData = NULL;
+ DisMap = NULL;
+
+ CallbackData->BmmAskSaveOrNot = TRUE;
+ UpdatePageStart (CallbackData);
+
+ DisMap = ZeroMem (CallbackData->BmmOldFakeNVData.DisableMap, sizeof (CallbackData->BmmOldFakeNVData.DisableMap));
+
+ //
+ // Create oneof option list
+ //
+ switch (UpdatePageId) {
+ case FORM_SET_FD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
+ Key = (UINT16) LEGACY_FD_QUESTION_ID;
+ TypeStr = STR_FLOPPY;
+ TypeStrHelp = STR_FLOPPY_HELP;
+ BbsType = BBS_FLOPPY;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyFD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyFD;
+ break;
+
+ case FORM_SET_HD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
+ Key = (UINT16) LEGACY_HD_QUESTION_ID;
+ TypeStr = STR_HARDDISK;
+ TypeStrHelp = STR_HARDDISK_HELP;
+ BbsType = BBS_HARDDISK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyHD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyHD;
+ break;
+
+ case FORM_SET_CD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
+ Key = (UINT16) LEGACY_CD_QUESTION_ID;
+ TypeStr = STR_CDROM;
+ TypeStrHelp = STR_CDROM_HELP;
+ BbsType = BBS_CDROM;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyCD;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyCD;
+ break;
+
+ case FORM_SET_NET_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
+ Key = (UINT16) LEGACY_NET_QUESTION_ID;
+ TypeStr = STR_NET;
+ TypeStrHelp = STR_NET_HELP;
+ BbsType = BBS_EMBED_NETWORK;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyNET;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyNET;
+ break;
+
+ case FORM_SET_BEV_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
+ Key = (UINT16) LEGACY_BEV_QUESTION_ID;
+ TypeStr = STR_BEV;
+ TypeStrHelp = STR_BEV_HELP;
+ BbsType = BBS_BEV_DEVICE;
+ LegacyOrder = CallbackData->BmmFakeNvData.LegacyBEV;
+ OldData = CallbackData->BmmOldFakeNVData.LegacyBEV;
+ break;
+
+ default:
+ DEBUG ((EFI_D_ERROR, "Invalid command ID for updating page!\n"));
+ return;
+ }
+
+ CreateMenuStringToken (CallbackData, CallbackData->BmmHiiHandle, OptionMenu);
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (OptionMenu, Index);
+ //
+ // Create OneOf for each legacy device
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ NewMenuEntry->DisplayStringToken,
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ (UINT8) ((BM_LEGACY_DEVICE_CONTEXT *) NewMenuEntry->VariableContext)->BbsIndex
+ );
+ }
+
+ //
+ // Create OneOf for item "Disabled"
+ //
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ STRING_TOKEN (STR_DISABLE_LEGACY_DEVICE),
+ 0,
+ EFI_IFR_TYPE_NUM_SIZE_8,
+ 0xFF
+ );
+
+ //
+ // Get Device Order from variable
+ //
+ VarData = BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &VarSize
+ );
+
+ if (NULL != VarData) {
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ while (VarData < VarData + VarSize) {
+ if (DevOrder->BbsType == BbsType) {
+ break;
+ }
+
+ VarData = (UINT8 *)((UINTN)VarData + sizeof (BBS_TYPE));
+ VarData += *(UINT16 *) VarData;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ }
+ //
+ // Create oneof tag here for FD/HD/CD #1 #2
+ //
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ //
+ // Create the string for oneof tag
+ //
+ UnicodeSPrint (String, sizeof (String), TypeStr, Index);
+ StrRef = HiiSetString (CallbackData->BmmHiiHandle, 0, String, NULL);
+
+ UnicodeSPrint (String, sizeof (String), TypeStrHelp, Index);
+ StrRefHelp = HiiSetString (CallbackData->BmmHiiHandle, 0, String, NULL);
+
+ HiiCreateOneOfOpCode (
+ mStartOpCodeHandle,
+ (EFI_QUESTION_ID) (Key + Index),
+ VARSTORE_ID_BOOT_MAINT,
+ (UINT16) (Key + Index - CONFIG_OPTION_OFFSET),
+ StrRef,
+ StrRefHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ VarDevOrder = *(UINT16 *) ((UINTN) DevOrder + sizeof (BBS_TYPE) + sizeof (UINT16) + Index * sizeof (UINT16));
+
+ if (0xFF00 == (VarDevOrder & 0xFF00)) {
+ LegacyOrder[Index] = 0xFF;
+ Pos = (VarDevOrder & 0xFF) / 8;
+ Bit = 7 - ((VarDevOrder & 0xFF) % 8);
+ DisMap[Pos] = (UINT8) (DisMap[Pos] | (UINT8) (1 << Bit));
+ } else {
+ LegacyOrder[Index] = (UINT8) (VarDevOrder & 0xFF);
+ }
+ }
+ }
+
+ CopyMem (OldData, LegacyOrder, 100);
+
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+
+ UpdatePageEnd (CallbackData);
+}
+
+
+/**
+ Dispatch the display to the next page based on NewPageId.
+
+ @param Private The BMM context data.
+ @param NewPageId The original page ID.
+
+**/
+VOID
+UpdatePageId (
+ BMM_CALLBACK_DATA *Private,
+ UINT16 NewPageId
+ )
+{
+ //
+ // For the question don't impact the page update, just ignore it.
+ //
+ if (((NewPageId >= BOOT_OPTION_DEL_QUESTION_ID) && (NewPageId < BOOT_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER)) ||
+ ((NewPageId >= DRIVER_OPTION_DEL_QUESTION_ID) && (NewPageId < DRIVER_OPTION_DEL_QUESTION_ID + MAX_MENU_NUMBER))) {
+ return;
+ }
+
+ if ((NewPageId < FILE_OPTION_OFFSET) && (NewPageId >= HANDLE_OPTION_OFFSET)) {
+ //
+ // If we select a handle to add driver option, advance to the add handle description page.
+ //
+ NewPageId = FORM_DRV_ADD_HANDLE_DESC_ID;
+ } else if ((NewPageId == KEY_VALUE_SAVE_AND_EXIT) || (NewPageId == KEY_VALUE_NO_SAVE_AND_EXIT)) {
+ //
+ // Return to main page after "Save Changes" or "Discard Changes".
+ //
+ NewPageId = FORM_MAIN_ID;
+ } else if ((NewPageId >= TERMINAL_OPTION_OFFSET) && (NewPageId < CONSOLE_OPTION_OFFSET)) {
+ NewPageId = FORM_CON_COM_SETUP_ID;
+ }
+
+ if ((NewPageId > 0) && (NewPageId < MAXIMUM_FORM_ID)) {
+ Private->BmmPreviousPageId = Private->BmmCurrentPageId;
+ Private->BmmCurrentPageId = NewPageId;
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Variable.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Variable.c
new file mode 100644
index 0000000000..b933dd9699
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMaint/Variable.c
@@ -0,0 +1,1380 @@
+/** @file
+ Variable operation that will be used by bootmaint
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootMaint.h"
+
+/**
+ Delete Boot Option that represent a Deleted state in BootOptionMenu.
+ After deleting this boot option, call Var_ChangeBootOrder to
+ make sure BootOrder is in valid state.
+
+ @retval EFI_SUCCESS If all boot load option EFI Variables corresponding to
+ BM_LOAD_CONTEXT marked for deletion is deleted.
+ @retval EFI_NOT_FOUND If can not find the boot option want to be deleted.
+ @return Others If failed to update the "BootOrder" variable after deletion.
+
+**/
+EFI_STATUS
+Var_DelBootOption (
+ VOID
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 BootString[10];
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ Status = EFI_SUCCESS;
+ Index2 = 0;
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, (Index - Index2));
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (!NewLoadContext->Deleted) {
+ continue;
+ }
+
+ UnicodeSPrint (
+ BootString,
+ sizeof (BootString),
+ L"Boot%04x",
+ NewMenuEntry->OptionNumber
+ );
+
+ EfiLibDeleteVariable (BootString, &gEfiGlobalVariableGuid);
+ Index2++;
+ //
+ // If current Load Option is the same as BootNext,
+ // must delete BootNext in order to make sure
+ // there will be no panic on next boot
+ //
+ if (NewLoadContext->IsBootNext) {
+ EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
+ }
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ NewMenuEntry = NULL;
+ }
+
+ BootOptionMenu.MenuNumber -= Index2;
+
+ Status = Var_ChangeBootOrder ();
+ return Status;
+}
+
+/**
+ After any operation on Boot####, there will be a discrepancy in BootOrder.
+ Since some are missing but in BootOrder, while some are present but are
+ not reflected by BootOrder. Then a function rebuild BootOrder from
+ scratch by content from BootOptionMenu is needed.
+
+
+
+
+ @retval EFI_SUCCESS The boot order is updated successfully.
+ @return EFI_STATUS other than EFI_SUCCESS if failed to
+ Set the "BootOrder" EFI Variable.
+
+**/
+EFI_STATUS
+Var_ChangeBootOrder (
+ VOID
+ )
+{
+
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *BootOrderList;
+ UINT16 *BootOrderListPtr;
+ UINTN BootOrderListSize;
+ UINTN Index;
+
+ BootOrderList = NULL;
+ BootOrderListSize = 0;
+
+ //
+ // First check whether BootOrder is present in current configuration
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+
+ //
+ // If exists, delete it to hold new BootOrder
+ //
+ if (BootOrderList != NULL) {
+ EfiLibDeleteVariable (L"BootOrder", &gEfiGlobalVariableGuid);
+ FreePool (BootOrderList);
+ BootOrderList = NULL;
+ }
+ //
+ // Maybe here should be some check method to ensure that
+ // no new added boot options will be added
+ // but the setup engine now will give only one callback
+ // that is to say, user are granted only one chance to
+ // decide whether the boot option will be added or not
+ // there should be no indictor to show whether this
+ // is a "new" boot option
+ //
+ BootOrderListSize = BootOptionMenu.MenuNumber;
+
+ if (BootOrderListSize > 0) {
+ BootOrderList = AllocateZeroPool (BootOrderListSize * sizeof (UINT16));
+ ASSERT (BootOrderList != NULL);
+ BootOrderListPtr = BootOrderList;
+
+ //
+ // Get all current used Boot#### from BootOptionMenu.
+ // OptionNumber in each BM_LOAD_OPTION is really its
+ // #### value.
+ //
+ for (Index = 0; Index < BootOrderListSize; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ *BootOrderList = (UINT16) NewMenuEntry->OptionNumber;
+ BootOrderList++;
+ }
+
+ BootOrderList = BootOrderListPtr;
+
+ //
+ // After building the BootOrderList, write it back
+ //
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderListSize * sizeof (UINT16),
+ BootOrderList
+ );
+ //
+ // Changing variable without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Delete Load Option that represent a Deleted state in BootOptionMenu.
+ After deleting this Driver option, call Var_ChangeDriverOrder to
+ make sure DriverOrder is in valid state.
+
+ @retval EFI_SUCCESS Load Option is successfully updated.
+ @retval EFI_NOT_FOUND Fail to find the driver option want to be deleted.
+ @return Other value than EFI_SUCCESS if failed to update "Driver Order" EFI
+ Variable.
+
+**/
+EFI_STATUS
+Var_DelDriverOption (
+ VOID
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ UINT16 DriverString[12];
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN Index2;
+
+ Status = EFI_SUCCESS;
+ Index2 = 0;
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, (Index - Index2));
+ if (NULL == NewMenuEntry) {
+ return EFI_NOT_FOUND;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ if (!NewLoadContext->Deleted) {
+ continue;
+ }
+
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ NewMenuEntry->OptionNumber
+ );
+
+ EfiLibDeleteVariable (DriverString, &gEfiGlobalVariableGuid);
+ Index2++;
+
+ RemoveEntryList (&NewMenuEntry->Link);
+ BOpt_DestroyMenuEntry (NewMenuEntry);
+ NewMenuEntry = NULL;
+ }
+
+ DriverOptionMenu.MenuNumber -= Index2;
+
+ Status = Var_ChangeDriverOrder ();
+ return Status;
+}
+
+/**
+ After any operation on Driver####, there will be a discrepancy in
+ DriverOrder. Since some are missing but in DriverOrder, while some
+ are present but are not reflected by DriverOrder. Then a function
+ rebuild DriverOrder from scratch by content from DriverOptionMenu is
+ needed.
+
+ @retval EFI_SUCCESS The driver order is updated successfully.
+ @return Other status than EFI_SUCCESS if failed to set the "DriverOrder" EFI Variable.
+
+**/
+EFI_STATUS
+Var_ChangeDriverOrder (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BM_MENU_ENTRY *NewMenuEntry;
+ UINT16 *DriverOrderList;
+ UINT16 *DriverOrderListPtr;
+ UINTN DriverOrderListSize;
+ UINTN Index;
+
+ DriverOrderList = NULL;
+ DriverOrderListSize = 0;
+
+ //
+ // First check whether DriverOrder is present in current configuration
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+
+ //
+ // If exists, delete it to hold new DriverOrder
+ //
+ if (DriverOrderList != NULL) {
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ FreePool (DriverOrderList);
+ DriverOrderList = NULL;
+ }
+
+ DriverOrderListSize = DriverOptionMenu.MenuNumber;
+
+ if (DriverOrderListSize > 0) {
+ DriverOrderList = AllocateZeroPool (DriverOrderListSize * sizeof (UINT16));
+ ASSERT (DriverOrderList != NULL);
+ DriverOrderListPtr = DriverOrderList;
+
+ //
+ // Get all current used Driver#### from DriverOptionMenu.
+ // OptionNumber in each BM_LOAD_OPTION is really its
+ // #### value.
+ //
+ for (Index = 0; Index < DriverOrderListSize; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&DriverOptionMenu, Index);
+ *DriverOrderList = (UINT16) NewMenuEntry->OptionNumber;
+ DriverOrderList++;
+ }
+
+ DriverOrderList = DriverOrderListPtr;
+
+ //
+ // After building the DriverOrderList, write it back
+ //
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ DriverOrderListSize * sizeof (UINT16),
+ DriverOrderList
+ );
+ //
+ // Changing variable without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the device path of "ConOut", "ConIn" and "ErrOut"
+ based on the new BaudRate, Data Bits, parity and Stop Bits
+ set.
+
+**/
+VOID
+Var_UpdateAllConsoleOption (
+ VOID
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *OutDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *InpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ErrDevicePath;
+ EFI_STATUS Status;
+
+ OutDevicePath = EfiLibGetVariable (L"ConOut", &gEfiGlobalVariableGuid);
+ InpDevicePath = EfiLibGetVariable (L"ConIn", &gEfiGlobalVariableGuid);
+ ErrDevicePath = EfiLibGetVariable (L"ErrOut", &gEfiGlobalVariableGuid);
+ if (OutDevicePath != NULL) {
+ ChangeVariableDevicePath (OutDevicePath);
+ Status = gRT->SetVariable (
+ L"ConOut",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (OutDevicePath),
+ OutDevicePath
+ );
+ //
+ // Changing variable without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (InpDevicePath != NULL) {
+ ChangeVariableDevicePath (InpDevicePath);
+ Status = gRT->SetVariable (
+ L"ConIn",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (InpDevicePath),
+ InpDevicePath
+ );
+ //
+ // Changing variable without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (ErrDevicePath != NULL) {
+ ChangeVariableDevicePath (ErrDevicePath);
+ Status = gRT->SetVariable (
+ L"ErrOut",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (ErrDevicePath),
+ ErrDevicePath
+ );
+ //
+ // Changing variable without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+}
+
+/**
+ This function delete and build multi-instance device path for
+ specified type of console device.
+
+ This function clear the EFI variable defined by ConsoleName and
+ gEfiGlobalVariableGuid. It then build the multi-instance device
+ path by appending the device path of the Console (In/Out/Err) instance
+ in ConsoleMenu. Then it scan all corresponding console device by
+ scanning Terminal (built from device supporting Serial I/O instances)
+ devices in TerminalMenu. At last, it save a EFI variable specifed
+ by ConsoleName and gEfiGlobalVariableGuid.
+
+ @param ConsoleName The name for the console device type. They are
+ usually "ConIn", "ConOut" and "ErrOut".
+ @param ConsoleMenu The console memu which is a list of console devices.
+ @param UpdatePageId The flag specifying which type of console device
+ to be processed.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateConsoleOption (
+ IN UINT16 *ConsoleName,
+ IN BM_MENU_OPTION *ConsoleMenu,
+ IN UINT16 UpdatePageId
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *ConDevicePath;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_CONSOLE_CONTEXT *NewConsoleContext;
+ BM_TERMINAL_CONTEXT *NewTerminalContext;
+ EFI_STATUS Status;
+ VENDOR_DEVICE_PATH Vendor;
+ EFI_DEVICE_PATH_PROTOCOL *TerminalDevicePath;
+ UINTN Index;
+
+ ConDevicePath = EfiLibGetVariable (ConsoleName, &gEfiGlobalVariableGuid);
+ if (ConDevicePath != NULL) {
+ EfiLibDeleteVariable (ConsoleName, &gEfiGlobalVariableGuid);
+ FreePool (ConDevicePath);
+ ConDevicePath = NULL;
+ };
+
+ //
+ // First add all console input device from console input menu
+ //
+ for (Index = 0; Index < ConsoleMenu->MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (ConsoleMenu, Index);
+
+ NewConsoleContext = (BM_CONSOLE_CONTEXT *) NewMenuEntry->VariableContext;
+ if (NewConsoleContext->IsActive) {
+ ConDevicePath = AppendDevicePathInstance (
+ ConDevicePath,
+ NewConsoleContext->DevicePath
+ );
+ }
+ }
+
+ for (Index = 0; Index < TerminalMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&TerminalMenu, Index);
+
+ NewTerminalContext = (BM_TERMINAL_CONTEXT *) NewMenuEntry->VariableContext;
+ if (((NewTerminalContext->IsConIn != 0) && (UpdatePageId == FORM_CON_IN_ID)) ||
+ ((NewTerminalContext->IsConOut != 0) && (UpdatePageId == FORM_CON_OUT_ID)) ||
+ ((NewTerminalContext->IsStdErr != 0) && (UpdatePageId == FORM_CON_ERR_ID))
+ ) {
+ Vendor.Header.Type = MESSAGING_DEVICE_PATH;
+ Vendor.Header.SubType = MSG_VENDOR_DP;
+
+ ASSERT (NewTerminalContext->TerminalType < (sizeof (TerminalTypeGuid) / sizeof (TerminalTypeGuid[0])));
+ CopyMem (
+ &Vendor.Guid,
+ &TerminalTypeGuid[NewTerminalContext->TerminalType],
+ sizeof (EFI_GUID)
+ );
+ SetDevicePathNodeLength (&Vendor.Header, sizeof (VENDOR_DEVICE_PATH));
+ TerminalDevicePath = AppendDevicePathNode (
+ NewTerminalContext->DevicePath,
+ (EFI_DEVICE_PATH_PROTOCOL *) &Vendor
+ );
+ ASSERT (TerminalDevicePath != NULL);
+ ChangeTerminalDevicePath (&TerminalDevicePath, TRUE);
+ ConDevicePath = AppendDevicePathInstance (
+ ConDevicePath,
+ TerminalDevicePath
+ );
+ }
+ }
+
+ if (ConDevicePath != NULL) {
+ Status = gRT->SetVariable (
+ ConsoleName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ GetDevicePathSize (ConDevicePath),
+ ConDevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+
+}
+
+/**
+ This function delete and build multi-instance device path ConIn
+ console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateConsoleInpOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ConIn", &ConsoleInpMenu, FORM_CON_IN_ID);
+}
+
+/**
+ This function delete and build multi-instance device path ConOut
+ console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateConsoleOutOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ConOut", &ConsoleOutMenu, FORM_CON_OUT_ID);
+}
+
+/**
+ This function delete and build multi-instance device path ErrOut
+ console device.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+**/
+EFI_STATUS
+Var_UpdateErrorOutOption (
+ VOID
+ )
+{
+ return Var_UpdateConsoleOption (L"ErrOut", &ConsoleErrMenu, FORM_CON_ERR_ID);
+}
+
+/**
+ This function create a currently loaded Drive Option from
+ the BMM. It then appends this Driver Option to the end of
+ the "DriverOrder" list. It append this Driver Opotion to the end
+ of DriverOptionMenu.
+
+ @param CallbackData The BMM context data.
+ @param HiiHandle The HII handle associated with the BMM formset.
+ @param DescriptionData The description of this driver option.
+ @param OptionalData The optional load option.
+ @param ForceReconnect If to force reconnect.
+
+ @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
+ @retval EFI_SUCCESS If function completes successfully.
+
+**/
+EFI_STATUS
+Var_UpdateDriverOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_HII_HANDLE HiiHandle,
+ IN UINT16 *DescriptionData,
+ IN UINT16 *OptionalData,
+ IN UINT8 ForceReconnect
+ )
+{
+ UINT16 Index;
+ UINT16 *DriverOrderList;
+ UINT16 *NewDriverOrderList;
+ UINT16 DriverString[12];
+ UINTN DriverOrderListSize;
+ VOID *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+
+ OptionalDataExist = FALSE;
+
+ Index = BOpt_GetDriverOptionNumber ();
+ UnicodeSPrint (
+ DriverString,
+ sizeof (DriverString),
+ L"Driver%04x",
+ Index
+ );
+
+ if (*DescriptionData == 0x0000) {
+ StrCpyS (DescriptionData, DESCRIPTION_DATA_SIZE, DriverString);
+ }
+
+ BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (DescriptionData);
+ BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ if (*OptionalData != 0x0000) {
+ OptionalDataExist = TRUE;
+ BufferSize += StrSize (OptionalData);
+ }
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (NULL == Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ FreePool (Buffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->LoadOptionSize = BufferSize;
+ Ptr = (UINT8 *) Buffer;
+ NewLoadContext->LoadOption = Ptr;
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE | (ForceReconnect << 1);
+ NewLoadContext->Attributes = *((UINT32 *) Ptr);
+ NewLoadContext->IsActive = TRUE;
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ Ptr += sizeof (UINT32);
+ *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+ NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
+
+ Ptr += sizeof (UINT16);
+ CopyMem (
+ Ptr,
+ DescriptionData,
+ StrSize (DescriptionData)
+ );
+
+ NewLoadContext->Description = AllocateZeroPool (StrSize (DescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ CopyMem (
+ NewLoadContext->Description,
+ (VOID *) Ptr,
+ StrSize (DescriptionData)
+ );
+
+ Ptr += StrSize (DescriptionData);
+ CopyMem (
+ Ptr,
+ CallbackData->LoadContext->FilePathList,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (VOID *) Ptr,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionStrDepository
+ );
+ NewMenuEntry->DisplayStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ DriverOptionHelpStrDepository
+ );
+ NewMenuEntry->HelpStringToken = HiiSetString (HiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ if (OptionalDataExist) {
+ Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ CopyMem (
+ Ptr,
+ OptionalData,
+ StrSize (OptionalData)
+ );
+ }
+
+ Status = gRT->SetVariable (
+ DriverString,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BufferSize,
+ Buffer
+ );
+ if (!EFI_ERROR (Status)) {
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+ NewDriverOrderList = AllocateZeroPool (DriverOrderListSize + sizeof (UINT16));
+ ASSERT (NewDriverOrderList != NULL);
+ if (DriverOrderList != NULL) {
+ CopyMem (NewDriverOrderList, DriverOrderList, DriverOrderListSize);
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ }
+ NewDriverOrderList[DriverOrderListSize / sizeof (UINT16)] = Index;
+
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ DriverOrderListSize + sizeof (UINT16),
+ NewDriverOrderList
+ );
+ if (DriverOrderList != NULL) {
+ FreePool (DriverOrderList);
+ }
+ DriverOrderList = NULL;
+ FreePool (NewDriverOrderList);
+ if (!EFI_ERROR (Status)) {
+ InsertTailList (&DriverOptionMenu.Head, &NewMenuEntry->Link);
+ DriverOptionMenu.MenuNumber++;
+
+ //
+ // Update "change boot order" page used data, append the new add boot
+ // option at the end.
+ //
+ Index = 0;
+ while (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] != 0) {
+ Index++;
+ }
+ CallbackData->BmmFakeNvData.DriverOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
+
+ *DescriptionData = 0x0000;
+ *OptionalData = 0x0000;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This function create a currently loaded Boot Option from
+ the BMM. It then appends this Boot Option to the end of
+ the "BootOrder" list. It also append this Boot Opotion to the end
+ of BootOptionMenu.
+
+ @param CallbackData The BMM context data.
+ @param NvRamMap The file explorer formset internal state.
+
+ @retval EFI_OUT_OF_RESOURCES If not enought memory to complete the operation.
+ @retval EFI_SUCCESS If function completes successfully.
+
+**/
+EFI_STATUS
+Var_UpdateBootOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN FILE_EXPLORER_NV_DATA *NvRamMap
+ )
+{
+ UINT16 *BootOrderList;
+ UINT16 *NewBootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 BootString[10];
+ VOID *Buffer;
+ UINTN BufferSize;
+ UINT8 *Ptr;
+ UINT16 Index;
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BOOLEAN OptionalDataExist;
+ EFI_STATUS Status;
+
+ OptionalDataExist = FALSE;
+
+ Index = BOpt_GetBootOptionNumber () ;
+ UnicodeSPrint (BootString, sizeof (BootString), L"Boot%04x", Index);
+
+ if (NvRamMap->BootDescriptionData[0] == 0x0000) {
+ StrCpyS (
+ NvRamMap->BootDescriptionData,
+ sizeof (NvRamMap->BootDescriptionData) / sizeof (NvRamMap->BootDescriptionData[0]),
+ BootString
+ );
+ }
+
+ BufferSize = sizeof (UINT32) + sizeof (UINT16) + StrSize (NvRamMap->BootDescriptionData);
+ BufferSize += GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ if (NvRamMap->BootOptionalData[0] != 0x0000) {
+ OptionalDataExist = TRUE;
+ BufferSize += StrSize (NvRamMap->BootOptionalData);
+ }
+
+ Buffer = AllocateZeroPool (BufferSize);
+ if (NULL == Buffer) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewMenuEntry = BOpt_CreateMenuEntry (BM_LOAD_CONTEXT_SELECT);
+ if (NULL == NewMenuEntry) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->Deleted = FALSE;
+ NewLoadContext->LoadOptionSize = BufferSize;
+ Ptr = (UINT8 *) Buffer;
+ NewLoadContext->LoadOption = Ptr;
+ *((UINT32 *) Ptr) = LOAD_OPTION_ACTIVE;
+ NewLoadContext->Attributes = *((UINT32 *) Ptr);
+ NewLoadContext->IsActive = TRUE;
+ NewLoadContext->ForceReconnect = (BOOLEAN) (NewLoadContext->Attributes & LOAD_OPTION_FORCE_RECONNECT);
+
+ Ptr += sizeof (UINT32);
+ *((UINT16 *) Ptr) = (UINT16) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+ NewLoadContext->FilePathListLength = *((UINT16 *) Ptr);
+ Ptr += sizeof (UINT16);
+
+ CopyMem (
+ Ptr,
+ NvRamMap->BootDescriptionData,
+ StrSize (NvRamMap->BootDescriptionData)
+ );
+
+ NewLoadContext->Description = AllocateZeroPool (StrSize (NvRamMap->BootDescriptionData));
+ ASSERT (NewLoadContext->Description != NULL);
+
+ NewMenuEntry->DisplayString = NewLoadContext->Description;
+ CopyMem (
+ NewLoadContext->Description,
+ (VOID *) Ptr,
+ StrSize (NvRamMap->BootDescriptionData)
+ );
+
+ Ptr += StrSize (NvRamMap->BootDescriptionData);
+ CopyMem (
+ Ptr,
+ CallbackData->LoadContext->FilePathList,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewLoadContext->FilePathList = AllocateZeroPool (GetDevicePathSize (CallbackData->LoadContext->FilePathList));
+ ASSERT (NewLoadContext->FilePathList != NULL);
+
+ CopyMem (
+ NewLoadContext->FilePathList,
+ (VOID *) Ptr,
+ GetDevicePathSize (CallbackData->LoadContext->FilePathList)
+ );
+
+ NewMenuEntry->HelpString = DevicePathToStr (NewLoadContext->FilePathList);
+ NewMenuEntry->OptionNumber = Index;
+ NewMenuEntry->DisplayStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionStrDepository
+ );
+ NewMenuEntry->DisplayStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->DisplayString, NULL);
+
+ NewMenuEntry->HelpStringToken = GetStringTokenFromDepository (
+ CallbackData,
+ BootOptionHelpStrDepository
+ );
+ NewMenuEntry->HelpStringToken = HiiSetString (CallbackData->FeHiiHandle, 0, NewMenuEntry->HelpString, NULL);
+
+ if (OptionalDataExist) {
+ Ptr += (UINT8) GetDevicePathSize (CallbackData->LoadContext->FilePathList);
+
+ CopyMem (Ptr, NvRamMap->BootOptionalData, StrSize (NvRamMap->BootOptionalData));
+ }
+
+ Status = gRT->SetVariable (
+ BootString,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BufferSize,
+ Buffer
+ );
+ if (!EFI_ERROR (Status)) {
+
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+ ASSERT (BootOrderList != NULL);
+ NewBootOrderList = AllocateZeroPool (BootOrderListSize + sizeof (UINT16));
+ ASSERT (NewBootOrderList != NULL);
+ CopyMem (NewBootOrderList, BootOrderList, BootOrderListSize);
+ NewBootOrderList[BootOrderListSize / sizeof (UINT16)] = Index;
+
+ if (BootOrderList != NULL) {
+ FreePool (BootOrderList);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderListSize + sizeof (UINT16),
+ NewBootOrderList
+ );
+ if (!EFI_ERROR (Status)) {
+
+ FreePool (NewBootOrderList);
+ NewBootOrderList = NULL;
+ InsertTailList (&BootOptionMenu.Head, &NewMenuEntry->Link);
+ BootOptionMenu.MenuNumber++;
+
+ //
+ // Update "change driver order" page used data, append the new add driver
+ // option at the end.
+ //
+ Index = 0;
+ while (CallbackData->BmmFakeNvData.BootOptionOrder[Index] != 0) {
+ Index++;
+ }
+ CallbackData->BmmFakeNvData.BootOptionOrder[Index] = (UINT32) (NewMenuEntry->OptionNumber + 1);
+
+ NvRamMap->BootDescriptionData[0] = 0x0000;
+ NvRamMap->BootOptionalData[0] = 0x0000;
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ This function update the "BootNext" EFI Variable. If there is
+ no "BootNext" specified in BMM, this EFI Variable is deleted.
+ It also update the BMM context data specified the "BootNext"
+ vaule.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @return The EFI variable can be saved. See gRT->SetVariable
+ for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateBootNext (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ BM_MENU_ENTRY *NewMenuEntry;
+ BM_LOAD_CONTEXT *NewLoadContext;
+ BMM_FAKE_NV_DATA *CurrentFakeNVMap;
+ UINT16 Index;
+ EFI_STATUS Status;
+
+ Status = EFI_SUCCESS;
+ CurrentFakeNVMap = &CallbackData->BmmFakeNvData;
+ for (Index = 0; Index < BootOptionMenu.MenuNumber; Index++) {
+ NewMenuEntry = BOpt_GetMenuEntry (&BootOptionMenu, Index);
+ ASSERT (NULL != NewMenuEntry);
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ NewLoadContext->IsBootNext = FALSE;
+ }
+
+ if (CurrentFakeNVMap->BootNext == BootOptionMenu.MenuNumber) {
+ EfiLibDeleteVariable (L"BootNext", &gEfiGlobalVariableGuid);
+ return EFI_SUCCESS;
+ }
+
+ NewMenuEntry = BOpt_GetMenuEntry (
+ &BootOptionMenu,
+ CurrentFakeNVMap->BootNext
+ );
+ ASSERT (NewMenuEntry != NULL);
+
+ NewLoadContext = (BM_LOAD_CONTEXT *) NewMenuEntry->VariableContext;
+ Status = gRT->SetVariable (
+ L"BootNext",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &NewMenuEntry->OptionNumber
+ );
+ NewLoadContext->IsBootNext = TRUE;
+ CallbackData->BmmOldFakeNVData.BootNext = CurrentFakeNVMap->BootNext;
+ return Status;
+}
+
+/**
+ This function update the "BootOrder" EFI Variable based on
+ BMM Formset's NV map. It then refresh BootOptionMenu
+ with the new "BootOrder" list.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to complete the function.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateBootOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ UINT16 OrderIndex;
+ UINT16 *BootOrderList;
+ UINTN BootOrderListSize;
+ UINT16 OptionNumber;
+
+ BootOrderList = NULL;
+ BootOrderListSize = 0;
+
+ //
+ // First check whether BootOrder is present in current configuration
+ //
+ BootOrderList = BdsLibGetVariableAndSize (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ &BootOrderListSize
+ );
+ if (BootOrderList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ASSERT (BootOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.BootOptionOrder) / sizeof (CallbackData->BmmFakeNvData.BootOptionOrder[0])));
+
+ for (OrderIndex = 0; (OrderIndex < BootOptionMenu.MenuNumber) && (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] != 0); OrderIndex++) {
+ for (Index = OrderIndex; Index < BootOrderListSize / sizeof (UINT16); Index++) {
+ if ((BootOrderList[Index] == (UINT16) (CallbackData->BmmFakeNvData.BootOptionOrder[OrderIndex] - 1)) && (OrderIndex != Index)) {
+ OptionNumber = BootOrderList[Index];
+ CopyMem (&BootOrderList[OrderIndex + 1], &BootOrderList[OrderIndex], (Index - OrderIndex) * sizeof (UINT16));
+ BootOrderList[OrderIndex] = OptionNumber;
+ }
+ }
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ BootOrderListSize,
+ BootOrderList
+ );
+ //
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ FreePool (BootOrderList);
+
+ GroupMultipleLegacyBootOption4SameType ();
+
+ BOpt_FreeMenu (&BootOptionMenu);
+ BOpt_GetBootOptions (CallbackData);
+
+ return Status;
+
+}
+
+/**
+ This function update the "DriverOrder" EFI Variable based on
+ BMM Formset's NV map. It then refresh DriverOptionMenu
+ with the new "DriverOrder" list.
+
+ @param CallbackData The BMM context data.
+
+ @retval EFI_SUCCESS The function complete successfully.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to complete the function.
+ @return The EFI variable can not be saved. See gRT->SetVariable for detail return information.
+
+**/
+EFI_STATUS
+Var_UpdateDriverOrder (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINT16 Index;
+ UINT16 *DriverOrderList;
+ UINT16 *NewDriverOrderList;
+ UINTN DriverOrderListSize;
+
+ DriverOrderList = NULL;
+ DriverOrderListSize = 0;
+
+ //
+ // First check whether DriverOrder is present in current configuration
+ //
+ DriverOrderList = BdsLibGetVariableAndSize (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ &DriverOrderListSize
+ );
+
+ NewDriverOrderList = AllocateZeroPool (DriverOrderListSize);
+
+ if (NewDriverOrderList == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // If exists, delete it to hold new DriverOrder
+ //
+ if (DriverOrderList != NULL) {
+ EfiLibDeleteVariable (L"DriverOrder", &gEfiGlobalVariableGuid);
+ FreePool (DriverOrderList);
+ }
+
+ ASSERT (DriverOptionMenu.MenuNumber <= (sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder) / sizeof (CallbackData->BmmFakeNvData.DriverOptionOrder[0])));
+ for (Index = 0; Index < DriverOptionMenu.MenuNumber; Index++) {
+ NewDriverOrderList[Index] = (UINT16) (CallbackData->BmmFakeNvData.DriverOptionOrder[Index] - 1);
+ }
+
+ Status = gRT->SetVariable (
+ L"DriverOrder",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ DriverOrderListSize,
+ NewDriverOrderList
+ );
+ //
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ BOpt_FreeMenu (&DriverOptionMenu);
+ BOpt_GetDriverOptions (CallbackData);
+ return EFI_SUCCESS;
+}
+
+/**
+ Update the legacy BBS boot option. VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable
+ is udpated with the new Legacy Boot order. The EFI Variable of "Boot####" and gEfiGlobalVariableGuid
+ is also updated.
+
+ @param CallbackData The context data for BMM.
+ @param FormId The form id.
+
+ @return EFI_SUCCESS The function completed successfully.
+ @retval EFI_NOT_FOUND If VAR_LEGACY_DEV_ORDER and gEfiLegacyDevOrderVariableGuid EFI Variable can be found.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource
+**/
+EFI_STATUS
+Var_UpdateBBSOption (
+ IN BMM_CALLBACK_DATA *CallbackData,
+ IN EFI_FORM_ID FormId
+ )
+{
+ UINTN Index;
+ UINTN Index2;
+ VOID *BootOptionVar;
+ CHAR16 VarName[100];
+ UINTN OptionSize;
+ EFI_STATUS Status;
+ UINT32 *Attribute;
+ BM_MENU_OPTION *OptionMenu;
+ UINT8 *LegacyDev;
+ UINT8 *VarData;
+ UINTN VarSize;
+ LEGACY_DEV_ORDER_ENTRY *DevOrder;
+ UINT8 *OriginalPtr;
+ UINT8 *DisMap;
+ UINTN Pos;
+ UINTN Bit;
+ UINT16 *NewOrder;
+ UINT16 Tmp;
+ UINT16 *EnBootOption;
+ UINTN EnBootOptionCount;
+ UINT16 *DisBootOption;
+ UINTN DisBootOptionCount;
+
+ DisMap = NULL;
+ NewOrder = NULL;
+
+ switch (FormId) {
+ case FORM_SET_FD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyFDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyFD;
+ CallbackData->BbsType = BBS_FLOPPY;
+ break;
+
+ case FORM_SET_HD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyHDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyHD;
+ CallbackData->BbsType = BBS_HARDDISK;
+ break;
+
+ case FORM_SET_CD_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyCDMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyCD;
+ CallbackData->BbsType = BBS_CDROM;
+ break;
+
+ case FORM_SET_NET_ORDER_ID:
+ OptionMenu = (BM_MENU_OPTION *) &LegacyNETMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyNET;
+ CallbackData->BbsType = BBS_EMBED_NETWORK;
+ break;
+
+ default:
+ ASSERT (FORM_SET_BEV_ORDER_ID == CallbackData->BmmPreviousPageId);
+ OptionMenu = (BM_MENU_OPTION *) &LegacyBEVMenu;
+ LegacyDev = CallbackData->BmmFakeNvData.LegacyBEV;
+ CallbackData->BbsType = BBS_BEV_DEVICE;
+ break;
+ }
+
+ DisMap = CallbackData->BmmOldFakeNVData.DisableMap;
+ Status = EFI_SUCCESS;
+
+
+ //
+ // Update the Variable "LegacyDevOrder"
+ //
+ VarData = (UINT8 *) BdsLibGetVariableAndSize (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ &VarSize
+ );
+
+ if (VarData == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ OriginalPtr = VarData;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+
+ while (VarData < OriginalPtr + VarSize) {
+ if (DevOrder->BbsType == CallbackData->BbsType) {
+ break;
+ }
+
+ VarData += sizeof (BBS_TYPE) + DevOrder->Length;
+ DevOrder = (LEGACY_DEV_ORDER_ENTRY *) VarData;
+ }
+
+ if (VarData >= OriginalPtr + VarSize) {
+ FreePool (OriginalPtr);
+ return EFI_NOT_FOUND;
+ }
+
+ NewOrder = AllocateZeroPool (DevOrder->Length - sizeof (DevOrder->Length));
+ if (NewOrder == NULL) {
+ FreePool (OriginalPtr);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for (Index = 0; Index < OptionMenu->MenuNumber; Index++) {
+ if (0xFF == LegacyDev[Index]) {
+ break;
+ }
+
+ NewOrder[Index] = LegacyDev[Index];
+ }
+ //
+ // Only the enable/disable state of each boot device with same device type can be changed,
+ // so we can count on the index information in DevOrder.
+ // DisMap bit array is the only reliable source to check a device's en/dis state,
+ // so we use DisMap to set en/dis state of each item in NewOrder array
+ //
+ for (Index2 = 0; Index2 < OptionMenu->MenuNumber; Index2++) {
+ Tmp = (UINT16) (DevOrder->Data[Index2] & 0xFF);
+ Pos = Tmp / 8;
+ Bit = 7 - (Tmp % 8);
+ if ((DisMap[Pos] & (1 << Bit)) != 0) {
+ NewOrder[Index] = (UINT16) (0xFF00 | Tmp);
+ Index++;
+ }
+ }
+
+ CopyMem (
+ DevOrder->Data,
+ NewOrder,
+ DevOrder->Length - sizeof (DevOrder->Length)
+ );
+ FreePool (NewOrder);
+
+ Status = gRT->SetVariable (
+ VAR_LEGACY_DEV_ORDER,
+ &gEfiLegacyDevOrderVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ VarSize,
+ OriginalPtr
+ );
+
+
+ //
+ // Update BootOrder and Boot####.Attribute
+ //
+ // 1. Re-order the Option Number in BootOrder according to Legacy Dev Order
+ //
+ ASSERT (OptionMenu->MenuNumber == DevOrder->Length / sizeof (UINT16) - 1);
+
+ OrderLegacyBootOption4SameType (
+ DevOrder->Data,
+ DevOrder->Length / sizeof (UINT16) - 1,
+ &EnBootOption,
+ &EnBootOptionCount,
+ &DisBootOption,
+ &DisBootOptionCount
+ );
+
+ //
+ // 2. Deactivate the DisBootOption and activate the EnBootOption
+ //
+ for (Index = 0; Index < DisBootOptionCount; Index++) {
+ UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", DisBootOption[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (BootOptionVar != NULL) {
+ Attribute = (UINT32 *) BootOptionVar;
+ *Attribute &= ~LOAD_OPTION_ACTIVE;
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionSize,
+ BootOptionVar
+ );
+ //
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOptionVar);
+ }
+ }
+
+ for (Index = 0; Index < EnBootOptionCount; Index++) {
+ UnicodeSPrint (VarName, sizeof (VarName), L"Boot%04x", EnBootOption[Index]);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ &OptionSize
+ );
+ if (BootOptionVar != NULL) {
+ Attribute = (UINT32 *) BootOptionVar;
+ *Attribute |= LOAD_OPTION_ACTIVE;
+
+ Status = gRT->SetVariable (
+ VarName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ OptionSize,
+ BootOptionVar
+ );
+ //
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ FreePool (BootOptionVar);
+ }
+ }
+
+ BOpt_GetBootOptions (CallbackData);
+
+ FreePool (OriginalPtr);
+ FreePool (EnBootOption);
+ FreePool (DisBootOption);
+ return Status;
+}
+
+/**
+ Update the Text Mode of Console.
+
+ @param CallbackData The context data for BMM.
+
+ @retval EFI_SUCCSS If the Text Mode of Console is updated.
+ @return Other value if the Text Mode of Console is not updated.
+
+**/
+EFI_STATUS
+Var_UpdateConMode (
+ IN BMM_CALLBACK_DATA *CallbackData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Mode;
+ CONSOLE_OUT_MODE ModeInfo;
+
+ Mode = CallbackData->BmmFakeNvData.ConsoleOutMode;
+
+ Status = gST->ConOut->QueryMode (gST->ConOut, Mode, &(ModeInfo.Column), &(ModeInfo.Row));
+ if (!EFI_ERROR(Status)) {
+ Status = PcdSet32S (PcdSetupConOutColumn, (UINT32) ModeInfo.Column);
+ if (!EFI_ERROR (Status)){
+ Status = PcdSet32S (PcdSetupConOutRow, (UINT32) ModeInfo.Row);
+ }
+ }
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.c
new file mode 100644
index 0000000000..6efd783ab2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.c
@@ -0,0 +1,399 @@
+/** @file
+ The platform boot manager reference implementation
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "BootManager.h"
+
+UINT16 mKeyInput;
+LIST_ENTRY mBootOptionsList;
+BDS_COMMON_OPTION *gOption;
+CHAR16 *mDeviceTypeStr[] = {
+ L"Legacy BEV",
+ L"Legacy Floppy",
+ L"Legacy Hard Drive",
+ L"Legacy CD ROM",
+ L"Legacy PCMCIA",
+ L"Legacy USB",
+ L"Legacy Embedded Network",
+ L"Legacy Unknown Device"
+};
+
+
+HII_VENDOR_DEVICE_PATH mBootManagerHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ BOOT_MANAGER_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+BOOT_MANAGER_CALLBACK_DATA gBootManagerPrivate = {
+ BOOT_MANAGER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ BootManagerCallback
+ }
+};
+
+/**
+ This call back function is registered with Boot Manager formset.
+ When user selects a boot option, this call back function will
+ be triggered. The boot option is saved for later processing.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+BootManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ BDS_COMMON_OPTION *Option;
+ LIST_ENTRY *Link;
+ UINT16 KeyCount;
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Initialize the key count
+ //
+ KeyCount = 0;
+
+ for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ KeyCount++;
+
+ gOption = Option;
+
+ //
+ // Is this device the one chosen?
+ //
+ if (KeyCount == QuestionId) {
+ //
+ // Assigning the returned Key to a global allows the original routine to know what was chosen
+ //
+ mKeyInput = QuestionId;
+
+ //
+ // Request to exit SendForm(), so that we could boot the selected option
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+
+ Registers HII packages for the Boot Manger to HII Database.
+ It also registers the browser call back function.
+
+ @retval EFI_SUCCESS HII packages for the Boot Manager were registered successfully.
+ @retval EFI_OUT_OF_RESOURCES HII packages for the Boot Manager failed to be registered.
+
+**/
+EFI_STATUS
+InitializeBootManager (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gBootManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mBootManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gBootManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ gBootManagerPrivate.HiiHandle = HiiAddPackages (
+ &gBootManagerFormSetGuid,
+ gBootManagerPrivate.DriverHandle,
+ BootManagerVfrBin,
+ BdsDxeStrings,
+ NULL
+ );
+ if (gBootManagerPrivate.HiiHandle == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ } else {
+ Status = EFI_SUCCESS;
+ }
+ return Status;
+}
+
+/**
+ This function invokes Boot Manager. If all devices have not a chance to be connected,
+ the connect all will be triggered. It then enumerate all boot options. If
+ a boot option from the Boot Manager page is selected, Boot Manager will boot
+ from this boot option.
+
+**/
+VOID
+CallBootManager (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ BDS_COMMON_OPTION *Option;
+ LIST_ENTRY *Link;
+ CHAR16 *ExitData;
+ UINTN ExitDataSize;
+ EFI_STRING_ID Token;
+ EFI_INPUT_KEY Key;
+ CHAR16 *HelpString;
+ UINTN HelpSize;
+ EFI_STRING_ID HelpToken;
+ UINT16 *TempStr;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ UINT16 DeviceType;
+ BOOLEAN IsLegacyOption;
+ BOOLEAN NeedEndOp;
+
+ DeviceType = (UINT16) -1;
+ gOption = NULL;
+ InitializeListHead (&mBootOptionsList);
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+
+ BdsLibEnumerateAllBootOption (&mBootOptionsList);
+
+ //
+ // Group the legacy boot options for the same device type
+ //
+ GroupMultipleLegacyBootOption4SameType ();
+
+ InitializeListHead (&mBootOptionsList);
+ BdsLibBuildOptionFromVar (&mBootOptionsList, L"BootOrder");
+
+ HiiHandle = gBootManagerPrivate.HiiHandle;
+
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_BOOT_OPTION;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_BOOT_OPTION_END;
+
+ mKeyInput = 0;
+ NeedEndOp = FALSE;
+ for (Link = GetFirstNode (&mBootOptionsList); !IsNull (&mBootOptionsList, Link); Link = GetNextNode (&mBootOptionsList, Link)) {
+ Option = CR (Link, BDS_COMMON_OPTION, Link, BDS_LOAD_OPTION_SIGNATURE);
+
+ //
+ // At this stage we are creating a menu entry, thus the Keys are reproduceable
+ //
+ mKeyInput++;
+
+ //
+ // Don't display the hidden/inactive boot option
+ //
+ if (((Option->Attribute & LOAD_OPTION_HIDDEN) != 0) || ((Option->Attribute & LOAD_OPTION_ACTIVE) == 0)) {
+ continue;
+ }
+
+ //
+ // Group the legacy boot option in the sub title created dynamically
+ //
+ IsLegacyOption = (BOOLEAN) (
+ (DevicePathType (Option->DevicePath) == BBS_DEVICE_PATH) &&
+ (DevicePathSubType (Option->DevicePath) == BBS_BBS_DP)
+ );
+
+ if (!IsLegacyOption && NeedEndOp) {
+ NeedEndOp = FALSE;
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ if (IsLegacyOption && DeviceType != ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType) {
+ if (NeedEndOp) {
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ DeviceType = ((BBS_BBS_DEVICE_PATH *) Option->DevicePath)->DeviceType;
+ Token = HiiSetString (
+ HiiHandle,
+ 0,
+ mDeviceTypeStr[
+ MIN (DeviceType & 0xF, sizeof (mDeviceTypeStr) / sizeof (mDeviceTypeStr[0]) - 1)
+ ],
+ NULL
+ );
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, Token, 0, 0, 1);
+ NeedEndOp = TRUE;
+ }
+
+ ASSERT (Option->Description != NULL);
+
+ Token = HiiSetString (HiiHandle, 0, Option->Description, NULL);
+
+ TempStr = DevicePathToStr (Option->DevicePath);
+ HelpSize = StrSize (TempStr) + StrSize (L"Device Path : ");
+ HelpString = AllocateZeroPool (HelpSize);
+ ASSERT (HelpString != NULL);
+ StrCatS (HelpString, HelpSize / sizeof (CHAR16), L"Device Path : ");
+ StrCatS (HelpString, HelpSize / sizeof (CHAR16), TempStr);
+
+ HelpToken = HiiSetString (HiiHandle, 0, HelpString, NULL);
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ mKeyInput,
+ Token,
+ HelpToken,
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ }
+
+ if (NeedEndOp) {
+ HiiCreateEndOpCode (StartOpCodeHandle);
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &gBootManagerFormSetGuid,
+ BOOT_MANAGER_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandle,
+ 1,
+ &gBootManagerFormSetGuid,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ if (gOption == NULL) {
+ return ;
+ }
+
+ //
+ // Will leave browser, check any reset required change is applied? if yes, reset system
+ //
+ SetupResetReminder ();
+
+ //
+ // Restore to original mode before launching boot option.
+ //
+ BdsSetConsoleMode (FALSE);
+
+ //
+ // parse the selected option
+ //
+ Status = BdsLibBootViaBootOption (gOption, gOption->DevicePath, &ExitDataSize, &ExitData);
+
+ if (!EFI_ERROR (Status)) {
+ gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (gOption);
+ } else {
+ gOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (gOption, Status, ExitData, ExitDataSize);
+ gST->ConOut->OutputString (
+ gST->ConOut,
+ GetStringById (STRING_TOKEN (STR_ANY_KEY_CONTINUE))
+ );
+ gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.h
new file mode 100644
index 0000000000..e26147183a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManager.h
@@ -0,0 +1,103 @@
+/** @file
+ The platform boot manager reference implement
+
+Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_BOOT_MANAGER_H_
+#define _EFI_BOOT_MANAGER_H_
+
+#include "Bds.h"
+#include "FrontPage.h"
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+#define LABEL_BOOT_OPTION_END 0x01
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 BootManagerVfrBin[];
+
+#define BOOT_MANAGER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('B', 'M', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} BOOT_MANAGER_CALLBACK_DATA;
+
+/**
+ This call back function is registered with Boot Manager formset.
+ When user selects a boot option, this call back function will
+ be triggered. The boot option is saved for later processing.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+BootManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+/**
+
+ Registers HII packages for the Boot Manger to HII Database.
+ It also registers the browser call back function.
+
+ @retval EFI_SUCCESS HII packages for the Boot Manager were registered successfully.
+ @retval EFI_OUT_OF_RESOURCES HII packages for the Boot Manager failed to be registered.
+
+**/
+EFI_STATUS
+InitializeBootManager (
+ VOID
+ );
+
+/**
+ This function invokes Boot Manager. If all devices have not a chance to be connected,
+ the connect all will be triggered. It then enumerate all boot options. If
+ a boot option from the Boot Manager page is selected, Boot Manager will boot
+ from this boot option.
+
+**/
+VOID
+CallBootManager (
+ VOID
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni
new file mode 100644
index 0000000000..e62c264da3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr
new file mode 100644
index 0000000000..0d8142c17d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/BootMngr/BootManagerVfr.Vfr
@@ -0,0 +1,50 @@
+///** @file
+//
+// Browser formset.
+//
+// Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include <Guid/BdsHii.h>
+
+#define BOOT_MANAGER_FORM_ID 0x1000
+
+#define LABEL_BOOT_OPTION 0x00
+#define LABEL_BOOT_OPTION_END 0x01
+
+#define BOOT_MANAGER_CLASS 0x00
+#define BOOT_MANAGER_SUBCLASS 0x00
+
+formset
+ guid = BOOT_MANAGER_FORMSET_GUID,
+ title = STRING_TOKEN(STR_BM_BANNER),
+ help = STRING_TOKEN(STR_LAST_STRING),
+ classguid = BOOT_MANAGER_FORMSET_GUID,
+
+ form formid = BOOT_MANAGER_FORM_ID,
+ title = STRING_TOKEN(STR_BM_BANNER);
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ subtitle text = STRING_TOKEN(STR_BOOT_OPTION_BANNER);
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+
+ //
+ // This is where we will dynamically add choices for the Boot Manager
+ //
+ label LABEL_BOOT_OPTION;
+ label LABEL_BOOT_OPTION_END;
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ subtitle text = STRING_TOKEN(STR_HELP_FOOTER);
+
+ endform;
+
+endformset;
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c
new file mode 100644
index 0000000000..6c7fc7ced4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Capsules.c
@@ -0,0 +1,233 @@
+/** @file
+ BDS routines to handle capsules.
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+#include "Bds.h"
+
+/**
+
+ This routine is called to see if there are any capsules we need to process.
+ If the boot mode is not UPDATE, then we do nothing. Otherwise find the
+ capsule HOBS and produce firmware volumes for them via the DXE service.
+ Then call the dispatcher to dispatch drivers from them. Finally, check
+ the status of the updates.
+
+ This function should be called by BDS in case we need to do some
+ sort of processing even if there is no capsule to process. We
+ need to do this if an earlier update went away and we need to
+ clear the capsule variable so on the next reset PEI does not see it and
+ think there is a capsule available.
+
+ @param BootMode the current boot mode
+
+ @retval EFI_INVALID_PARAMETER boot mode is not correct for an update
+ @retval EFI_SUCCESS There is no error when processing capsule
+
+**/
+EFI_STATUS
+EFIAPI
+BdsProcessCapsules (
+ EFI_BOOT_MODE BootMode
+ )
+{
+ EFI_STATUS Status;
+ EFI_PEI_HOB_POINTERS HobPointer;
+ EFI_CAPSULE_HEADER *CapsuleHeader;
+ UINT32 Size;
+ UINT32 CapsuleNumber;
+ UINT32 CapsuleTotalNumber;
+ EFI_CAPSULE_TABLE *CapsuleTable;
+ UINT32 Index;
+ UINT32 CacheIndex;
+ UINT32 CacheNumber;
+ VOID **CapsulePtr;
+ VOID **CapsulePtrCache;
+ EFI_GUID *CapsuleGuidCache;
+ BOOLEAN NeedReset;
+
+ CapsuleNumber = 0;
+ CapsuleTotalNumber = 0;
+ CacheIndex = 0;
+ CacheNumber = 0;
+ CapsulePtr = NULL;
+ CapsulePtrCache = NULL;
+ CapsuleGuidCache = NULL;
+ NeedReset = FALSE;
+
+ //
+ // We don't do anything else if the boot mode is not flash-update
+ //
+ if (BootMode != BOOT_ON_FLASH_UPDATE) {
+ DEBUG ((EFI_D_ERROR, "Boot mode is not correct for capsule update.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
+ CapsuleTotalNumber ++;
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ if (CapsuleTotalNumber == 0) {
+ //
+ // We didn't find a hob, so had no errors.
+ //
+ DEBUG ((EFI_D_ERROR, "We can not find capsule data in capsule update boot mode.\n"));
+ DEBUG ((EFI_D_ERROR, "Please check the followings are correct if unexpected capsule update error happens.\n"));
+ DEBUG ((EFI_D_ERROR, "1. CapsuleX64 is built as X64 module when PEI is IA32 and DXE is X64\n"));
+ DEBUG ((EFI_D_ERROR, "2. Capsule data should persist in memory across a system reset.\n"));
+ PlatformBdsLockNonUpdatableFlash ();
+ return EFI_SUCCESS;
+ }
+
+ //
+ // Init temp Capsule Data table.
+ //
+ CapsulePtr = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
+ ASSERT (CapsulePtr != NULL);
+ CapsulePtrCache = (VOID **) AllocateZeroPool (sizeof (VOID *) * CapsuleTotalNumber);
+ ASSERT (CapsulePtrCache != NULL);
+ CapsuleGuidCache = (EFI_GUID *) AllocateZeroPool (sizeof (EFI_GUID) * CapsuleTotalNumber);
+ ASSERT (CapsuleGuidCache != NULL);
+
+ //
+ // Find all capsule images from hob
+ //
+ HobPointer.Raw = GetHobList ();
+ while ((HobPointer.Raw = GetNextHob (EFI_HOB_TYPE_UEFI_CAPSULE, HobPointer.Raw)) != NULL) {
+ CapsulePtr [CapsuleNumber++] = (VOID *) (UINTN) HobPointer.Capsule->BaseAddress;
+ HobPointer.Raw = GET_NEXT_HOB (HobPointer);
+ }
+
+ //
+ //Check the capsule flags,if contains CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE, install
+ //capsuleTable to configure table with EFI_CAPSULE_GUID
+ //
+
+ //
+ // Capsules who have CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE always are used for operating
+ // System to have information persist across a system reset. EFI System Table must
+ // point to an array of capsules that contains the same CapsuleGuid value. And agents
+ // searching for this type capsule will look in EFI System Table and search for the
+ // capsule's Guid and associated pointer to retrieve the data. Two steps below describes
+ // how to sorting the capsules by the unique guid and install the array to EFI System Table.
+ // Firstly, Loop for all coalesced capsules, record unique CapsuleGuids and cache them in an
+ // array for later sorting capsules by CapsuleGuid.
+ //
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
+ //
+ // For each capsule, we compare it with known CapsuleGuid in the CacheArray.
+ // If already has the Guid, skip it. Whereas, record it in the CacheArray as
+ // an additional one.
+ //
+ CacheIndex = 0;
+ while (CacheIndex < CacheNumber) {
+ if (CompareGuid(&CapsuleGuidCache[CacheIndex],&CapsuleHeader->CapsuleGuid)) {
+ break;
+ }
+ CacheIndex++;
+ }
+ if (CacheIndex == CacheNumber) {
+ CopyMem(&CapsuleGuidCache[CacheNumber++],&CapsuleHeader->CapsuleGuid,sizeof(EFI_GUID));
+ }
+ }
+ }
+
+ //
+ // Secondly, for each unique CapsuleGuid in CacheArray, gather all coalesced capsules
+ // whose guid is the same as it, and malloc memory for an array which preceding
+ // with UINT32. The array fills with entry point of capsules that have the same
+ // CapsuleGuid, and UINT32 represents the size of the array of capsules. Then install
+ // this array into EFI System Table, so that agents searching for this type capsule
+ // will look in EFI System Table and search for the capsule's Guid and associated
+ // pointer to retrieve the data.
+ //
+ CacheIndex = 0;
+ while (CacheIndex < CacheNumber) {
+ CapsuleNumber = 0;
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) != 0) {
+ if (CompareGuid (&CapsuleGuidCache[CacheIndex], &CapsuleHeader->CapsuleGuid)) {
+ //
+ // Cache Caspuleheader to the array, this array is uniqued with certain CapsuleGuid.
+ //
+ CapsulePtrCache[CapsuleNumber++] = (VOID*)CapsuleHeader;
+ }
+ }
+ }
+ if (CapsuleNumber != 0) {
+ Size = sizeof(EFI_CAPSULE_TABLE) + (CapsuleNumber - 1) * sizeof(VOID*);
+ CapsuleTable = AllocateRuntimePool (Size);
+ ASSERT (CapsuleTable != NULL);
+ CapsuleTable->CapsuleArrayNumber = CapsuleNumber;
+ CopyMem(&CapsuleTable->CapsulePtr[0], CapsulePtrCache, CapsuleNumber * sizeof(VOID*));
+ Status = gBS->InstallConfigurationTable (&CapsuleGuidCache[CacheIndex], (VOID*)CapsuleTable);
+ ASSERT_EFI_ERROR (Status);
+ }
+ CacheIndex++;
+ }
+
+ //
+ // Besides ones with CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE flag, all capsules left are
+ // recognized by platform with CapsuleGuid. For general platform driver, UpdateFlash
+ // type is commonly supported, so here only deal with encapsuled FVs capsule. Additional
+ // type capsule transaction could be extended. It depends on platform policy.
+ //
+ for (Index = 0; Index < CapsuleTotalNumber; Index++) {
+ CapsuleHeader = (EFI_CAPSULE_HEADER*) CapsulePtr [Index];
+ if ((CapsuleHeader->Flags & CAPSULE_FLAGS_POPULATE_SYSTEM_TABLE) == 0) {
+ //
+ // Always reset system after all capsule processed if FMP capsule exist
+ //
+ if (CompareGuid (&gEfiFmpCapsuleGuid, &CapsuleHeader->CapsuleGuid)){
+ NeedReset = TRUE;
+ }
+
+ //
+ // Call capsule library to process capsule image.
+ //
+ ProcessCapsuleImage (CapsuleHeader);
+ }
+ }
+
+ if (NeedReset) {
+ Print(L"Capsule Request Cold Reboot.\n");
+
+ for (Index = 5; Index > 0; Index--) {
+ Print(L"\rResetting system in %d seconds ...", Index);
+ gBS->Stall (1000000);
+ }
+
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ CpuDeadLoop ();
+ }
+
+ PlatformBdsLockNonUpdatableFlash ();
+
+ //
+ // Free the allocated temp memory space.
+ //
+ FreePool (CapsuleGuidCache);
+ FreePool (CapsulePtrCache);
+ FreePool (CapsulePtr);
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c
new file mode 100644
index 0000000000..af2b18a047
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.c
@@ -0,0 +1,2591 @@
+/** @file
+ The platform device manager reference implementation
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DeviceManager.h"
+
+DEVICE_MANAGER_CALLBACK_DATA gDeviceManagerPrivate = {
+ DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ DeviceManagerCallback
+ },
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ DriverHealthCallback
+ }
+};
+
+#define MAX_MAC_ADDRESS_NODE_LIST_LEN 10
+
+//
+// Which Mac Address string is select
+// it will decide what menu need to show in the NETWORK_DEVICE_FORM_ID form.
+//
+EFI_STRING mSelectedMacAddrString;
+
+//
+// Which form Id need to be show.
+//
+EFI_FORM_ID mNextShowFormId = DEVICE_MANAGER_FORM_ID;
+
+//
+// The Mac Address show in the NETWORK_DEVICE_LIST_FORM_ID
+//
+MAC_ADDRESS_NODE_LIST mMacDeviceList;
+
+DEVICE_MANAGER_MENU_ITEM mDeviceManagerMenuItemTable[] = {
+ { STRING_TOKEN (STR_DISK_DEVICE), EFI_DISK_DEVICE_CLASS },
+ { STRING_TOKEN (STR_VIDEO_DEVICE), EFI_VIDEO_DEVICE_CLASS },
+ { STRING_TOKEN (STR_NETWORK_DEVICE), EFI_NETWORK_DEVICE_CLASS },
+ { STRING_TOKEN (STR_INPUT_DEVICE), EFI_INPUT_DEVICE_CLASS },
+ { STRING_TOKEN (STR_ON_BOARD_DEVICE), EFI_ON_BOARD_DEVICE_CLASS },
+ { STRING_TOKEN (STR_OTHER_DEVICE), EFI_OTHER_DEVICE_CLASS }
+};
+
+HII_VENDOR_DEVICE_PATH mDeviceManagerHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ DEVICE_MANAGER_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mDriverHealthHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ DRIVER_HEALTH_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ This function is invoked if user selected a interactive opcode from Device Manager's
+ Formset. The decision by user is saved to gCallbackKey for later processing. If
+ user set VBIOS, the new value is saved to EFI variable.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+DeviceManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ UINTN CurIndex;
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gCallbackKey = QuestionId;
+ if ((QuestionId < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET) && (QuestionId >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
+ //
+ // If user select the mac address, need to record mac address string to support next form show.
+ //
+ for (CurIndex = 0; CurIndex < mMacDeviceList.CurListLen; CurIndex ++) {
+ if (mMacDeviceList.NodeList[CurIndex].QuestionId == QuestionId) {
+ mSelectedMacAddrString = HiiGetString (gDeviceManagerPrivate.HiiHandle, mMacDeviceList.NodeList[CurIndex].PromptId, NULL);
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This function registers HII packages to HII database.
+
+ @retval EFI_SUCCESS HII packages for the Device Manager were registered successfully.
+ @retval EFI_OUT_OF_RESOURCES HII packages for the Device Manager failed to be registered.
+
+**/
+EFI_STATUS
+InitializeDeviceManager (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gDeviceManagerPrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDeviceManagerHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gDeviceManagerPrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gDeviceManagerPrivate.DriverHealthHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mDriverHealthHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gDeviceManagerPrivate.DriverHealthConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ mMacDeviceList.CurListLen = 0;
+ mMacDeviceList.MaxListLen = 0;
+
+ return Status;
+}
+
+/**
+ Extract the displayed formset for given HII handle and class guid.
+
+ @param Handle The HII handle.
+ @param SetupClassGuid The class guid specifies which form set will be displayed.
+ @param SkipCount Skip some formsets which has processed before.
+ @param FormSetTitle Formset title string.
+ @param FormSetHelp Formset help string.
+ @param FormSetGuid Return the formset guid for this formset.
+
+ @retval TRUE The formset for given HII handle will be displayed.
+ @return FALSE The formset for given HII handle will not be displayed.
+
+**/
+BOOLEAN
+ExtractDisplayedHiiFormFromHiiHandle (
+ IN EFI_HII_HANDLE Handle,
+ IN EFI_GUID *SetupClassGuid,
+ IN UINTN SkipCount,
+ OUT EFI_STRING_ID *FormSetTitle,
+ OUT EFI_STRING_ID *FormSetHelp,
+ OUT EFI_GUID **FormSetGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HII_PACKAGE_LIST_HEADER *HiiPackageList;
+ UINT8 *Package;
+ UINT8 *OpCodeData;
+ UINT32 Offset;
+ UINT32 Offset2;
+ UINT32 PackageListLength;
+ EFI_HII_PACKAGE_HEADER PackageHeader;
+ EFI_GUID *ClassGuid;
+ UINT8 ClassGuidNum;
+
+ ASSERT (Handle != NULL);
+ ASSERT (SetupClassGuid != NULL);
+ ASSERT (FormSetTitle != NULL);
+ ASSERT (FormSetHelp != NULL);
+
+ *FormSetTitle = 0;
+ *FormSetHelp = 0;
+ ClassGuidNum = 0;
+ ClassGuid = NULL;
+
+ //
+ // Get HII PackageList
+ //
+ BufferSize = 0;
+ HiiPackageList = NULL;
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ //
+ // Handle is a invalid handle. Check if Handle is corrupted.
+ //
+ ASSERT (Status != EFI_NOT_FOUND);
+ //
+ // The return status should always be EFI_BUFFER_TOO_SMALL as input buffer's size is 0.
+ //
+ ASSERT (Status == EFI_BUFFER_TOO_SMALL);
+
+ HiiPackageList = AllocatePool (BufferSize);
+ ASSERT (HiiPackageList != NULL);
+
+ Status = gHiiDatabase->ExportPackageLists (gHiiDatabase, Handle, &BufferSize, HiiPackageList);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Get Form package from this HII package List
+ //
+ Offset = sizeof (EFI_HII_PACKAGE_LIST_HEADER);
+ Offset2 = 0;
+ PackageListLength = ReadUnaligned32 (&HiiPackageList->PackageLength);
+
+ while (Offset < PackageListLength) {
+ Package = ((UINT8 *) HiiPackageList) + Offset;
+ CopyMem (&PackageHeader, Package, sizeof (EFI_HII_PACKAGE_HEADER));
+
+ if (PackageHeader.Type == EFI_HII_PACKAGE_FORMS) {
+ //
+ // Search FormSet Opcode in this Form Package
+ //
+ Offset2 = sizeof (EFI_HII_PACKAGE_HEADER);
+ while (Offset2 < PackageHeader.Length) {
+ OpCodeData = Package + Offset2;
+ Offset2 += ((EFI_IFR_OP_HEADER *) OpCodeData)->Length;
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->OpCode == EFI_IFR_FORM_SET_OP) {
+ if (SkipCount != 0) {
+ SkipCount --;
+ continue;
+ }
+
+ if (((EFI_IFR_OP_HEADER *) OpCodeData)->Length > OFFSET_OF (EFI_IFR_FORM_SET, Flags)) {
+ //
+ // Find FormSet OpCode
+ //
+ ClassGuidNum = (UINT8) (((EFI_IFR_FORM_SET *) OpCodeData)->Flags & 0x3);
+ ClassGuid = (EFI_GUID *) (VOID *)(OpCodeData + sizeof (EFI_IFR_FORM_SET));
+ while (ClassGuidNum-- > 0) {
+ if (CompareGuid (SetupClassGuid, ClassGuid)) {
+ CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+ CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
+ *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
+ ASSERT (*FormSetGuid != NULL);
+ FreePool (HiiPackageList);
+ return TRUE;
+ }
+ ClassGuid ++;
+ }
+ } else {
+ CopyMem (FormSetTitle, &((EFI_IFR_FORM_SET *) OpCodeData)->FormSetTitle, sizeof (EFI_STRING_ID));
+ CopyMem (FormSetHelp, &((EFI_IFR_FORM_SET *) OpCodeData)->Help, sizeof (EFI_STRING_ID));
+ *FormSetGuid = AllocateCopyPool (sizeof (EFI_GUID), &((EFI_IFR_FORM_SET *) OpCodeData)->Guid);
+ ASSERT (*FormSetGuid != NULL);
+ FreePool (HiiPackageList);
+ return TRUE;
+ }
+ }
+ }
+ }
+
+ //
+ // Go to next package
+ //
+ Offset += PackageHeader.Length;
+ }
+
+ FreePool (HiiPackageList);
+
+ return FALSE;
+}
+
+/**
+ Get the mac address string from the device path.
+ if the device path has the vlan, get the vanid also.
+
+ @param MacAddressNode Device path begin with mac address
+ @param PBuffer Output string buffer contain mac address.
+
+**/
+BOOLEAN
+GetMacAddressString(
+ IN MAC_ADDR_DEVICE_PATH *MacAddressNode,
+ OUT CHAR16 **PBuffer
+ )
+{
+ UINTN HwAddressSize;
+ UINTN Index;
+ UINT8 *HwAddress;
+ EFI_DEVICE_PATH_PROTOCOL *Node;
+ UINT16 VlanId;
+ CHAR16 *String;
+ UINTN BufferLen;
+
+ VlanId = 0;
+ String = NULL;
+ ASSERT(MacAddressNode != NULL);
+
+ HwAddressSize = sizeof (EFI_MAC_ADDRESS);
+ if (MacAddressNode->IfType == 0x01 || MacAddressNode->IfType == 0x00) {
+ HwAddressSize = 6;
+ }
+
+ //
+ // The output format is MAC:XX:XX:XX:...\XXXX
+ // The size is the Number size + ":" size + Vlan size(\XXXX) + End
+ //
+ BufferLen = (4 + 2 * HwAddressSize + (HwAddressSize - 1) + 5 + 1) * sizeof (CHAR16);
+ String = AllocateZeroPool (BufferLen);
+ if (String == NULL) {
+ return FALSE;
+ }
+
+ *PBuffer = String;
+ StrCpyS (String, BufferLen / sizeof (CHAR16), L"MAC:");
+ String += 4;
+
+ //
+ // Convert the MAC address into a unicode string.
+ //
+ HwAddress = &MacAddressNode->MacAddress.Addr[0];
+ for (Index = 0; Index < HwAddressSize; Index++) {
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, *(HwAddress++), 2);
+ if (Index < HwAddressSize - 1) {
+ *String++ = L':';
+ }
+ }
+
+ //
+ // If VLAN is configured, it will need extra 5 characters like "\0005".
+ // Plus one unicode character for the null-terminator.
+ //
+ Node = (EFI_DEVICE_PATH_PROTOCOL *)MacAddressNode;
+ while (!IsDevicePathEnd (Node)) {
+ if (Node->Type == MESSAGING_DEVICE_PATH && Node->SubType == MSG_VLAN_DP) {
+ VlanId = ((VLAN_DEVICE_PATH *) Node)->VlanId;
+ }
+ Node = NextDevicePathNode (Node);
+ }
+
+ if (VlanId != 0) {
+ *String++ = L'\\';
+ String += UnicodeValueToString (String, PREFIX_ZERO | RADIX_HEX, VlanId, 4);
+ }
+
+ //
+ // Null terminate the Unicode string
+ //
+ *String = L'\0';
+
+ return TRUE;
+}
+
+/**
+ Save question id and prompt id to the mac device list.
+ If the same mac address has saved yet, no need to add more.
+
+ @param MacAddrString Mac address string.
+
+ @retval EFI_SUCCESS Add the item is successful.
+ @return Other values if failed to Add the item.
+**/
+BOOLEAN
+AddIdToMacDeviceList (
+ IN EFI_STRING MacAddrString
+ )
+{
+ MENU_INFO_ITEM *TempDeviceList;
+ UINTN Index;
+ EFI_STRING StoredString;
+ EFI_STRING_ID PromptId;
+ EFI_HII_HANDLE HiiHandle;
+
+ HiiHandle = gDeviceManagerPrivate.HiiHandle;
+ TempDeviceList = NULL;
+
+ for (Index = 0; Index < mMacDeviceList.CurListLen; Index ++) {
+ StoredString = HiiGetString (HiiHandle, mMacDeviceList.NodeList[Index].PromptId, NULL);
+ if (StoredString == NULL) {
+ return FALSE;
+ }
+
+ //
+ // Already has save the same mac address to the list.
+ //
+ if (StrCmp (MacAddrString, StoredString) == 0) {
+ return FALSE;
+ }
+ }
+
+ PromptId = HiiSetString(HiiHandle, 0, MacAddrString, NULL);
+ //
+ // If not in the list, save it.
+ //
+ if (mMacDeviceList.MaxListLen > mMacDeviceList.CurListLen + 1) {
+ mMacDeviceList.NodeList[mMacDeviceList.CurListLen].PromptId = PromptId;
+ mMacDeviceList.NodeList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
+ } else {
+ mMacDeviceList.MaxListLen += MAX_MAC_ADDRESS_NODE_LIST_LEN;
+ if (mMacDeviceList.CurListLen != 0) {
+ TempDeviceList = (MENU_INFO_ITEM *)AllocateCopyPool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen, (VOID *)mMacDeviceList.NodeList);
+ } else {
+ TempDeviceList = (MENU_INFO_ITEM *)AllocatePool (sizeof (MENU_INFO_ITEM) * mMacDeviceList.MaxListLen);
+ }
+
+ if (TempDeviceList == NULL) {
+ return FALSE;
+ }
+ TempDeviceList[mMacDeviceList.CurListLen].PromptId = PromptId;
+ TempDeviceList[mMacDeviceList.CurListLen].QuestionId = (EFI_QUESTION_ID) (mMacDeviceList.CurListLen + NETWORK_DEVICE_LIST_KEY_OFFSET);
+
+ if (mMacDeviceList.CurListLen > 0) {
+ FreePool(mMacDeviceList.NodeList);
+ }
+
+ mMacDeviceList.NodeList = TempDeviceList;
+ }
+ mMacDeviceList.CurListLen ++;
+
+ return TRUE;
+}
+
+/**
+ Check the devcie path, try to find whether it has mac address path.
+
+ In this function, first need to check whether this path has mac address path.
+ second, when the mac address device path has find, also need to deicide whether
+ need to add this mac address relate info to the menu.
+
+ @param *Node Input device which need to be check.
+ @param *NeedAddItem Whether need to add the menu in the network device list.
+
+ @retval TRUE Has mac address device path.
+ @retval FALSE NOT Has mac address device path.
+
+**/
+BOOLEAN
+IsMacAddressDevicePath (
+ IN VOID *Node,
+ OUT BOOLEAN *NeedAddItem
+ )
+{
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ CHAR16 *Buffer;
+ BOOLEAN ReturnVal;
+
+ ASSERT (Node != NULL);
+ *NeedAddItem = FALSE;
+ ReturnVal = FALSE;
+ Buffer = NULL;
+
+ DevicePath = (EFI_DEVICE_PATH_PROTOCOL *) Node;
+
+ //
+ // find the partition device path node
+ //
+ while (!IsDevicePathEnd (DevicePath)) {
+ if ((DevicePathType (DevicePath) == MESSAGING_DEVICE_PATH) &&
+ (DevicePathSubType (DevicePath) == MSG_MAC_ADDR_DP)) {
+ ReturnVal = TRUE;
+
+ if (DEVICE_MANAGER_FORM_ID == mNextShowFormId) {
+ *NeedAddItem = TRUE;
+ break;
+ }
+
+ if (!GetMacAddressString((MAC_ADDR_DEVICE_PATH*)DevicePath, &Buffer)) {
+ break;
+ }
+
+ if (NETWORK_DEVICE_FORM_ID == mNextShowFormId) {
+ if (StrCmp (Buffer, mSelectedMacAddrString) == 0) {
+ *NeedAddItem = TRUE;
+ }
+ break;
+ }
+
+ if (NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) {
+ //
+ // Same handle may has two network child handle, so the questionid
+ // has the offset of SAME_HANDLE_KEY_OFFSET.
+ //
+ if (AddIdToMacDeviceList (Buffer)) {
+ *NeedAddItem = TRUE;
+ }
+ break;
+ }
+ }
+ DevicePath = NextDevicePathNode (DevicePath);
+ }
+
+ if (Buffer != NULL) {
+ FreePool (Buffer);
+ }
+
+ return ReturnVal;
+}
+
+/**
+ Check to see if the device path is for the network device.
+
+ @param Handle The HII handle which include the mac address device path.
+ @param ItemCount The new add Mac address item count.
+
+ @retval TRUE Need to add new item in the menu.
+ @return FALSE Do not need to add the menu about the network.
+
+**/
+BOOLEAN
+IsNeedAddNetworkMenu (
+ IN EFI_HII_HANDLE Handle,
+ OUT UINTN *ItemCount
+ )
+{
+ EFI_STATUS Status;
+ UINTN EntryCount;
+ UINTN Index;
+ EFI_HANDLE DriverHandle;
+ EFI_HANDLE ControllerHandle;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *TmpDevicePath;
+ EFI_DEVICE_PATH_PROTOCOL *ChildDevicePath;
+ EFI_OPEN_PROTOCOL_INFORMATION_ENTRY *OpenInfoBuffer;
+ BOOLEAN IsNeedAdd;
+
+ IsNeedAdd = FALSE;
+ OpenInfoBuffer = NULL;
+ if ((Handle == NULL) || (ItemCount == NULL)) {
+ return FALSE;
+ }
+ *ItemCount = 0;
+
+ Status = gHiiDatabase->GetPackageListHandle (gHiiDatabase, Handle, &DriverHandle);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ //
+ // Get the device path by the got Driver handle .
+ //
+ Status = gBS->HandleProtocol (DriverHandle, &gEfiDevicePathProtocolGuid, (VOID **) &DevicePath);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+ TmpDevicePath = DevicePath;
+
+ //
+ // Check whether this device path include mac address device path.
+ // If this path has mac address path, get the value whether need
+ // add this info to the menu and return.
+ // Else check more about the child handle devcie path.
+ //
+ if (IsMacAddressDevicePath(TmpDevicePath, &IsNeedAdd)) {
+ if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId) && IsNeedAdd) {
+ (*ItemCount) = 1;
+ }
+ return IsNeedAdd;
+ }
+
+ //
+ // Search whether this path is the controller path, not he child handle path.
+ // And the child handle has the network devcie connected.
+ //
+ TmpDevicePath = DevicePath;
+ Status = gBS->LocateDevicePath(&gEfiDevicePathProtocolGuid, &TmpDevicePath, &ControllerHandle);
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ if (!IsDevicePathEnd (TmpDevicePath)) {
+ return FALSE;
+ }
+
+ //
+ // Retrieve the list of agents that are consuming the specific protocol
+ // on ControllerHandle.
+ // The buffer point by OpenInfoBuffer need be free at this function.
+ //
+ Status = gBS->OpenProtocolInformation (
+ ControllerHandle,
+ &gEfiPciIoProtocolGuid,
+ &OpenInfoBuffer,
+ &EntryCount
+ );
+ if (EFI_ERROR (Status)) {
+ return FALSE;
+ }
+
+ //
+ // Inspect if ChildHandle is one of the agents.
+ //
+ Status = EFI_UNSUPPORTED;
+ for (Index = 0; Index < EntryCount; Index++) {
+ //
+ // Query all the children created by the controller handle's driver
+ //
+ if ((OpenInfoBuffer[Index].Attributes & EFI_OPEN_PROTOCOL_BY_CHILD_CONTROLLER) != 0) {
+ Status = gBS->OpenProtocol (
+ OpenInfoBuffer[Index].ControllerHandle,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &ChildDevicePath,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Check whether this device path include mac address device path.
+ //
+ if (!IsMacAddressDevicePath(ChildDevicePath, &IsNeedAdd)) {
+ //
+ // If this path not has mac address path, check the other.
+ //
+ continue;
+ } else {
+ //
+ // If need to update the NETWORK_DEVICE_LIST_FORM, try to get more.
+ //
+ if ((NETWORK_DEVICE_LIST_FORM_ID == mNextShowFormId)) {
+ if (IsNeedAdd) {
+ (*ItemCount) += 1;
+ }
+ continue;
+ } else {
+ //
+ // If need to update other form, return whether need to add to the menu.
+ //
+ goto Done;
+ }
+ }
+ }
+ }
+
+Done:
+ if (OpenInfoBuffer != NULL) {
+ FreePool (OpenInfoBuffer);
+ }
+ return IsNeedAdd;
+}
+
+/**
+ Get HiiHandle total number.
+
+ @param HiiHandles The input HiiHandle array.
+
+ @retval the Hiihandle count.
+
+**/
+UINTN
+GetHiiHandleCount (
+ IN EFI_HII_HANDLE *HiiHandles
+ )
+{
+ UINTN Index;
+
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ }
+
+ return Index;
+}
+
+/**
+ Insert the new HiiHandle + FormsetGuid at the NewPair[InsertOffset].
+
+ @param HiiHandles The input HiiHandle array.
+ @param GuidLists The input form set guid lists.
+ @param ArrayCount The input array count, new array will be arraycount + 1 size.
+ @param Offset The current used HiiHandle's Offset.
+ @param FormSetGuid The new found formset guid.
+
+**/
+VOID
+AdjustArrayData (
+ IN OUT EFI_HII_HANDLE **HiiHandles,
+ IN OUT EFI_GUID ***GuidLists,
+ IN UINTN ArrayCount,
+ IN UINTN Offset,
+ IN EFI_GUID *FormSetGuid
+ )
+{
+ EFI_HII_HANDLE *NewHiiHandles;
+ EFI_GUID **NewGuidLists;
+
+ //
+ // +2 means include the new HiiHandle and the last empty NULL pointer.
+ //
+ NewHiiHandles = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_HII_HANDLE));
+ ASSERT (NewHiiHandles != NULL);
+
+ CopyMem (NewHiiHandles, *HiiHandles, Offset * sizeof (EFI_HII_HANDLE));
+ NewHiiHandles[Offset] = NewHiiHandles[Offset - 1];
+ CopyMem (NewHiiHandles + Offset + 1, *HiiHandles + Offset, (ArrayCount - Offset) * sizeof (EFI_HII_HANDLE));
+
+ NewGuidLists = AllocateZeroPool ((ArrayCount + 2) * sizeof (EFI_GUID *));
+ ASSERT (NewGuidLists != NULL);
+
+ CopyMem (NewGuidLists, *GuidLists, Offset * sizeof (EFI_GUID *));
+ NewGuidLists[Offset] = FormSetGuid;
+
+ FreePool (*HiiHandles);
+ *HiiHandles = NewHiiHandles;
+ FreePool (*GuidLists);
+ *GuidLists = NewGuidLists;
+}
+
+/**
+ Call the browser and display the device manager to allow user
+ to configure the platform.
+
+ This function create the dynamic content for device manager. It includes
+ section header for all class of devices, one-of opcode to set VBIOS.
+
+ @retval EFI_SUCCESS Operation is successful.
+ @return Other values if failed to clean up the dynamic content from HII
+ database.
+
+**/
+EFI_STATUS
+CallDeviceManager (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_STRING String;
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ EFI_HII_HANDLE *HiiHandles;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_STRING_ID FormSetTitle;
+ EFI_STRING_ID FormSetHelp;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ UINTN NumHandles;
+ EFI_HANDLE *DriverHealthHandles;
+ BOOLEAN AddNetworkMenu;
+ UINTN AddItemCount;
+ UINTN NewStringLen;
+ EFI_STRING NewStringTitle;
+ EFI_GUID **GuidLists;
+ UINTN HandleNum;
+ UINTN SkipCount;
+ EFI_GUID *FormSetGuid;
+
+ GuidLists = NULL;
+ HiiHandles = NULL;
+ Status = EFI_SUCCESS;
+ gCallbackKey = 0;
+ NumHandles = 0;
+ DriverHealthHandles = NULL;
+ AddNetworkMenu = FALSE;
+ AddItemCount = 0;
+ SkipCount = 0;
+ FormSetGuid = NULL;
+
+ //
+ // Connect all prior to entering the platform setup menu.
+ //
+ if (!gConnectAllHappened) {
+ BdsLibConnectAllDriversToAllControllers ();
+ gConnectAllHappened = TRUE;
+ }
+
+ HiiHandle = gDeviceManagerPrivate.HiiHandle;
+ if (HiiHandle == NULL) {
+ //
+ // Publish our HII data.
+ //
+ HiiHandle = HiiAddPackages (
+ &gDeviceManagerFormSetGuid,
+ gDeviceManagerPrivate.DriverHandle,
+ DeviceManagerVfrBin,
+ BdsDxeStrings,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ gDeviceManagerPrivate.HiiHandle = HiiHandle;
+ }
+
+ //
+ // If need show the Network device list form, clear the old save list first.
+ //
+ if ((mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) && (mMacDeviceList.CurListLen > 0)) {
+ mMacDeviceList.CurListLen = 0;
+ }
+
+ //
+ // Update the network device form titile.
+ //
+ if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
+ String = HiiGetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NULL);
+ NewStringLen = StrLen(mSelectedMacAddrString) * 2;
+ NewStringLen += (StrLen(String) + 2) * 2;
+ NewStringTitle = AllocatePool (NewStringLen);
+ UnicodeSPrint (NewStringTitle, NewStringLen, L"%s %s", String, mSelectedMacAddrString);
+ HiiSetString (HiiHandle, STRING_TOKEN (STR_FORM_NETWORK_DEVICE_TITLE), NewStringTitle, NULL);
+ FreePool (String);
+ FreePool (NewStringTitle);
+ }
+
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ //
+ // According to the next show Form id(mNextShowFormId) to decide which form need to update.
+ //
+ StartLabel->Number = (UINT16) (LABEL_FORM_ID_OFFSET + mNextShowFormId);
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Get all the Hii handles
+ //
+ HiiHandles = HiiGetHiiHandles (NULL);
+ ASSERT (HiiHandles != NULL);
+
+ HandleNum = GetHiiHandleCount (HiiHandles);
+ GuidLists = AllocateZeroPool ((HandleNum + 1) * sizeof (EFI_GUID *));
+ ASSERT (GuidLists != NULL);
+
+ //
+ // Search for formset of each class type
+ //
+ for (Index = 0; HiiHandles[Index] != NULL; Index++) {
+ //
+ // The QuestionId in the form which will call the driver form has this asssumption.
+ // QuestionId = Handle Index + NETWORK_DEVICE_LIST_KEY_OFFSET;
+ // Different QuestionId at least has the section of NETWORK_DEVICE_LIST_KEY_OFFSET.
+ //
+ ASSERT(Index < MAX_KEY_SECTION_LEN);
+
+ if (!ExtractDisplayedHiiFormFromHiiHandle (HiiHandles[Index], &gEfiHiiPlatformSetupFormsetGuid, SkipCount, &FormSetTitle, &FormSetHelp, &FormSetGuid)) {
+ SkipCount = 0;
+ continue;
+ }
+
+ //
+ // One HiiHandle has more than one formset can be shown,
+ // Insert a new pair of HiiHandle + Guid to the HiiHandles and GuidLists list.
+ //
+ if (SkipCount > 0) {
+ AdjustArrayData (&HiiHandles, &GuidLists, HandleNum, Index + 1, FormSetGuid);
+ HandleNum ++;
+ Index ++;
+ }
+
+ String = HiiGetString (HiiHandles[Index], FormSetTitle, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
+ ASSERT (String != NULL);
+ }
+ Token = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ String = HiiGetString (HiiHandles[Index], FormSetHelp, NULL);
+ if (String == NULL) {
+ String = HiiGetString (HiiHandle, STR_MISSING_STRING, NULL);
+ ASSERT (String != NULL);
+ }
+ TokenHelp = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ //
+ // Network device process
+ //
+ if (IsNeedAddNetworkMenu (HiiHandles[Index], &AddItemCount)) {
+ if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
+ //
+ // Only show one menu item "Network Config" in the device manger form.
+ //
+ if (!AddNetworkMenu) {
+ AddNetworkMenu = TRUE;
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ INVALID_FORM_ID,
+ STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_TITLE),
+ STRING_TOKEN (STR_FORM_NETWORK_DEVICE_LIST_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ (EFI_QUESTION_ID) QUESTION_NETWORK_DEVICE_ID
+ );
+ }
+ } else if (mNextShowFormId == NETWORK_DEVICE_LIST_FORM_ID) {
+ //
+ // In network device list form, same mac address device only show one menu.
+ //
+ while (AddItemCount > 0) {
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ INVALID_FORM_ID,
+ mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].PromptId,
+ STRING_TOKEN (STR_NETWORK_DEVICE_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ mMacDeviceList.NodeList[mMacDeviceList.CurListLen - AddItemCount].QuestionId
+ );
+ AddItemCount -= 1;
+ }
+ } else if (mNextShowFormId == NETWORK_DEVICE_FORM_ID) {
+ //
+ // In network device form, only the selected mac address device need to be show.
+ //
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ INVALID_FORM_ID,
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
+ );
+ }
+ } else {
+ //
+ //
+ // Not network device process, only need to show at device manger form.
+ //
+ if (mNextShowFormId == DEVICE_MANAGER_FORM_ID) {
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ INVALID_FORM_ID,
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ (EFI_QUESTION_ID) (Index + DEVICE_KEY_OFFSET)
+ );
+ }
+ }
+
+ //
+ // Try to find more formset in this HiiHandle.
+ //
+ SkipCount++;
+ Index--;
+ }
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverHealthProtocolGuid,
+ NULL,
+ &NumHandles,
+ &DriverHealthHandles
+ );
+
+ //
+ // If there are no drivers installed driver health protocol, do not create driver health entry in UI
+ //
+ if (NumHandles != 0) {
+ //
+ // If driver health protocol is installed, create Driver Health subtitle and entry
+ //
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DM_DRIVER_HEALTH_TITLE), 0, 0, 0);
+ HiiCreateGotoOpCode (
+ StartOpCodeHandle,
+ DRIVER_HEALTH_FORM_ID,
+ STRING_TOKEN(STR_DRIVER_HEALTH_ALL_HEALTHY), // Prompt text
+ STRING_TOKEN(STR_DRIVER_HEALTH_STATUS_HELP), // Help text
+ EFI_IFR_FLAG_CALLBACK,
+ DEVICE_MANAGER_KEY_DRIVER_HEALTH // Question ID
+ );
+
+ //
+ // Check All Driver health status
+ //
+ if (!PlaformHealthStatusCheck ()) {
+ //
+ // At least one driver in the platform are not in healthy status
+ //
+ HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_NOT_HEALTH)), NULL);
+ } else {
+ //
+ // For the string of STR_DRIVER_HEALTH_ALL_HEALTHY previously has been updated and we need to update it while re-entry.
+ //
+ HiiSetString (HiiHandle, STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY), GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
+ }
+ }
+
+ HiiUpdateForm (
+ HiiHandle,
+ &gDeviceManagerFormSetGuid,
+ mNextShowFormId,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandle,
+ 1,
+ &gDeviceManagerFormSetGuid,
+ mNextShowFormId,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // We will have returned from processing a callback, selected
+ // a target to display
+ //
+ if ((gCallbackKey >= DEVICE_KEY_OFFSET)) {
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandles[gCallbackKey - DEVICE_KEY_OFFSET],
+ 1,
+ GuidLists[gCallbackKey - DEVICE_KEY_OFFSET],
+ 0,
+ NULL,
+ &ActionRequest
+ );
+
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // Force return to Device Manager
+ //
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ goto Done;
+ }
+
+ //
+ // Driver Health item chose.
+ //
+ if (gCallbackKey == DEVICE_MANAGER_KEY_DRIVER_HEALTH) {
+ CallDriverHealth ();
+ //
+ // Force return to Device Manager
+ //
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ goto Done;
+ }
+
+ //
+ // Enter from device manager and into the network device list.
+ //
+ if (gCallbackKey == QUESTION_NETWORK_DEVICE_ID) {
+ mNextShowFormId = NETWORK_DEVICE_LIST_FORM_ID;
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ goto Done;
+ }
+
+ //
+ // In this case, go from the network device list to the specify device.
+ //
+ if ((gCallbackKey < MAX_KEY_SECTION_LEN + NETWORK_DEVICE_LIST_KEY_OFFSET ) && (gCallbackKey >= NETWORK_DEVICE_LIST_KEY_OFFSET)) {
+ mNextShowFormId = NETWORK_DEVICE_FORM_ID;
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ goto Done;
+ }
+
+ //
+ // Select the ESC, the gCallbackKey == 0.
+ //
+ if(mNextShowFormId - 1 < DEVICE_MANAGER_FORM_ID) {
+ mNextShowFormId = DEVICE_MANAGER_FORM_ID;
+ } else {
+ mNextShowFormId = (UINT16) (mNextShowFormId - 1);
+ gCallbackKey = FRONT_PAGE_KEY_DEVICE_MANAGER;
+ }
+
+Done:
+ //
+ // Remove our packagelist from HII database.
+ //
+ HiiRemovePackages (HiiHandle);
+ gDeviceManagerPrivate.HiiHandle = NULL;
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ FreePool (HiiHandles);
+
+ for (Index = 0; Index < HandleNum; Index++) {
+ if (GuidLists[Index] != NULL) {
+ FreePool (GuidLists[Index]);
+ }
+ }
+ FreePool (GuidLists);
+
+ return Status;
+}
+
+/**
+ This function is invoked if user selected a interactive opcode from Driver Health's
+ Formset. The decision by user is saved to gCallbackKey for later processing.
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverHealthCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ gCallbackKey = QuestionId;
+
+ //
+ // Request to exit SendForm(), so as to switch to selected form
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+
+ return EFI_SUCCESS;
+ }
+
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Collect and display the platform's driver health relative information, allow user to do interactive
+ operation while the platform is unhealthy.
+
+ This function display a form which divided into two parts. The one list all modules which has installed
+ driver health protocol. The list usually contain driver name, controller name, and it's health info.
+ While the driver name can't be retrieved, will use device path as backup. The other part of the form provide
+ a choice to the user to repair all platform.
+
+**/
+VOID
+CallDriverHealth (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_HII_HANDLE HiiHandle;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *StartLabelRepair;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_IFR_GUID_LABEL *EndLabelRepair;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ VOID *StartOpCodeHandleRepair;
+ VOID *EndOpCodeHandleRepair;
+ UINTN Index;
+ EFI_STRING_ID Token;
+ EFI_STRING_ID TokenHelp;
+ EFI_STRING String;
+ EFI_STRING TmpString;
+ EFI_STRING DriverName;
+ EFI_STRING ControllerName;
+ LIST_ENTRY DriverHealthList;
+ DRIVER_HEALTH_INFO *DriverHealthInfo;
+ LIST_ENTRY *Link;
+ EFI_DEVICE_PATH_PROTOCOL *DriverDevicePath;
+ BOOLEAN RebootRequired;
+ BOOLEAN IsControllerNameEmpty;
+ UINTN StringSize;
+
+ Index = 0;
+ DriverHealthInfo = NULL;
+ DriverDevicePath = NULL;
+ IsControllerNameEmpty = FALSE;
+ InitializeListHead (&DriverHealthList);
+
+ HiiHandle = gDeviceManagerPrivate.DriverHealthHiiHandle;
+ if (HiiHandle == NULL) {
+ //
+ // Publish Driver Health HII data.
+ //
+ HiiHandle = HiiAddPackages (
+ &gDeviceManagerFormSetGuid,
+ gDeviceManagerPrivate.DriverHealthHandle,
+ DriverHealthVfrBin,
+ BdsDxeStrings,
+ NULL
+ );
+ if (HiiHandle == NULL) {
+ return;
+ }
+
+ gDeviceManagerPrivate.DriverHealthHiiHandle = HiiHandle;
+ }
+
+ //
+ // Allocate space for creation of UpdateData Buffer
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ StartOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandleRepair != NULL);
+
+ EndOpCodeHandleRepair = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandleRepair != NULL);
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_DRIVER_HEALTH;
+
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_DRIVER_HEALTH_END;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabelRepair = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandleRepair, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabelRepair->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabelRepair->Number = LABEL_DRIVER_HEALTH_REAPIR_ALL_END;
+
+ HiiCreateSubTitleOpCode (StartOpCodeHandle, STRING_TOKEN (STR_DH_STATUS_LIST), 0, 0, 1);
+
+ Status = GetAllControllersHealthStatus (&DriverHealthList);
+ ASSERT (Status != EFI_OUT_OF_RESOURCES);
+
+ Link = GetFirstNode (&DriverHealthList);
+
+ while (!IsNull (&DriverHealthList, Link)) {
+ DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
+
+ Status = DriverHealthGetDriverName (DriverHealthInfo->DriverHandle, &DriverName);
+ if (EFI_ERROR (Status)) {
+ //
+ // Can not get the Driver name, so use the Device path
+ //
+ DriverDevicePath = DevicePathFromHandle (DriverHealthInfo->DriverHandle);
+ DriverName = DevicePathToStr (DriverDevicePath);
+ }
+ StringSize = StrSize (DriverName);
+
+ Status = DriverHealthGetControllerName (
+ DriverHealthInfo->DriverHandle,
+ DriverHealthInfo->ControllerHandle,
+ DriverHealthInfo->ChildHandle,
+ &ControllerName
+ );
+
+ if (!EFI_ERROR (Status)) {
+ IsControllerNameEmpty = FALSE;
+ StringSize += StrLen (L" ") * sizeof(CHAR16);
+ StringSize += StrLen (ControllerName) * sizeof(CHAR16);
+ } else {
+ IsControllerNameEmpty = TRUE;
+ }
+
+ //
+ // Add the message of the Module itself provided after the string item.
+ //
+ if ((DriverHealthInfo->MessageList != NULL) && (DriverHealthInfo->MessageList->StringId != 0)) {
+ TmpString = HiiGetString (
+ DriverHealthInfo->MessageList->HiiHandle,
+ DriverHealthInfo->MessageList->StringId,
+ NULL
+ );
+ ASSERT (TmpString != NULL);
+
+ StringSize += StrLen (L" ") * sizeof(CHAR16);
+ StringSize += StrLen (TmpString) * sizeof(CHAR16);
+
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ ASSERT (String != NULL);
+
+ StrCpyS (String, StringSize / sizeof(CHAR16), DriverName);
+ if (!IsControllerNameEmpty) {
+ StrCatS (String, StringSize / sizeof(CHAR16), L" ");
+ StrCatS (String, StringSize / sizeof(CHAR16), ControllerName);
+ }
+
+ StrCatS (String, StringSize / sizeof(CHAR16), L" ");
+ StrCatS (String, StringSize / sizeof(CHAR16), TmpString);
+
+ } else {
+ //
+ // Update the string will be displayed base on the driver's health status
+ //
+ switch(DriverHealthInfo->HealthStatus) {
+ case EfiDriverHealthStatusRepairRequired:
+ TmpString = GetStringById (STRING_TOKEN (STR_REPAIR_REQUIRED));
+ break;
+ case EfiDriverHealthStatusConfigurationRequired:
+ TmpString = GetStringById (STRING_TOKEN (STR_CONFIGURATION_REQUIRED));
+ break;
+ case EfiDriverHealthStatusFailed:
+ TmpString = GetStringById (STRING_TOKEN (STR_OPERATION_FAILED));
+ break;
+ case EfiDriverHealthStatusReconnectRequired:
+ TmpString = GetStringById (STRING_TOKEN (STR_RECONNECT_REQUIRED));
+ break;
+ case EfiDriverHealthStatusRebootRequired:
+ TmpString = GetStringById (STRING_TOKEN (STR_REBOOT_REQUIRED));
+ break;
+ default:
+ TmpString = GetStringById (STRING_TOKEN (STR_DRIVER_HEALTH_HEALTHY));
+ break;
+ }
+ ASSERT (TmpString != NULL);
+
+ StringSize += StrLen (TmpString) * sizeof(CHAR16);
+
+ String = (EFI_STRING) AllocateZeroPool (StringSize);
+ ASSERT (String != NULL);
+
+ StrCpyS (String, StringSize / sizeof (CHAR16), DriverName);
+ if (!IsControllerNameEmpty) {
+ StrCatS (String, StringSize / sizeof (CHAR16), L" ");
+ StrCatS (String, StringSize / sizeof (CHAR16), ControllerName);
+ }
+
+ StrCatS (String, StringSize / sizeof (CHAR16), TmpString);
+ }
+
+ FreePool (TmpString);
+
+ Token = HiiSetString (HiiHandle, 0, String, NULL);
+ FreePool (String);
+
+ TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_SINGLE_HELP)), NULL);
+
+ HiiCreateActionOpCode (
+ StartOpCodeHandle,
+ (EFI_QUESTION_ID) (Index + DRIVER_HEALTH_KEY_OFFSET),
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ Index++;
+ Link = GetNextNode (&DriverHealthList, Link);
+ }
+
+ //
+ // Add End Opcode for Subtitle
+ //
+ HiiCreateEndOpCode (StartOpCodeHandle);
+
+ HiiCreateSubTitleOpCode (StartOpCodeHandleRepair, STRING_TOKEN (STR_DRIVER_HEALTH_REPAIR_ALL), 0, 0, 1);
+ TokenHelp = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_HELP)), NULL);
+
+ if (PlaformHealthStatusCheck ()) {
+ //
+ // No action need to do for the platform
+ //
+ Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DRIVER_HEALTH_ALL_HEALTHY)), NULL);
+ HiiCreateActionOpCode (
+ StartOpCodeHandleRepair,
+ 0,
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_READ_ONLY,
+ 0
+ );
+ } else {
+ //
+ // Create ActionOpCode only while the platform need to do health related operation.
+ //
+ Token = HiiSetString (HiiHandle, 0, GetStringById( STRING_TOKEN (STR_DH_REPAIR_ALL_TITLE)), NULL);
+ HiiCreateActionOpCode (
+ StartOpCodeHandleRepair,
+ (EFI_QUESTION_ID) DRIVER_HEALTH_REPAIR_ALL_KEY,
+ Token,
+ TokenHelp,
+ EFI_IFR_FLAG_CALLBACK,
+ 0
+ );
+ }
+
+ HiiCreateEndOpCode (StartOpCodeHandleRepair);
+
+ Status = HiiUpdateForm (
+ HiiHandle,
+ &gDriverHealthFormSetGuid,
+ DRIVER_HEALTH_FORM_ID,
+ StartOpCodeHandle,
+ EndOpCodeHandle
+ );
+ ASSERT (Status != EFI_NOT_FOUND);
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+
+ Status = HiiUpdateForm (
+ HiiHandle,
+ &gDriverHealthFormSetGuid,
+ DRIVER_HEALTH_FORM_ID,
+ StartOpCodeHandleRepair,
+ EndOpCodeHandleRepair
+ );
+ ASSERT (Status != EFI_NOT_FOUND);
+ ASSERT (Status != EFI_BUFFER_TOO_SMALL);
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &HiiHandle,
+ 1,
+ &gDriverHealthFormSetGuid,
+ DRIVER_HEALTH_FORM_ID,
+ NULL,
+ &ActionRequest
+ );
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // We will have returned from processing a callback - user either hit ESC to exit, or selected
+ // a target to display.
+ // Process the diver health status states here.
+ //
+ if (gCallbackKey >= DRIVER_HEALTH_KEY_OFFSET && gCallbackKey != DRIVER_HEALTH_REPAIR_ALL_KEY) {
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+
+ Link = GetFirstNode (&DriverHealthList);
+ Index = 0;
+
+ while (!IsNull (&DriverHealthList, Link)) {
+ //
+ // Got the item relative node in the List
+ //
+ if (Index == (gCallbackKey - DRIVER_HEALTH_KEY_OFFSET)) {
+ DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
+ //
+ // Process the driver's healthy status for the specify module
+ //
+ RebootRequired = FALSE;
+ ProcessSingleControllerHealth (
+ DriverHealthInfo->DriverHealth,
+ DriverHealthInfo->ControllerHandle,
+ DriverHealthInfo->ChildHandle,
+ DriverHealthInfo->HealthStatus,
+ &(DriverHealthInfo->MessageList),
+ DriverHealthInfo->HiiHandle,
+ &RebootRequired
+ );
+ if (RebootRequired) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+ break;
+ }
+ Index++;
+ Link = GetNextNode (&DriverHealthList, Link);
+ }
+
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ //
+ // Force return to the form of Driver Health in Device Manager
+ //
+ gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
+ }
+
+ //
+ // Repair the whole platform
+ //
+ if (gCallbackKey == DRIVER_HEALTH_REPAIR_ALL_KEY) {
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+
+ PlatformRepairAll (&DriverHealthList);
+
+ gCallbackKey = DRIVER_HEALTH_RETURN_KEY;
+ }
+
+ //
+ // Remove driver health packagelist from HII database.
+ //
+ HiiRemovePackages (HiiHandle);
+ gDeviceManagerPrivate.DriverHealthHiiHandle = NULL;
+
+ //
+ // Free driver health info list
+ //
+ while (!IsListEmpty (&DriverHealthList)) {
+
+ Link = GetFirstNode(&DriverHealthList);
+ DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
+ RemoveEntryList (Link);
+
+ if (DriverHealthInfo->MessageList != NULL) {
+ FreePool(DriverHealthInfo->MessageList);
+ FreePool (DriverHealthInfo);
+ }
+ }
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (StartOpCodeHandleRepair);
+ HiiFreeOpCodeHandle (EndOpCodeHandleRepair);
+
+ if (gCallbackKey == DRIVER_HEALTH_RETURN_KEY) {
+ //
+ // Force return to Driver Health Form
+ //
+ gCallbackKey = DEVICE_MANAGER_KEY_DRIVER_HEALTH;
+ CallDriverHealth ();
+ }
+}
+
+
+/**
+ Check the Driver Health status of a single controller and try to process it if not healthy.
+
+ This function called by CheckAllControllersHealthStatus () function in order to process a specify
+ contoller's health state.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health information.
+ @param DriverHandle The handle of driver.
+ @param ControllerHandle The class guid specifies which form set will be displayed.
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+ @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
+ @param HealthStatus The health status of the controller.
+
+ @retval EFI_INVALID_PARAMETER HealthStatus or DriverHealth is NULL.
+ @retval HealthStatus The Health status of specify controller.
+ @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
+ @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
+ @retval EFI_SUCCESS The Health related operation has been taken successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSingleControllerHealthStatus (
+ IN OUT LIST_ENTRY *DriverHealthList,
+ IN EFI_HANDLE DriverHandle,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
+ IN EFI_DRIVER_HEALTH_STATUS *HealthStatus
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
+ EFI_HII_HANDLE FormHiiHandle;
+ DRIVER_HEALTH_INFO *DriverHealthInfo;
+
+ if (HealthStatus == NULL) {
+ //
+ // If HealthStatus is NULL, then return EFI_INVALID_PARAMETER
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Assume the HealthStatus is healthy
+ //
+ *HealthStatus = EfiDriverHealthStatusHealthy;
+
+ if (DriverHealth == NULL) {
+ //
+ // If DriverHealth is NULL, then return EFI_INVALID_PARAMETER
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (ControllerHandle == NULL) {
+ //
+ // If ControllerHandle is NULL, the return the cumulative health status of the driver
+ //
+ Status = DriverHealth->GetHealthStatus (DriverHealth, NULL, NULL, HealthStatus, NULL, NULL);
+ if (*HealthStatus == EfiDriverHealthStatusHealthy) {
+ //
+ // Add the driver health related information into the list
+ //
+ DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
+ if (DriverHealthInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
+ DriverHealthInfo->DriverHandle = DriverHandle;
+ DriverHealthInfo->ControllerHandle = NULL;
+ DriverHealthInfo->ChildHandle = NULL;
+ DriverHealthInfo->HiiHandle = NULL;
+ DriverHealthInfo->DriverHealth = DriverHealth;
+ DriverHealthInfo->MessageList = NULL;
+ DriverHealthInfo->HealthStatus = *HealthStatus;
+
+ InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
+ }
+ return Status;
+ }
+
+ MessageList = NULL;
+ FormHiiHandle = NULL;
+
+ //
+ // Collect the health status with the optional HII message list
+ //
+ Status = DriverHealth->GetHealthStatus (DriverHealth, ControllerHandle, ChildHandle, HealthStatus, &MessageList, &FormHiiHandle);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // If the health status could not be retrieved, then return immediately
+ //
+ return Status;
+ }
+
+ //
+ // Add the driver health related information into the list
+ //
+ DriverHealthInfo = AllocateZeroPool (sizeof (DRIVER_HEALTH_INFO));
+ if (DriverHealthInfo == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ DriverHealthInfo->Signature = DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE;
+ DriverHealthInfo->DriverHandle = DriverHandle;
+ DriverHealthInfo->ControllerHandle = ControllerHandle;
+ DriverHealthInfo->ChildHandle = ChildHandle;
+ DriverHealthInfo->HiiHandle = FormHiiHandle;
+ DriverHealthInfo->DriverHealth = DriverHealth;
+ DriverHealthInfo->MessageList = MessageList;
+ DriverHealthInfo->HealthStatus = *HealthStatus;
+
+ InsertTailList (DriverHealthList, &DriverHealthInfo->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Collects all the EFI Driver Health Protocols currently present in the EFI Handle Database,
+ and queries each EFI Driver Health Protocol to determine if one or more of the controllers
+ managed by each EFI Driver Health Protocol instance are not healthy.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health
+ information.
+
+ @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
+ @retval EFI_SUCCESS All the controllers in the platform are healthy.
+ @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
+
+**/
+EFI_STATUS
+GetAllControllersHealthStatus (
+ IN OUT LIST_ENTRY *DriverHealthList
+ )
+{
+ EFI_STATUS Status;
+ UINTN NumHandles;
+ EFI_HANDLE *DriverHealthHandles;
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+ UINTN DriverHealthIndex;
+ EFI_HANDLE *Handles;
+ UINTN HandleCount;
+ UINTN ControllerIndex;
+ UINTN ChildIndex;
+
+ //
+ // Initialize local variables
+ //
+ Handles = NULL;
+ DriverHealthHandles = NULL;
+ NumHandles = 0;
+ HandleCount = 0;
+
+ HealthStatus = EfiDriverHealthStatusHealthy;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverHealthProtocolGuid,
+ NULL,
+ &NumHandles,
+ &DriverHealthHandles
+ );
+
+ if (Status == EFI_NOT_FOUND || NumHandles == 0) {
+ //
+ // If there are no Driver Health Protocols handles, then return EFI_NOT_FOUND
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ if (EFI_ERROR (Status) || DriverHealthHandles == NULL) {
+ //
+ // If the list of Driver Health Protocol handles can not be retrieved, then
+ // return EFI_OUT_OF_RESOURCES
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Check the health status of all controllers in the platform
+ // Start by looping through all the Driver Health Protocol handles in the handle database
+ //
+ for (DriverHealthIndex = 0; DriverHealthIndex < NumHandles; DriverHealthIndex++) {
+ //
+ // Skip NULL Driver Health Protocol handles
+ //
+ if (DriverHealthHandles[DriverHealthIndex] == NULL) {
+ continue;
+ }
+
+ //
+ // Retrieve the Driver Health Protocol from DriverHandle
+ //
+ Status = gBS->HandleProtocol (
+ DriverHealthHandles[DriverHealthIndex],
+ &gEfiDriverHealthProtocolGuid,
+ (VOID **)&DriverHealth
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If the Driver Health Protocol can not be retrieved, then skip to the next
+ // Driver Health Protocol handle
+ //
+ continue;
+ }
+
+ //
+ // Check the health of all the controllers managed by a Driver Health Protocol handle
+ //
+ Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], NULL, NULL, DriverHealth, &HealthStatus);
+
+ //
+ // If Status is an error code, then the health information could not be retrieved, so assume healthy
+ // and skip to the next Driver Health Protocol handle
+ //
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // If all the controllers managed by this Driver Health Protocol are healthy, then skip to the next
+ // Driver Health Protocol handle
+ //
+ if (HealthStatus == EfiDriverHealthStatusHealthy) {
+ continue;
+ }
+
+ //
+ // See if the list of all handles in the handle database has been retrieved
+ //
+ //
+ if (Handles == NULL) {
+ //
+ // Retrieve the list of all handles from the handle database
+ //
+ Status = gBS->LocateHandleBuffer (
+ AllHandles,
+ NULL,
+ NULL,
+ &HandleCount,
+ &Handles
+ );
+ if (EFI_ERROR (Status) || Handles == NULL) {
+ //
+ // If all the handles in the handle database can not be retrieved, then
+ // return EFI_OUT_OF_RESOURCES
+ //
+ Status = EFI_OUT_OF_RESOURCES;
+ goto Done;
+ }
+ }
+ //
+ // Loop through all the controller handles in the handle database
+ //
+ for (ControllerIndex = 0; ControllerIndex < HandleCount; ControllerIndex++) {
+ //
+ // Skip NULL controller handles
+ //
+ if (Handles[ControllerIndex] == NULL) {
+ continue;
+ }
+
+ Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], NULL, DriverHealth, &HealthStatus);
+ if (EFI_ERROR (Status)) {
+ //
+ // If Status is an error code, then the health information could not be retrieved, so assume healthy
+ //
+ HealthStatus = EfiDriverHealthStatusHealthy;
+ }
+
+ //
+ // If CheckHealthSingleController() returned an error on a terminal state, then do not check the health of child controllers
+ //
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ //
+ // Loop through all the child handles in the handle database
+ //
+ for (ChildIndex = 0; ChildIndex < HandleCount; ChildIndex++) {
+ //
+ // Skip NULL child handles
+ //
+ if (Handles[ChildIndex] == NULL) {
+ continue;
+ }
+
+ Status = GetSingleControllerHealthStatus (DriverHealthList, DriverHealthHandles[DriverHealthIndex], Handles[ControllerIndex], Handles[ChildIndex], DriverHealth, &HealthStatus);
+ if (EFI_ERROR (Status)) {
+ //
+ // If Status is an error code, then the health information could not be retrieved, so assume healthy
+ //
+ HealthStatus = EfiDriverHealthStatusHealthy;
+ }
+
+ //
+ // If CheckHealthSingleController() returned an error on a terminal state, then skip to the next child
+ //
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ }
+ }
+ }
+
+ Status = EFI_SUCCESS;
+
+Done:
+ if (Handles != NULL) {
+ gBS->FreePool (Handles);
+ }
+ if (DriverHealthHandles != NULL) {
+ gBS->FreePool (DriverHealthHandles);
+ }
+
+ return Status;
+}
+
+
+/**
+ Check the healthy status of the platform, this function will return immediately while found one driver
+ in the platform are not healthy.
+
+ @retval FALSE at least one driver in the platform are not healthy.
+ @retval TRUE No controller install Driver Health Protocol,
+ or all controllers in the platform are in healthy status.
+**/
+BOOLEAN
+PlaformHealthStatusCheck (
+ VOID
+ )
+{
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN NoHandles;
+ EFI_HANDLE *DriverHealthHandles;
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+ BOOLEAN AllHealthy;
+
+ //
+ // Initialize local variables
+ //
+ DriverHealthHandles = NULL;
+ DriverHealth = NULL;
+
+ HealthStatus = EfiDriverHealthStatusHealthy;
+
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiDriverHealthProtocolGuid,
+ NULL,
+ &NoHandles,
+ &DriverHealthHandles
+ );
+ //
+ // There are no handles match the search for Driver Health Protocol has been installed.
+ //
+ if (Status == EFI_NOT_FOUND) {
+ return TRUE;
+ }
+ //
+ // Assume all modules are healthy.
+ //
+ AllHealthy = TRUE;
+
+ //
+ // Found one or more Handles.
+ //
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < NoHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ DriverHealthHandles[Index],
+ &gEfiDriverHealthProtocolGuid,
+ (VOID **) &DriverHealth
+ );
+ if (!EFI_ERROR (Status)) {
+ Status = DriverHealth->GetHealthStatus (
+ DriverHealth,
+ NULL,
+ NULL,
+ &HealthStatus,
+ NULL,
+ NULL
+ );
+ }
+ //
+ // Get the healthy status of the module
+ //
+ if (!EFI_ERROR (Status)) {
+ if (HealthStatus != EfiDriverHealthStatusHealthy) {
+ //
+ // Return immediately one driver's status not in healthy.
+ //
+ return FALSE;
+ }
+ }
+ }
+ }
+ return AllHealthy;
+}
+
+/**
+ Processes a single controller using the EFI Driver Health Protocol associated with
+ that controller. This algorithm continues to query the GetHealthStatus() service until
+ one of the legal terminal states of the EFI Driver Health Protocol is reached. This may
+ require the processing of HII Messages, HII Form, and invocation of repair operations.
+
+ @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
+ @param ControllerHandle The class guid specifies which form set will be displayed.
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+ @param HealthStatus The health status of the controller.
+ @param MessageList An array of warning or error messages associated
+ with the controller specified by ControllerHandle and
+ ChildHandle. This is an optional parameter that may be NULL.
+ @param FormHiiHandle The HII handle for an HII form associated with the
+ controller specified by ControllerHandle and ChildHandle.
+ @param RebootRequired Indicate whether a reboot is required to repair the controller.
+**/
+VOID
+ProcessSingleControllerHealth (
+ IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN EFI_DRIVER_HEALTH_STATUS HealthStatus,
+ IN EFI_DRIVER_HEALTH_HII_MESSAGE **MessageList, OPTIONAL
+ IN EFI_HII_HANDLE FormHiiHandle,
+ IN OUT BOOLEAN *RebootRequired
+ )
+{
+ EFI_STATUS Status;
+ EFI_DRIVER_HEALTH_STATUS LocalHealthStatus;
+
+ LocalHealthStatus = HealthStatus;
+ //
+ // If the module need to be repaired or reconfiguration, will process it until
+ // reach a terminal status. The status from EfiDriverHealthStatusRepairRequired after repair
+ // will be in (Health, Failed, Configuration Required).
+ //
+ while(LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired ||
+ LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
+
+ if (LocalHealthStatus == EfiDriverHealthStatusRepairRequired) {
+ Status = DriverHealth->Repair (
+ DriverHealth,
+ ControllerHandle,
+ ChildHandle,
+ RepairNotify
+ );
+ }
+ //
+ // Via a form of the driver need to do configuration provided to process of status in
+ // EfiDriverHealthStatusConfigurationRequired. The status after configuration should be in
+ // (Healthy, Reboot Required, Failed, Reconnect Required, Repair Required).
+ //
+ if (LocalHealthStatus == EfiDriverHealthStatusConfigurationRequired) {
+ if (FormHiiHandle != NULL) {
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &FormHiiHandle,
+ 1,
+ &gEfiHiiDriverHealthFormsetGuid,
+ 0,
+ NULL,
+ NULL
+ );
+ ASSERT( !EFI_ERROR (Status));
+ } else {
+ //
+ // Exit the loop in case no FormHiiHandle is supplied to prevent dead-loop
+ //
+ break;
+ }
+ }
+
+ Status = DriverHealth->GetHealthStatus (
+ DriverHealth,
+ ControllerHandle,
+ ChildHandle,
+ &LocalHealthStatus,
+ NULL,
+ &FormHiiHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (*MessageList != NULL) {
+ ProcessMessages (*MessageList);
+ }
+ }
+
+ //
+ // Health status in {Healthy, Failed} may also have Messages need to process
+ //
+ if (LocalHealthStatus == EfiDriverHealthStatusHealthy || LocalHealthStatus == EfiDriverHealthStatusFailed) {
+ if (*MessageList != NULL) {
+ ProcessMessages (*MessageList);
+ }
+ }
+ //
+ // Check for RebootRequired or ReconnectRequired
+ //
+ if (LocalHealthStatus == EfiDriverHealthStatusRebootRequired) {
+ *RebootRequired = TRUE;
+ }
+
+ //
+ // Do reconnect if need.
+ //
+ if (LocalHealthStatus == EfiDriverHealthStatusReconnectRequired) {
+ Status = gBS->DisconnectController (ControllerHandle, NULL, NULL);
+ if (EFI_ERROR (Status)) {
+ //
+ // Disconnect failed. Need to promote reconnect to a reboot.
+ //
+ *RebootRequired = TRUE;
+ } else {
+ gBS->ConnectController (ControllerHandle, NULL, NULL, TRUE);
+ }
+ }
+}
+
+
+/**
+ Reports the progress of a repair operation.
+
+ @param[in] Value A value between 0 and Limit that identifies the current
+ progress of the repair operation.
+
+ @param[in] Limit The maximum value of Value for the current repair operation.
+ For example, a driver that wants to specify progress in
+ percent would use a Limit value of 100.
+
+ @retval EFI_SUCCESS The progress of a repair operation is reported successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+RepairNotify (
+ IN UINTN Value,
+ IN UINTN Limit
+ )
+{
+ UINTN Percent;
+
+ if (Limit == 0) {
+ Print(L"Repair Progress Undefined\n\r");
+ } else {
+ Percent = Value * 100 / Limit;
+ Print(L"Repair Progress = %3d%%\n\r", Percent);
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Processes a set of messages returned by the GetHealthStatus ()
+ service of the EFI Driver Health Protocol
+
+ @param MessageList The MessageList point to messages need to processed.
+
+**/
+VOID
+ProcessMessages (
+ IN EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList
+ )
+{
+ UINTN MessageIndex;
+ EFI_STRING MessageString;
+
+ for (MessageIndex = 0;
+ MessageList[MessageIndex].HiiHandle != NULL;
+ MessageIndex++) {
+
+ MessageString = HiiGetString (
+ MessageList[MessageIndex].HiiHandle,
+ MessageList[MessageIndex].StringId,
+ NULL
+ );
+ if (MessageString != NULL) {
+ //
+ // User can customize the output. Just simply print out the MessageString like below.
+ // Also can use the HiiHandle to display message on the front page.
+ //
+ // Print(L"%s\n",MessageString);
+ // gBS->Stall (100000);
+ }
+ }
+
+}
+
+/**
+ Repair the whole platform.
+
+ This function is the main entry for user choose "Repair All" in the front page.
+ It will try to do recovery job till all the driver health protocol installed modules
+ reach a terminal state.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health
+ information.
+
+**/
+VOID
+PlatformRepairAll (
+ IN LIST_ENTRY *DriverHealthList
+ )
+{
+ DRIVER_HEALTH_INFO *DriverHealthInfo;
+ LIST_ENTRY *Link;
+ BOOLEAN RebootRequired;
+
+ ASSERT (DriverHealthList != NULL);
+
+ RebootRequired = FALSE;
+
+ for ( Link = GetFirstNode (DriverHealthList)
+ ; !IsNull (DriverHealthList, Link)
+ ; Link = GetNextNode (DriverHealthList, Link)
+ ) {
+ DriverHealthInfo = DEVICE_MANAGER_HEALTH_INFO_FROM_LINK (Link);
+ //
+ // Do driver health status operation by each link node
+ //
+ ASSERT (DriverHealthInfo != NULL);
+
+ ProcessSingleControllerHealth (
+ DriverHealthInfo->DriverHealth,
+ DriverHealthInfo->ControllerHandle,
+ DriverHealthInfo->ChildHandle,
+ DriverHealthInfo->HealthStatus,
+ &(DriverHealthInfo->MessageList),
+ DriverHealthInfo->HiiHandle,
+ &RebootRequired
+ );
+ }
+
+ if (RebootRequired) {
+ gRT->ResetSystem (EfiResetWarm, EFI_SUCCESS, 0, NULL);
+ }
+}
+
+/**
+
+ Select the best matching language according to front page policy for best user experience.
+
+ This function supports both ISO 639-2 and RFC 4646 language codes, but language
+ code types may not be mixed in a single call to this function.
+
+ @param SupportedLanguages A pointer to a Null-terminated ASCII string that
+ contains a set of language codes in the format
+ specified by Iso639Language.
+ @param Iso639Language If TRUE, then all language codes are assumed to be
+ in ISO 639-2 format. If FALSE, then all language
+ codes are assumed to be in RFC 4646 language format.
+
+ @retval NULL The best matching language could not be found in SupportedLanguages.
+ @retval NULL There are not enough resources available to return the best matching
+ language.
+ @retval Other A pointer to a Null-terminated ASCII string that is the best matching
+ language in SupportedLanguages.
+**/
+CHAR8 *
+DriverHealthSelectBestLanguage (
+ IN CHAR8 *SupportedLanguages,
+ IN BOOLEAN Iso639Language
+ )
+{
+ CHAR8 *LanguageVariable;
+ CHAR8 *BestLanguage;
+
+ GetEfiGlobalVariable2 (Iso639Language ? L"Lang" : L"PlatformLang", (VOID**)&LanguageVariable, NULL);
+
+ BestLanguage = GetBestLanguage(
+ SupportedLanguages,
+ Iso639Language,
+ (LanguageVariable != NULL) ? LanguageVariable : "",
+ Iso639Language ? "eng" : "en-US",
+ NULL
+ );
+ if (LanguageVariable != NULL) {
+ FreePool (LanguageVariable);
+ }
+
+ return BestLanguage;
+}
+
+
+
+/**
+
+ This is an internal worker function to get the Component Name (2) protocol interface
+ and the language it supports.
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ComponentName A pointer to the Component Name (2) protocol interface.
+ @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the
+ located Component Name (2) instance.
+
+ @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find
+ the best matching language it support.
+ @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol.
+ @retval Other Some error occurs when locating Component Name (2) protocol instance or finding
+ the supported language.
+
+**/
+EFI_STATUS
+GetComponentNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
+ OUT CHAR8 **SupportedLanguage
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Locate Component Name (2) protocol on the driver binging handle.
+ //
+ Status = gBS->OpenProtocol (
+ DriverBindingHandle,
+ ProtocolGuid,
+ (VOID **) ComponentName,
+ NULL,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Apply shell policy to select the best language.
+ //
+ *SupportedLanguage = DriverHealthSelectBestLanguage (
+ (*ComponentName)->SupportedLanguages,
+ (BOOLEAN) (ProtocolGuid == &gEfiComponentNameProtocolGuid)
+ );
+ if (*SupportedLanguage == NULL) {
+ Status = EFI_UNSUPPORTED;
+ }
+
+ return Status;
+}
+
+/**
+
+ This is an internal worker function to get driver name from Component Name (2) protocol interface.
+
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
+ of the driver specified by This.
+
+ @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The driver name cannot be retrieved from Component Name (2) protocol
+ interface.
+
+**/
+EFI_STATUS
+GetDriverNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT CHAR16 **DriverName
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BestLanguage;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+
+ //
+ // Retrieve Component Name (2) protocol instance on the driver binding handle and
+ // find the best language this instance supports.
+ //
+ Status = GetComponentNameWorker (
+ ProtocolGuid,
+ DriverBindingHandle,
+ &ComponentName,
+ &BestLanguage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the driver name from Component Name (2) protocol instance on the driver binging handle.
+ //
+ Status = ComponentName->GetDriverName (
+ ComponentName,
+ BestLanguage,
+ DriverName
+ );
+ FreePool (BestLanguage);
+
+ return Status;
+}
+
+/**
+
+ This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
+ If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
+ of the driver specified by This.
+
+ @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The driver name cannot be retrieved from Component Name (2) protocol
+ interface.
+
+**/
+EFI_STATUS
+DriverHealthGetDriverName (
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT CHAR16 **DriverName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Get driver name from UEFI 2.0 Component Name 2 protocol interface.
+ //
+ Status = GetDriverNameWorker (&gEfiComponentName2ProtocolGuid, DriverBindingHandle, DriverName);
+ if (EFI_ERROR (Status)) {
+ //
+ // If it fails to get the driver name from Component Name protocol interface, we should fall back on
+ // EFI 1.1 Component Name protocol interface.
+ //
+ Status = GetDriverNameWorker (&gEfiComponentNameProtocolGuid, DriverBindingHandle, DriverName);
+ }
+
+ return Status;
+}
+
+
+
+/**
+ This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
+ If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by This is managing.
+ This handle specifies the controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name of. This is an
+ optional parameter that may be NULL. It will be NULL for device drivers.
+ It will also be NULL for bus drivers that attempt to retrieve the name
+ of the bus controller. It will not be NULL for a bus driver that attempts
+ to retrieve the name of a child controller.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode string
+ is the name of the controller specified by ControllerHandle and ChildHandle.
+
+ @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
+
+**/
+EFI_STATUS
+GetControllerNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *BestLanguage;
+ EFI_COMPONENT_NAME_PROTOCOL *ComponentName;
+
+ //
+ // Retrieve Component Name (2) protocol instance on the driver binding handle and
+ // find the best language this instance supports.
+ //
+ Status = GetComponentNameWorker (
+ ProtocolGuid,
+ DriverBindingHandle,
+ &ComponentName,
+ &BestLanguage
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Get the controller name from Component Name (2) protocol instance on the driver binging handle.
+ //
+ Status = ComponentName->GetControllerName (
+ ComponentName,
+ ControllerHandle,
+ ChildHandle,
+ BestLanguage,
+ ControllerName
+ );
+ FreePool (BestLanguage);
+
+ return Status;
+}
+
+/**
+
+ This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
+ If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by This is managing.
+ This handle specifies the controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name of. This is an
+ optional parameter that may be NULL. It will be NULL for device drivers.
+ It will also be NULL for bus drivers that attempt to retrieve the name
+ of the bus controller. It will not be NULL for a bus driver that attempts
+ to retrieve the name of a child controller.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode string
+ is the name of the controller specified by ControllerHandle and ChildHandle.
+
+ @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
+
+**/
+EFI_STATUS
+DriverHealthGetControllerName (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ OUT CHAR16 **ControllerName
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Get controller name from UEFI 2.0 Component Name 2 protocol interface.
+ //
+ Status = GetControllerNameWorker (
+ &gEfiComponentName2ProtocolGuid,
+ DriverBindingHandle,
+ ControllerHandle,
+ ChildHandle,
+ ControllerName
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If it fails to get the controller name from Component Name protocol interface, we should fall back on
+ // EFI 1.1 Component Name protocol interface.
+ //
+ Status = GetControllerNameWorker (
+ &gEfiComponentNameProtocolGuid,
+ DriverBindingHandle,
+ ControllerHandle,
+ ChildHandle,
+ ControllerName
+ );
+ }
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h
new file mode 100644
index 0000000000..95bde8de5a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManager.h
@@ -0,0 +1,523 @@
+/** @file
+ The platform device manager reference implement
+
+Copyright (c) 2004 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DEVICE_MANAGER_H_
+#define _DEVICE_MANAGER_H_
+
+#include "Bds.h"
+#include "FrontPage.h"
+#include "DeviceManagerVfr.h"
+#include <Protocol/PciIo.h>
+
+#define DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('D', 'M', 'C', 'B')
+#define DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE SIGNATURE_32 ('D', 'M', 'D', 'H')
+
+
+typedef struct {
+ UINTN Signature;
+
+ ///
+ /// Device Manager HII relative handles
+ ///
+ EFI_HII_HANDLE HiiHandle;
+
+ ///
+ /// Driver Health HII relative handles
+ ///
+ EFI_HII_HANDLE DriverHealthHiiHandle;
+
+ EFI_HANDLE DriverHandle;
+ EFI_HANDLE DriverHealthHandle;
+
+ ///
+ /// Device Manager Produced protocols
+ ///
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+
+ ///
+ /// Driver Health Produced protocols
+ ///
+ EFI_HII_CONFIG_ACCESS_PROTOCOL DriverHealthConfigAccess;
+
+ ///
+ /// Configuration data
+ ///
+ UINT8 VideoBios;
+} DEVICE_MANAGER_CALLBACK_DATA;
+
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ ///
+ /// HII relative handles
+ ///
+ EFI_HII_HANDLE HiiHandle;
+
+ ///
+ /// Driver relative handles
+ ///
+ EFI_HANDLE DriverHandle;
+ EFI_HANDLE ControllerHandle;
+ EFI_HANDLE ChildHandle;
+
+ EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth;
+ ///
+ /// Driver health messages of the specify Driver
+ ///
+ EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList;
+
+ ///
+ /// Driver Health status
+ ///
+ EFI_DRIVER_HEALTH_STATUS HealthStatus;
+} DRIVER_HEALTH_INFO;
+
+typedef struct {
+ EFI_STRING_ID PromptId;
+ EFI_QUESTION_ID QuestionId;
+}MENU_INFO_ITEM;
+
+typedef struct {
+ UINTN CurListLen;
+ UINTN MaxListLen;
+ MENU_INFO_ITEM *NodeList;
+} MAC_ADDRESS_NODE_LIST;
+
+#define DEVICE_MANAGER_HEALTH_INFO_FROM_LINK(a) \
+ CR (a, \
+ DRIVER_HEALTH_INFO, \
+ Link, \
+ DEVICE_MANAGER_DRIVER_HEALTH_INFO_SIGNATURE \
+ )
+
+#define DEVICE_MANAGER_CALLBACK_DATA_FROM_THIS(a) \
+ CR (a, \
+ DEVICE_MANAGER_CALLBACK_DATA, \
+ ConfigAccess, \
+ DEVICE_MANAGER_CALLBACK_DATA_SIGNATURE \
+ )
+typedef struct {
+ EFI_STRING_ID StringId;
+ UINT16 Class;
+} DEVICE_MANAGER_MENU_ITEM;
+
+/**
+ This function is invoked if user selected a interactive opcode from Device Manager's
+ Formset. The decision by user is saved to gCallbackKey for later processing. If
+ user set VBIOS, the new value is saved to EFI variable.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+DeviceManagerCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+/**
+ This function is invoked if user selected a interactive opcode from Driver Health's
+ Formset. The decision by user is saved to gCallbackKey for later processing.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_INVALID_PARAMETER The setup browser call this function with invalid parameters.
+
+**/
+EFI_STATUS
+EFIAPI
+DriverHealthCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+
+/**
+
+ This function registers HII packages to HII database.
+
+ @retval EFI_SUCCESS HII packages for the Device Manager were registered successfully.
+ @retval EFI_OUT_OF_RESOURCES HII packages for the Device Manager failed to be registered.
+
+**/
+EFI_STATUS
+InitializeDeviceManager (
+ VOID
+ );
+
+/**
+
+ Call the browser and display the device manager to allow user
+ to configure the platform.
+
+ This function create the dynamic content for device manager. It includes
+ section header for all class of devices, one-of opcode to set VBIOS.
+
+ @retval EFI_SUCCESS Operation is successful.
+ @retval Other values if failed to clean up the dynamic content from HII
+ database.
+
+**/
+EFI_STATUS
+CallDeviceManager (
+ VOID
+ );
+
+
+/**
+ Check the Driver Health status of a single controller and try to process it if not healthy.
+
+ This function called by CheckAllControllersHealthStatus () function in order to process a specify
+ contoller's health state.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health information.
+ @param DriverHandle The handle of driver.
+ @param ControllerHandle The class guid specifies which form set will be displayed.
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+ @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
+ @param HealthStatus The health status of the controller.
+
+ @retval EFI_INVALID_PARAMETER HealthStatus or DriverHealth is NULL.
+ @retval HealthStatus The Health status of specify controller.
+ @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
+ @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
+ @retval EFI_SUCCESS The Health related operation has been taken successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSingleControllerHealthStatus (
+ IN OUT LIST_ENTRY *DriverHealthList,
+ IN EFI_HANDLE DriverHandle,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
+ IN EFI_DRIVER_HEALTH_STATUS *HealthStatus
+ );
+
+/**
+ Collects all the EFI Driver Health Protocols currently present in the EFI Handle Database,
+ and queries each EFI Driver Health Protocol to determine if one or more of the controllers
+ managed by each EFI Driver Health Protocol instance are not healthy.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health
+ information.
+
+ @retval EFI_NOT_FOUND No controller in the platform install Driver Health Protocol.
+ @retval EFI_SUCCESS All the controllers in the platform are healthy.
+ @retval EFI_OUT_OF_RESOURCES The list of Driver Health Protocol handles can not be retrieved.
+
+**/
+EFI_STATUS
+GetAllControllersHealthStatus (
+ IN OUT LIST_ENTRY *DriverHealthList
+ );
+
+/**
+ Check the healthy status of the platform, this function will return immediately while found one driver
+ in the platform are not healthy.
+
+ @retval FALSE at least one driver in the platform are not healthy.
+ @retval TRUE No controller install Driver Health Protocol,
+ or all controllers in the platform are in healthy status.
+**/
+BOOLEAN
+PlaformHealthStatusCheck (
+ VOID
+ );
+
+/**
+ Repair the whole platform.
+
+ This function is the main entry for user choose "Repair All" in the front page.
+ It will try to do recovery job till all the driver health protocol installed modules
+ reach a terminal state.
+
+ @param DriverHealthList A Pointer to the list contain all of the platform driver health
+ information.
+
+**/
+VOID
+PlatformRepairAll (
+ IN LIST_ENTRY *DriverHealthList
+ );
+
+/**
+ Processes a single controller using the EFI Driver Health Protocol associated with
+ that controller. This algorithm continues to query the GetHealthStatus() service until
+ one of the legal terminal states of the EFI Driver Health Protocol is reached. This may
+ require the processing of HII Messages, HII Form, and invocation of repair operations.
+
+ @param DriverHealth A pointer to the EFI_DRIVER_HEALTH_PROTOCOL instance.
+ @param ControllerHandle The class guid specifies which form set will be displayed.
+ @param ChildHandle The handle of the child controller to retrieve the health
+ status on. This is an optional parameter that may be NULL.
+ @param HealthStatus The health status of the controller.
+ @param MessageList An array of warning or error messages associated
+ with the controller specified by ControllerHandle and
+ ChildHandle. This is an optional parameter that may be NULL.
+ @param FormHiiHandle The HII handle for an HII form associated with the
+ controller specified by ControllerHandle and ChildHandle.
+ @param RebootRequired Indicate whether a reboot is required to repair the controller.
+**/
+VOID
+ProcessSingleControllerHealth (
+ IN EFI_DRIVER_HEALTH_PROTOCOL *DriverHealth,
+ IN EFI_HANDLE ControllerHandle, OPTIONAL
+ IN EFI_HANDLE ChildHandle, OPTIONAL
+ IN EFI_DRIVER_HEALTH_STATUS HealthStatus,
+ IN EFI_DRIVER_HEALTH_HII_MESSAGE **MessageList, OPTIONAL
+ IN EFI_HII_HANDLE FormHiiHandle,
+ IN OUT BOOLEAN *RebootRequired
+ );
+
+/**
+ Reports the progress of a repair operation.
+
+ @param[in] Value A value between 0 and Limit that identifies the current
+ progress of the repair operation.
+
+ @param[in] Limit The maximum value of Value for the current repair operation.
+ For example, a driver that wants to specify progress in
+ percent would use a Limit value of 100.
+
+ @retval EFI_SUCCESS The progress of a repair operation is reported successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+RepairNotify (
+ IN UINTN Value,
+ IN UINTN Limit
+ );
+
+/**
+ Processes a set of messages returned by the GetHealthStatus ()
+ service of the EFI Driver Health Protocol
+
+ @param MessageList The MessageList point to messages need to processed.
+
+**/
+VOID
+ProcessMessages (
+ IN EFI_DRIVER_HEALTH_HII_MESSAGE *MessageList
+ );
+
+
+/**
+ Collect and display the platform's driver health relative information, allow user to do interactive
+ operation while the platform is unhealthy.
+
+ This function display a form which divided into two parts. The one list all modules which has installed
+ driver health protocol. The list usually contain driver name, controller name, and it's health info.
+ While the driver name can't be retrieved, will use device path as backup. The other part of the form provide
+ a choice to the user to repair all platform.
+
+**/
+VOID
+CallDriverHealth (
+ VOID
+ );
+
+/**
+
+ Select the best matching language according to front page policy for best user experience.
+
+ This function supports both ISO 639-2 and RFC 4646 language codes, but language
+ code types may not be mixed in a single call to this function.
+
+ @param SupportedLanguages A pointer to a Null-terminated ASCII string that
+ contains a set of language codes in the format
+ specified by Iso639Language.
+ @param Iso639Language If TRUE, then all language codes are assumed to be
+ in ISO 639-2 format. If FALSE, then all language
+ codes are assumed to be in RFC 4646 language format.
+
+ @retval NULL The best matching language could not be found in SupportedLanguages.
+ @retval NULL There are not enough resources available to return the best matching
+ language.
+ @retval Other A pointer to a Null-terminated ASCII string that is the best matching
+ language in SupportedLanguages.
+**/
+CHAR8 *
+DriverHealthSelectBestLanguage (
+ IN CHAR8 *SupportedLanguages,
+ IN BOOLEAN Iso639Language
+ );
+
+/**
+
+ This is an internal worker function to get the Component Name (2) protocol interface
+ and the language it supports.
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ComponentName A pointer to the Component Name (2) protocol interface.
+ @param SupportedLanguage The best suitable language that matches the SupportedLangues interface for the
+ located Component Name (2) instance.
+
+ @retval EFI_SUCCESS The Component Name (2) protocol instance is successfully located and we find
+ the best matching language it support.
+ @retval EFI_UNSUPPORTED The input Language is not supported by the Component Name (2) protocol.
+ @retval Other Some error occurs when locating Component Name (2) protocol instance or finding
+ the supported language.
+
+**/
+EFI_STATUS
+GetComponentNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT EFI_COMPONENT_NAME_PROTOCOL **ComponentName,
+ OUT CHAR8 **SupportedLanguage
+ );
+
+/**
+
+ This is an internal worker function to get driver name from Component Name (2) protocol interface.
+
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
+ of the driver specified by This.
+
+ @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The driver name cannot be retrieved from Component Name (2) protocol
+ interface.
+
+**/
+EFI_STATUS
+GetDriverNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+
+ This function gets driver name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the driver name.
+ If the attempt fails, it then gets the driver name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param DriverName A pointer to the Unicode string to return. This Unicode string is the name
+ of the driver specified by This.
+
+ @retval EFI_SUCCESS The driver name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The driver name cannot be retrieved from Component Name (2) protocol
+ interface.
+
+**/
+EFI_STATUS
+DriverHealthGetDriverName (
+ IN EFI_HANDLE DriverBindingHandle,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
+ If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param ProtocolGuid A pointer to an EFI_GUID. It points to Component Name (2) protocol GUID.
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by This is managing.
+ This handle specifies the controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name of. This is an
+ optional parameter that may be NULL. It will be NULL for device drivers.
+ It will also be NULL for bus drivers that attempt to retrieve the name
+ of the bus controller. It will not be NULL for a bus driver that attempts
+ to retrieve the name of a child controller.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode string
+ is the name of the controller specified by ControllerHandle and ChildHandle.
+
+ @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
+
+**/
+EFI_STATUS
+GetControllerNameWorker (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ OUT CHAR16 **ControllerName
+ );
+
+/**
+ This function gets controller name from Component Name 2 protocol interface and Component Name protocol interface
+ in turn. It first tries UEFI 2.0 Component Name 2 protocol interface and try to get the controller name.
+ If the attempt fails, it then gets the controller name from EFI 1.1 Component Name protocol for backward
+ compatibility support.
+
+ @param DriverBindingHandle The handle on which the Component Name (2) protocol instance is retrieved.
+ @param ControllerHandle The handle of a controller that the driver specified by This is managing.
+ This handle specifies the controller whose name is to be returned.
+ @param ChildHandle The handle of the child controller to retrieve the name of. This is an
+ optional parameter that may be NULL. It will be NULL for device drivers.
+ It will also be NULL for bus drivers that attempt to retrieve the name
+ of the bus controller. It will not be NULL for a bus driver that attempts
+ to retrieve the name of a child controller.
+ @param ControllerName A pointer to the Unicode string to return. This Unicode string
+ is the name of the controller specified by ControllerHandle and ChildHandle.
+
+ @retval EFI_SUCCESS The controller name is successfully retrieved from Component Name (2) protocol
+ interface.
+ @retval Other The controller name cannot be retrieved from Component Name (2) protocol.
+
+**/
+EFI_STATUS
+DriverHealthGetControllerName (
+ IN EFI_HANDLE DriverBindingHandle,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle,
+ OUT CHAR16 **ControllerName
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni
new file mode 100644
index 0000000000..1553f10bf9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr
new file mode 100644
index 0000000000..0ad671bdca
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.Vfr
@@ -0,0 +1,93 @@
+///** @file
+//
+// Device Manager formset.
+//
+// Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include "DeviceManagerVfr.h"
+
+#define EFI_DISK_DEVICE_CLASS 0x0001
+#define EFI_VIDEO_DEVICE_CLASS 0x0002
+#define EFI_NETWORK_DEVICE_CLASS 0x0004
+#define EFI_INPUT_DEVICE_CLASS 0x0008
+#define EFI_ON_BOARD_DEVICE_CLASS 0x0010
+#define EFI_OTHER_DEVICE_CLASS 0x0020
+
+#define DEVICE_MANAGER_CLASS 0x0000
+#define FRONT_PAGE_SUBCLASS 0x0003
+
+formset
+ guid = DEVICE_MANAGER_FORMSET_GUID,
+ title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE),
+ help = STRING_TOKEN(STR_EMPTY_STRING),
+ classguid = DEVICE_MANAGER_FORMSET_GUID,
+
+ form formid = DEVICE_MANAGER_FORM_ID,
+ title = STRING_TOKEN(STR_DEVICE_MANAGER_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_DEVICES_LIST);
+ //
+ // This is where devices get added to the device manager hierarchy
+ //
+ label EFI_DISK_DEVICE_CLASS;
+// label LABEL_END; // Since next opcode is a label, so this one could be omitted to save code size
+
+ label EFI_VIDEO_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_NETWORK_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_INPUT_DEVICE_CLASS;
+// label LABEL_END;
+
+ label EFI_ON_BOARD_DEVICE_CLASS;
+// label LABEL_END;
+
+// label EFI_OTHER_DEVICE_CLASS;
+
+ label LABEL_DEVICES_LIST;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+
+ label LABEL_VBIOS;
+ label LABEL_END;
+
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+ subtitle text = STRING_TOKEN(STR_EXIT_STRING);
+
+ endform;
+
+ form formid = NETWORK_DEVICE_LIST_FORM_ID,
+ title = STRING_TOKEN(STR_FORM_NETWORK_DEVICE_LIST_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NETWORK_DEVICE_LIST_STRING);
+
+ label LABEL_NETWORK_DEVICE_LIST_ID;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+ subtitle text = STRING_TOKEN(STR_EXIT_STRING);
+ endform;
+
+ form formid = NETWORK_DEVICE_FORM_ID,
+ title = STRING_TOKEN(STR_FORM_NETWORK_DEVICE_TITLE);
+
+ subtitle text = STRING_TOKEN(STR_NETWORK_DEVICE_STRING);
+
+ label LABEL_NETWORK_DEVICE_ID;
+ label LABEL_END;
+ subtitle text = STRING_TOKEN(STR_EMPTY_STRING);
+ subtitle text = STRING_TOKEN(STR_EXIT_STRING);
+ endform;
+endformset;
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.h
new file mode 100644
index 0000000000..b6b086600f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DeviceManagerVfr.h
@@ -0,0 +1,56 @@
+/** @file
+ The platform device manager reference implement
+
+Copyright (c) 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DEVICE_MANAGER_VFR_H_
+#define _DEVICE_MANAGER_VFR_H_
+
+#include <Guid/BdsHii.h>
+
+#define LABEL_DEVICES_LIST 0x1100
+#define LABEL_NETWORK_DEVICE_LIST_ID 0x1101
+#define LABEL_NETWORK_DEVICE_ID 0x1102
+#define LABEL_END 0xffff
+#define LABEL_FORM_ID_OFFSET 0x0100
+
+#define LABEL_DRIVER_HEALTH 0x2000
+#define LABEL_DRIVER_HEALTH_END 0x2001
+
+#define LABEL_DRIVER_HEALTH_REAPIR_ALL 0x3000
+#define LABEL_DRIVER_HEALTH_REAPIR_ALL_END 0x3001
+
+#define LABEL_VBIOS 0x0040
+
+#define INVALID_FORM_ID 0x0FFF
+#define DEVICE_MANAGER_FORM_ID 0x1000
+#define NETWORK_DEVICE_LIST_FORM_ID 0x1001
+#define NETWORK_DEVICE_FORM_ID 0x1002
+#define DRIVER_HEALTH_FORM_ID 0x1003
+#define DEVICE_KEY_OFFSET 0x4000
+#define NETWORK_DEVICE_LIST_KEY_OFFSET 0x2000
+#define DEVICE_MANAGER_KEY_VBIOS 0x3000
+#define MAX_KEY_SECTION_LEN 0x1000
+
+#define DEVICE_MANAGER_KEY_DRIVER_HEALTH 0x1111
+#define DRIVER_HEALTH_KEY_OFFSET 0x2000
+#define DRIVER_HEALTH_REPAIR_ALL_KEY 0x3000
+#define DRIVER_HEALTH_RETURN_KEY 0x4000
+
+#define QUESTION_NETWORK_DEVICE_ID 0x3FFF
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 DeviceManagerVfrBin[];
+extern UINT8 DriverHealthVfrBin[];
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DriverHealthVfr.Vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DriverHealthVfr.Vfr
new file mode 100644
index 0000000000..cb1a8f887b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/DeviceMngr/DriverHealthVfr.Vfr
@@ -0,0 +1,38 @@
+///** @file
+//
+// Driver Health formset.
+//
+// Copyright (c) 2004 - 2011, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include "DeviceManagerVfr.h"
+
+formset
+ guid = DRIVER_HEALTH_FORMSET_GUID,
+ title = STRING_TOKEN(STR_DH_BANNER),
+ help = STRING_TOKEN(STR_EMPTY_STRING),
+ classguid = DRIVER_HEALTH_FORMSET_GUID,
+
+ form formid = DRIVER_HEALTH_FORM_ID,
+ title = STRING_TOKEN(STR_DH_BANNER);
+
+ label LABEL_DRIVER_HEALTH;
+ label LABEL_DRIVER_HEALTH_END;
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ label LABEL_DRIVER_HEALTH_REAPIR_ALL;
+ label LABEL_DRIVER_HEALTH_REAPIR_ALL_END;
+
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ subtitle text = STRING_TOKEN(STR_HELP_FOOTER);
+ subtitle text = STRING_TOKEN(STR_LAST_STRING);
+ endform;
+endformset;
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.c
new file mode 100644
index 0000000000..f04da16598
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.c
@@ -0,0 +1,1480 @@
+/** @file
+ FrontPage routines to handle the callbacks and browser calls
+
+Copyright (c) 2004 - 2016, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Bds.h"
+#include "FrontPage.h"
+#include "Language.h"
+#include "Hotkey.h"
+
+BOOLEAN mModeInitialized = FALSE;
+
+BOOLEAN gConnectAllHappened = FALSE;
+UINTN gCallbackKey;
+CHAR8 *mLanguageString;
+
+//
+// Boot video resolution and text mode.
+//
+UINT32 mBootHorizontalResolution = 0;
+UINT32 mBootVerticalResolution = 0;
+UINT32 mBootTextModeColumn = 0;
+UINT32 mBootTextModeRow = 0;
+//
+// BIOS setup video resolution and text mode.
+//
+UINT32 mSetupTextModeColumn = 0;
+UINT32 mSetupTextModeRow = 0;
+UINT32 mSetupHorizontalResolution = 0;
+UINT32 mSetupVerticalResolution = 0;
+
+EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+
+FRONT_PAGE_CALLBACK_DATA gFrontPagePrivate = {
+ FRONT_PAGE_CALLBACK_DATA_SIGNATURE,
+ NULL,
+ NULL,
+ NULL,
+ {
+ FakeExtractConfig,
+ FakeRouteConfig,
+ FrontPageCallback
+ }
+};
+
+HII_VENDOR_DEVICE_PATH mFrontPageHiiVendorDevicePath = {
+ {
+ {
+ HARDWARE_DEVICE_PATH,
+ HW_VENDOR_DP,
+ {
+ (UINT8) (sizeof (VENDOR_DEVICE_PATH)),
+ (UINT8) ((sizeof (VENDOR_DEVICE_PATH)) >> 8)
+ }
+ },
+ FRONT_PAGE_FORMSET_GUID
+ },
+ {
+ END_DEVICE_PATH_TYPE,
+ END_ENTIRE_DEVICE_PATH_SUBTYPE,
+ {
+ (UINT8) (END_DEVICE_PATH_LENGTH),
+ (UINT8) ((END_DEVICE_PATH_LENGTH) >> 8)
+ }
+ }
+};
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request A null-terminated Unicode string in <ConfigRequest> format.
+ @param Progress On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ )
+{
+ if (Progress == NULL || Results == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ *Progress = Request;
+ return EFI_NOT_FOUND;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration A null-terminated Unicode string in <ConfigResp> format.
+ @param Progress A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ )
+{
+ if (Configuration == NULL || Progress == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *Progress = Configuration;
+ if (!HiiIsConfigHdrMatch (Configuration, &gBootMaintFormSetGuid, mBootMaintStorageName)
+ && !HiiIsConfigHdrMatch (Configuration, &gFileExploreFormSetGuid, mFileExplorerStorageName)) {
+ return EFI_NOT_FOUND;
+ }
+
+ *Progress = Configuration + StrLen (Configuration);
+ return EFI_SUCCESS;
+}
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action Specifies the type of action taken by the browser.
+ @param QuestionId A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type The type of value for the question.
+ @param Value A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
+
+**/
+EFI_STATUS
+EFIAPI
+FrontPageCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ )
+{
+ CHAR8 *LangCode;
+ CHAR8 *Lang;
+ UINTN Index;
+
+ if (Action != EFI_BROWSER_ACTION_CHANGING && Action != EFI_BROWSER_ACTION_CHANGED) {
+ //
+ // All other action return unsupported.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ gCallbackKey = QuestionId;
+
+ if (Action == EFI_BROWSER_ACTION_CHANGED) {
+ if ((Value == NULL) || (ActionRequest == NULL)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ switch (QuestionId) {
+ case FRONT_PAGE_KEY_CONTINUE:
+ //
+ // This is the continue - clear the screen and return an error to get out of FrontPage loop
+ //
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+ break;
+
+ case FRONT_PAGE_KEY_LANGUAGE:
+ //
+ // Allocate working buffer for RFC 4646 language in supported LanguageString.
+ //
+ Lang = AllocatePool (AsciiStrSize (mLanguageString));
+ ASSERT (Lang != NULL);
+
+ Index = 0;
+ LangCode = mLanguageString;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (Index == Value->u8) {
+ break;
+ }
+
+ Index++;
+ }
+
+ if (Index == Value->u8) {
+ BdsDxeSetVariableAndReportStatusCodeOnError (
+ L"PlatformLang",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (Lang),
+ Lang
+ );
+ } else {
+ ASSERT (FALSE);
+ }
+
+ *ActionRequest = EFI_BROWSER_ACTION_REQUEST_EXIT;
+
+ FreePool (Lang);
+ break;
+
+ default:
+ break;
+ }
+ } else if (Action == EFI_BROWSER_ACTION_CHANGING) {
+ if (Value == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
+ // describe to their customers in documentation how to find their setup information (namely
+ // under the device manager and specific buckets)
+ //
+ switch (QuestionId) {
+ case FRONT_PAGE_KEY_BOOT_MANAGER:
+ //
+ // Boot Manager
+ //
+ break;
+
+ case FRONT_PAGE_KEY_DEVICE_MANAGER:
+ //
+ // Device Manager
+ //
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MAINTAIN:
+ //
+ // Boot Maintenance Manager
+ //
+ break;
+
+ default:
+ gCallbackKey = 0;
+ break;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Initialize HII information for the FrontPage
+
+
+ @param InitializeHiiData TRUE if HII elements need to be initialized.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed.
+
+**/
+EFI_STATUS
+InitializeFrontPage (
+ IN BOOLEAN InitializeHiiData
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *LangCode;
+ CHAR8 *Lang;
+ UINTN LangSize;
+ CHAR8 *CurrentLang;
+ UINTN OptionCount;
+ CHAR16 *StringBuffer;
+ EFI_HII_HANDLE HiiHandle;
+ VOID *OptionsOpCodeHandle;
+ VOID *StartOpCodeHandle;
+ VOID *EndOpCodeHandle;
+ EFI_IFR_GUID_LABEL *StartLabel;
+ EFI_IFR_GUID_LABEL *EndLabel;
+ EFI_HII_STRING_PROTOCOL *HiiString;
+ UINTN StringSize;
+
+ Lang = NULL;
+ StringBuffer = NULL;
+
+ if (InitializeHiiData) {
+ //
+ // Initialize the Device Manager
+ //
+ InitializeDeviceManager ();
+
+ //
+ // Initialize the Device Manager
+ //
+ InitializeBootManager ();
+
+ gCallbackKey = 0;
+
+ //
+ // Locate Hii relative protocols
+ //
+ Status = gBS->LocateProtocol (&gEfiFormBrowser2ProtocolGuid, NULL, (VOID **) &gFormBrowser2);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Install Device Path Protocol and Config Access protocol to driver handle
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &gFrontPagePrivate.DriverHandle,
+ &gEfiDevicePathProtocolGuid,
+ &mFrontPageHiiVendorDevicePath,
+ &gEfiHiiConfigAccessProtocolGuid,
+ &gFrontPagePrivate.ConfigAccess,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Publish our HII data
+ //
+ gFrontPagePrivate.HiiHandle = HiiAddPackages (
+ &gFrontPageFormSetGuid,
+ gFrontPagePrivate.DriverHandle,
+ FrontPageVfrBin,
+ BdsDxeStrings,
+ NULL
+ );
+ if (gFrontPagePrivate.HiiHandle == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ }
+
+
+ //
+ // Init OpCode Handle and Allocate space for creation of UpdateData Buffer
+ //
+ StartOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (StartOpCodeHandle != NULL);
+
+ EndOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (EndOpCodeHandle != NULL);
+
+ OptionsOpCodeHandle = HiiAllocateOpCodeHandle ();
+ ASSERT (OptionsOpCodeHandle != NULL);
+ //
+ // Create Hii Extend Label OpCode as the start opcode
+ //
+ StartLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (StartOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ StartLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ StartLabel->Number = LABEL_SELECT_LANGUAGE;
+
+ //
+ // Create Hii Extend Label OpCode as the end opcode
+ //
+ EndLabel = (EFI_IFR_GUID_LABEL *) HiiCreateGuidOpCode (EndOpCodeHandle, &gEfiIfrTianoGuid, NULL, sizeof (EFI_IFR_GUID_LABEL));
+ EndLabel->ExtendOpCode = EFI_IFR_EXTEND_OP_LABEL;
+ EndLabel->Number = LABEL_END;
+
+ //
+ // Collect the languages from what our current Language support is based on our VFR
+ //
+ HiiHandle = gFrontPagePrivate.HiiHandle;
+
+ GetEfiGlobalVariable2 (L"PlatformLang", (VOID**)&CurrentLang, NULL);
+
+ //
+ // Get Support language list from variable.
+ //
+ if (mLanguageString == NULL){
+ GetEfiGlobalVariable2 (L"PlatformLangCodes", (VOID**)&mLanguageString, NULL);
+ if (mLanguageString == NULL) {
+ mLanguageString = AllocateCopyPool (
+ AsciiStrSize ((CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)),
+ (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes)
+ );
+ ASSERT (mLanguageString != NULL);
+ }
+ }
+
+ if (gFrontPagePrivate.LanguageToken == NULL) {
+ //
+ // Count the language list number.
+ //
+ LangCode = mLanguageString;
+ Lang = AllocatePool (AsciiStrSize (mLanguageString));
+ ASSERT (Lang != NULL);
+ OptionCount = 0;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+ OptionCount ++;
+ }
+
+ //
+ // Allocate extra 1 as the end tag.
+ //
+ gFrontPagePrivate.LanguageToken = AllocateZeroPool ((OptionCount + 1) * sizeof (EFI_STRING_ID));
+ ASSERT (gFrontPagePrivate.LanguageToken != NULL);
+
+ Status = gBS->LocateProtocol (&gEfiHiiStringProtocolGuid, NULL, (VOID **) &HiiString);
+ ASSERT_EFI_ERROR (Status);
+
+ LangCode = mLanguageString;
+ OptionCount = 0;
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ StringSize = 0;
+ Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ StringBuffer = AllocateZeroPool (StringSize);
+ ASSERT (StringBuffer != NULL);
+ Status = HiiString->GetString (HiiString, Lang, HiiHandle, PRINTABLE_LANGUAGE_NAME_STRING_ID, StringBuffer, &StringSize, NULL);
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (EFI_ERROR (Status)) {
+ LangSize = AsciiStrSize (Lang);
+ StringBuffer = AllocatePool (LangSize * sizeof (CHAR16));
+ ASSERT (StringBuffer != NULL);
+ AsciiStrToUnicodeStrS (Lang, StringBuffer, LangSize);
+ }
+
+ ASSERT (StringBuffer != NULL);
+ gFrontPagePrivate.LanguageToken[OptionCount] = HiiSetString (HiiHandle, 0, StringBuffer, NULL);
+ FreePool (StringBuffer);
+
+ OptionCount++;
+ }
+ }
+
+ ASSERT (gFrontPagePrivate.LanguageToken != NULL);
+ LangCode = mLanguageString;
+ OptionCount = 0;
+ if (Lang == NULL) {
+ Lang = AllocatePool (AsciiStrSize (mLanguageString));
+ ASSERT (Lang != NULL);
+ }
+ while (*LangCode != 0) {
+ GetNextLanguage (&LangCode, Lang);
+
+ if (CurrentLang != NULL && AsciiStrCmp (Lang, CurrentLang) == 0) {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ gFrontPagePrivate.LanguageToken[OptionCount],
+ EFI_IFR_OPTION_DEFAULT,
+ EFI_IFR_NUMERIC_SIZE_1,
+ (UINT8) OptionCount
+ );
+ } else {
+ HiiCreateOneOfOptionOpCode (
+ OptionsOpCodeHandle,
+ gFrontPagePrivate.LanguageToken[OptionCount],
+ 0,
+ EFI_IFR_NUMERIC_SIZE_1,
+ (UINT8) OptionCount
+ );
+ }
+
+ OptionCount++;
+ }
+
+ if (CurrentLang != NULL) {
+ FreePool (CurrentLang);
+ }
+ FreePool (Lang);
+
+ HiiCreateOneOfOpCode (
+ StartOpCodeHandle,
+ FRONT_PAGE_KEY_LANGUAGE,
+ 0,
+ 0,
+ STRING_TOKEN (STR_LANGUAGE_SELECT),
+ STRING_TOKEN (STR_LANGUAGE_SELECT_HELP),
+ EFI_IFR_FLAG_CALLBACK,
+ EFI_IFR_NUMERIC_SIZE_1,
+ OptionsOpCodeHandle,
+ NULL
+ );
+
+ Status = HiiUpdateForm (
+ HiiHandle,
+ &gFrontPageFormSetGuid,
+ FRONT_PAGE_FORM_ID,
+ StartOpCodeHandle, // LABEL_SELECT_LANGUAGE
+ EndOpCodeHandle // LABEL_END
+ );
+
+ HiiFreeOpCodeHandle (StartOpCodeHandle);
+ HiiFreeOpCodeHandle (EndOpCodeHandle);
+ HiiFreeOpCodeHandle (OptionsOpCodeHandle);
+ return Status;
+}
+
+/**
+ Call the browser and display the front page
+
+ @return Status code that will be returned by
+ EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
+
+**/
+EFI_STATUS
+CallFrontPage (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ EFI_BROWSER_ACTION_REQUEST ActionRequest;
+
+ //
+ // Begin waiting for USER INPUT
+ //
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_INPUT_WAIT)
+ );
+
+ ActionRequest = EFI_BROWSER_ACTION_REQUEST_NONE;
+ Status = gFormBrowser2->SendForm (
+ gFormBrowser2,
+ &gFrontPagePrivate.HiiHandle,
+ 1,
+ &gFrontPageFormSetGuid,
+ 0,
+ NULL,
+ &ActionRequest
+ );
+ //
+ // Check whether user change any option setting which needs a reset to be effective
+ //
+ if (ActionRequest == EFI_BROWSER_ACTION_REQUEST_RESET) {
+ EnableResetRequired ();
+ }
+
+ return Status;
+}
+
+/**
+ Acquire the string associated with the ProducerGuid and return it.
+
+
+ @param ProducerGuid The Guid to search the HII database for
+ @param Token The token value of the string to extract
+ @param String The string that is extracted
+
+ @retval EFI_SUCCESS The function returns EFI_SUCCESS always.
+
+**/
+EFI_STATUS
+GetProducerString (
+ IN EFI_GUID *ProducerGuid,
+ IN EFI_STRING_ID Token,
+ OUT CHAR16 **String
+ )
+{
+ EFI_STRING TmpString;
+
+ TmpString = HiiGetPackageString (ProducerGuid, Token, NULL);
+ if (TmpString == NULL) {
+ *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
+ } else {
+ *String = TmpString;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert Processor Frequency Data to a string.
+
+ @param ProcessorFrequency The frequency data to process
+ @param Base10Exponent The exponent based on 10
+ @param String The string that is created
+
+**/
+VOID
+ConvertProcessorToString (
+ IN UINT16 ProcessorFrequency,
+ IN UINT16 Base10Exponent,
+ OUT CHAR16 **String
+ )
+{
+ CHAR16 *StringBuffer;
+ UINTN Index;
+ UINT32 FreqMhz;
+
+ if (Base10Exponent >= 6) {
+ FreqMhz = ProcessorFrequency;
+ for (Index = 0; Index < (UINTN) (Base10Exponent - 6); Index++) {
+ FreqMhz *= 10;
+ }
+ } else {
+ FreqMhz = 0;
+ }
+
+ StringBuffer = AllocateZeroPool (0x20);
+ ASSERT (StringBuffer != NULL);
+ Index = UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, FreqMhz / 1000, 3);
+ StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L".");
+ UnicodeValueToString (StringBuffer + Index + 1, PREFIX_ZERO, (FreqMhz % 1000) / 10, 2);
+ StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" GHz");
+ *String = (CHAR16 *) StringBuffer;
+ return ;
+}
+
+
+/**
+ Convert Memory Size to a string.
+
+ @param MemorySize The size of the memory to process
+ @param String The string that is created
+
+**/
+VOID
+ConvertMemorySizeToString (
+ IN UINT32 MemorySize,
+ OUT CHAR16 **String
+ )
+{
+ CHAR16 *StringBuffer;
+
+ StringBuffer = AllocateZeroPool (0x20);
+ ASSERT (StringBuffer != NULL);
+ UnicodeValueToString (StringBuffer, LEFT_JUSTIFY, MemorySize, 6);
+ StrCatS (StringBuffer, 0x20 / sizeof (CHAR16), L" MB RAM");
+
+ *String = (CHAR16 *) StringBuffer;
+
+ return ;
+}
+
+/**
+
+ Acquire the string associated with the Index from smbios structure and return it.
+ The caller is responsible for free the string buffer.
+
+ @param OptionalStrStart The start position to search the string
+ @param Index The index of the string to extract
+ @param String The string that is extracted
+
+ @retval EFI_SUCCESS The function returns EFI_SUCCESS always.
+
+**/
+EFI_STATUS
+GetOptionalStringByIndex (
+ IN CHAR8 *OptionalStrStart,
+ IN UINT8 Index,
+ OUT CHAR16 **String
+ )
+{
+ UINTN StrSize;
+
+ if (Index == 0) {
+ *String = AllocateZeroPool (sizeof (CHAR16));
+ return EFI_SUCCESS;
+ }
+
+ StrSize = 0;
+ do {
+ Index--;
+ OptionalStrStart += StrSize;
+ StrSize = AsciiStrSize (OptionalStrStart);
+ } while (OptionalStrStart[StrSize] != 0 && Index != 0);
+
+ if ((Index != 0) || (StrSize == 1)) {
+ //
+ // Meet the end of strings set but Index is non-zero, or
+ // Find an empty string
+ //
+ *String = GetStringById (STRING_TOKEN (STR_MISSING_STRING));
+ } else {
+ *String = AllocatePool (StrSize * sizeof (CHAR16));
+ AsciiStrToUnicodeStrS (OptionalStrStart, *String, StrSize);
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Update the banner information for the Front Page based on DataHub information.
+
+**/
+VOID
+UpdateFrontPageStrings (
+ VOID
+ )
+{
+ UINT8 StrIndex;
+ CHAR16 *NewString;
+ BOOLEAN Find[5];
+ EFI_STATUS Status;
+ EFI_STRING_ID TokenToUpdate;
+ EFI_SMBIOS_HANDLE SmbiosHandle;
+ EFI_SMBIOS_PROTOCOL *Smbios;
+ SMBIOS_TABLE_TYPE0 *Type0Record;
+ SMBIOS_TABLE_TYPE1 *Type1Record;
+ SMBIOS_TABLE_TYPE4 *Type4Record;
+ SMBIOS_TABLE_TYPE19 *Type19Record;
+ EFI_SMBIOS_TABLE_HEADER *Record;
+
+ ZeroMem (Find, sizeof (Find));
+
+ //
+ // Update Front Page strings
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSmbiosProtocolGuid,
+ NULL,
+ (VOID **) &Smbios
+ );
+ if (!EFI_ERROR (Status)) {
+ SmbiosHandle = SMBIOS_HANDLE_PI_RESERVED;
+ do {
+ Status = Smbios->GetNext (Smbios, &SmbiosHandle, NULL, &Record, NULL);
+ if (EFI_ERROR(Status)) {
+ break;
+ }
+
+ if (Record->Type == EFI_SMBIOS_TYPE_BIOS_INFORMATION) {
+ Type0Record = (SMBIOS_TABLE_TYPE0 *) Record;
+ StrIndex = Type0Record->BiosVersion;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type0Record + Type0Record->Hdr.Length), StrIndex, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_BIOS_VERSION);
+ HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
+ FreePool (NewString);
+ Find[0] = TRUE;
+ }
+
+ if (Record->Type == EFI_SMBIOS_TYPE_SYSTEM_INFORMATION) {
+ Type1Record = (SMBIOS_TABLE_TYPE1 *) Record;
+ StrIndex = Type1Record->ProductName;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type1Record + Type1Record->Hdr.Length), StrIndex, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_COMPUTER_MODEL);
+ HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
+ FreePool (NewString);
+ Find[1] = TRUE;
+ }
+
+ if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
+ Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
+ StrIndex = Type4Record->ProcessorVersion;
+ GetOptionalStringByIndex ((CHAR8*)((UINT8*)Type4Record + Type4Record->Hdr.Length), StrIndex, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_MODEL);
+ HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
+ FreePool (NewString);
+ Find[2] = TRUE;
+ }
+
+ if (Record->Type == EFI_SMBIOS_TYPE_PROCESSOR_INFORMATION) {
+ Type4Record = (SMBIOS_TABLE_TYPE4 *) Record;
+ ConvertProcessorToString(Type4Record->CurrentSpeed, 6, &NewString);
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_CPU_SPEED);
+ HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
+ FreePool (NewString);
+ Find[3] = TRUE;
+ }
+
+ if ( Record->Type == EFI_SMBIOS_TYPE_MEMORY_ARRAY_MAPPED_ADDRESS ) {
+ Type19Record = (SMBIOS_TABLE_TYPE19 *) Record;
+ ConvertMemorySizeToString (
+ (UINT32)(RShiftU64((Type19Record->EndingAddress - Type19Record->StartingAddress + 1), 10)),
+ &NewString
+ );
+ TokenToUpdate = STRING_TOKEN (STR_FRONT_PAGE_MEMORY_SIZE);
+ HiiSetString (gFrontPagePrivate.HiiHandle, TokenToUpdate, NewString, NULL);
+ FreePool (NewString);
+ Find[4] = TRUE;
+ }
+ } while ( !(Find[0] && Find[1] && Find[2] && Find[3] && Find[4]));
+ }
+ return ;
+}
+
+
+/**
+ Function waits for a given event to fire, or for an optional timeout to expire.
+
+ @param Event The event to wait for
+ @param Timeout An optional timeout value in 100 ns units.
+
+ @retval EFI_SUCCESS Event fired before Timeout expired.
+ @retval EFI_TIME_OUT Timout expired before Event fired..
+
+**/
+EFI_STATUS
+WaitForSingleEvent (
+ IN EFI_EVENT Event,
+ IN UINT64 Timeout OPTIONAL
+ )
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ EFI_EVENT TimerEvent;
+ EFI_EVENT WaitList[2];
+
+ if (Timeout != 0) {
+ //
+ // Create a timer event
+ //
+ Status = gBS->CreateEvent (EVT_TIMER, 0, NULL, NULL, &TimerEvent);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Set the timer event
+ //
+ gBS->SetTimer (
+ TimerEvent,
+ TimerRelative,
+ Timeout
+ );
+
+ //
+ // Wait for the original event or the timer
+ //
+ WaitList[0] = Event;
+ WaitList[1] = TimerEvent;
+ Status = gBS->WaitForEvent (2, WaitList, &Index);
+ gBS->CloseEvent (TimerEvent);
+
+ //
+ // If the timer expired, change the return to timed out
+ //
+ if (!EFI_ERROR (Status) && Index == 1) {
+ Status = EFI_TIMEOUT;
+ }
+ }
+ } else {
+ //
+ // No timeout... just wait on the event
+ //
+ Status = gBS->WaitForEvent (1, &Event, &Index);
+ ASSERT (!EFI_ERROR (Status));
+ ASSERT (Index == 0);
+ }
+
+ return Status;
+}
+
+/**
+ Function show progress bar to wait for user input.
+
+
+ @param TimeoutDefault The fault time out value before the system continue to boot.
+
+ @retval EFI_SUCCESS User pressed some key except "Enter"
+ @retval EFI_TIME_OUT Timeout expired or user press "Enter"
+
+**/
+EFI_STATUS
+ShowProgress (
+ IN UINT16 TimeoutDefault
+ )
+{
+ CHAR16 *TmpStr;
+ UINT16 TimeoutRemain;
+ EFI_STATUS Status;
+ EFI_INPUT_KEY Key;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+
+ if (TimeoutDefault != 0) {
+ DEBUG ((EFI_D_INFO, "\n\nStart showing progress bar... Press any key to stop it! ...Zzz....\n"));
+
+ SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+ SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+
+ TmpStr = GetStringById (STRING_TOKEN (STR_START_BOOT_OPTION));
+
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ //
+ // Clear the progress status bar first
+ //
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (Foreground, Background, TmpStr, Color, 0, 0);
+ }
+ }
+
+
+ TimeoutRemain = TimeoutDefault;
+ while (TimeoutRemain != 0) {
+ DEBUG ((EFI_D_INFO, "Showing progress bar...Remaining %d second!\n", TimeoutRemain));
+
+ Status = WaitForSingleEvent (gST->ConIn->WaitForKey, ONE_SECOND);
+ if (Status != EFI_TIMEOUT) {
+ break;
+ }
+ TimeoutRemain--;
+
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ //
+ // Show progress
+ //
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ ((TimeoutDefault - TimeoutRemain) * 100 / TimeoutDefault),
+ 0
+ );
+ }
+ }
+ }
+
+ if (TmpStr != NULL) {
+ gBS->FreePool (TmpStr);
+ }
+
+ //
+ // Timeout expired
+ //
+ if (TimeoutRemain == 0) {
+ return EFI_TIMEOUT;
+ }
+ }
+
+ //
+ // User pressed some key
+ //
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {
+ Status = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Key.UnicodeChar == CHAR_CARRIAGE_RETURN) {
+ //
+ // User pressed enter, equivalent to select "continue"
+ //
+ return EFI_TIMEOUT;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function is the main entry of the platform setup entry.
+ The function will present the main menu of the system setup,
+ this is the platform reference part and can be customize.
+
+
+ @param TimeoutDefault The fault time out value before the system
+ continue to boot.
+ @param ConnectAllHappened The indicater to check if the connect all have
+ already happened.
+
+**/
+VOID
+PlatformBdsEnterFrontPage (
+ IN UINT16 TimeoutDefault,
+ IN BOOLEAN ConnectAllHappened
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS StatusHotkey;
+ EFI_BOOT_LOGO_PROTOCOL *BootLogo;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN BootTextColumn;
+ UINTN BootTextRow;
+ UINT64 OsIndication;
+ UINTN DataSize;
+ EFI_INPUT_KEY Key;
+
+ GraphicsOutput = NULL;
+ SimpleTextOut = NULL;
+
+ PERF_START (NULL, "BdsTimeOut", "BDS", 0);
+ //
+ // Indicate if we need connect all in the platform setup
+ //
+ if (ConnectAllHappened) {
+ gConnectAllHappened = TRUE;
+ }
+
+ if (!mModeInitialized) {
+ //
+ // After the console is ready, get current video resolution
+ // and text mode before launching setup at first time.
+ //
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID**)&GraphicsOutput
+ );
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+ }
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID**)&SimpleTextOut
+ );
+ if (EFI_ERROR (Status)) {
+ SimpleTextOut = NULL;
+ }
+
+ if (GraphicsOutput != NULL) {
+ //
+ // Get current video resolution and text mode.
+ //
+ mBootHorizontalResolution = GraphicsOutput->Mode->Info->HorizontalResolution;
+ mBootVerticalResolution = GraphicsOutput->Mode->Info->VerticalResolution;
+ }
+
+ if (SimpleTextOut != NULL) {
+ Status = SimpleTextOut->QueryMode (
+ SimpleTextOut,
+ SimpleTextOut->Mode->Mode,
+ &BootTextColumn,
+ &BootTextRow
+ );
+ mBootTextModeColumn = (UINT32)BootTextColumn;
+ mBootTextModeRow = (UINT32)BootTextRow;
+ }
+
+ //
+ // Get user defined text mode for setup.
+ //
+ mSetupHorizontalResolution = PcdGet32 (PcdSetupVideoHorizontalResolution);
+ mSetupVerticalResolution = PcdGet32 (PcdSetupVideoVerticalResolution);
+ mSetupTextModeColumn = PcdGet32 (PcdSetupConOutColumn);
+ mSetupTextModeRow = PcdGet32 (PcdSetupConOutRow);
+
+ mModeInitialized = TRUE;
+ }
+
+
+ //
+ // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set
+ //
+ OsIndication = 0;
+ DataSize = sizeof(UINT64);
+ Status = gRT->GetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ NULL,
+ &DataSize,
+ &OsIndication
+ );
+
+ //
+ // goto FrontPage directly when EFI_OS_INDICATIONS_BOOT_TO_FW_UI is set. Skip HotkeyBoot
+ //
+ if (!EFI_ERROR(Status) && ((OsIndication & EFI_OS_INDICATIONS_BOOT_TO_FW_UI) != 0)) {
+ //
+ // Clear EFI_OS_INDICATIONS_BOOT_TO_FW_UI to acknowledge OS
+ //
+ OsIndication &= ~((UINT64)EFI_OS_INDICATIONS_BOOT_TO_FW_UI);
+ Status = gRT->SetVariable (
+ L"OsIndications",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof(UINT64),
+ &OsIndication
+ );
+ //
+ // Changing the content without increasing its size with current variable implementation shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Follow generic rule, Call ReadKeyStroke to connect ConIn before enter UI
+ //
+ if (PcdGetBool (PcdConInConnectOnDemand)) {
+ gST->ConIn->ReadKeyStroke(gST->ConIn, &Key);
+ }
+
+ //
+ // Ensure screen is clear when switch Console from Graphics mode to Text mode
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ gST->ConOut->ClearScreen (gST->ConOut);
+
+ } else {
+
+ HotkeyBoot ();
+ if (TimeoutDefault != 0xffff) {
+ Status = ShowProgress (TimeoutDefault);
+ StatusHotkey = HotkeyBoot ();
+
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable) || !EFI_ERROR(Status) || !EFI_ERROR(StatusHotkey)){
+ //
+ // Ensure screen is clear when switch Console from Graphics mode to Text mode
+ // Skip it in normal boot
+ //
+ gST->ConOut->EnableCursor (gST->ConOut, TRUE);
+ gST->ConOut->ClearScreen (gST->ConOut);
+ }
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Timeout or user press enter to continue
+ //
+ goto Exit;
+ }
+ }
+ }
+
+ //
+ // Boot Logo is corrupted, report it using Boot Logo protocol.
+ //
+ Status = gBS->LocateProtocol (&gEfiBootLogoProtocolGuid, NULL, (VOID **) &BootLogo);
+ if (!EFI_ERROR (Status) && (BootLogo != NULL)) {
+ BootLogo->SetBootLogo (BootLogo, NULL, 0, 0, 0, 0);
+ }
+
+ //
+ // Install BM HiiPackages.
+ // Keep BootMaint HiiPackage, so that it can be covered by global setting.
+ //
+ InitBMPackage ();
+
+ Status = EFI_SUCCESS;
+ do {
+ //
+ // Set proper video resolution and text mode for setup
+ //
+ BdsSetConsoleMode (TRUE);
+
+ InitializeFrontPage (FALSE);
+
+ //
+ // Update Front Page strings
+ //
+ UpdateFrontPageStrings ();
+
+ gCallbackKey = 0;
+ CallFrontPage ();
+
+ //
+ // If gCallbackKey is greater than 1 and less or equal to 5,
+ // it will launch configuration utilities.
+ // 2 = set language
+ // 3 = boot manager
+ // 4 = device manager
+ // 5 = boot maintenance manager
+ //
+ if (gCallbackKey != 0) {
+ REPORT_STATUS_CODE (
+ EFI_PROGRESS_CODE,
+ (EFI_SOFTWARE_DXE_BS_DRIVER | EFI_SW_PC_USER_SETUP)
+ );
+ }
+ //
+ // Based on the key that was set, we can determine what to do
+ //
+ switch (gCallbackKey) {
+ //
+ // The first 4 entries in the Front Page are to be GUARANTEED to remain constant so IHV's can
+ // describe to their customers in documentation how to find their setup information (namely
+ // under the device manager and specific buckets)
+ //
+ // These entries consist of the Continue, Select language, Boot Manager, and Device Manager
+ //
+ case FRONT_PAGE_KEY_CONTINUE:
+ //
+ // User hit continue
+ //
+ break;
+
+ case FRONT_PAGE_KEY_LANGUAGE:
+ //
+ // User made a language setting change - display front page again
+ //
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MANAGER:
+ //
+ // Remove the installed BootMaint HiiPackages when exit.
+ //
+ FreeBMPackage ();
+
+ //
+ // User chose to run the Boot Manager
+ //
+ CallBootManager ();
+
+ //
+ // Reinstall BootMaint HiiPackages after exiting from Boot Manager.
+ //
+ InitBMPackage ();
+ break;
+
+ case FRONT_PAGE_KEY_DEVICE_MANAGER:
+ //
+ // Display the Device Manager
+ //
+ do {
+ CallDeviceManager ();
+ } while (gCallbackKey == FRONT_PAGE_KEY_DEVICE_MANAGER);
+ break;
+
+ case FRONT_PAGE_KEY_BOOT_MAINTAIN:
+ //
+ // Display the Boot Maintenance Manager
+ //
+ BdsStartBootMaint ();
+ break;
+ }
+
+ } while ((Status == EFI_SUCCESS) && (gCallbackKey != FRONT_PAGE_KEY_CONTINUE));
+
+ if (mLanguageString != NULL) {
+ FreePool (mLanguageString);
+ mLanguageString = NULL;
+ }
+ //
+ //Will leave browser, check any reset required change is applied? if yes, reset system
+ //
+ SetupResetReminder ();
+
+ //
+ // Remove the installed BootMaint HiiPackages when exit.
+ //
+ FreeBMPackage ();
+
+Exit:
+ //
+ // Automatically load current entry
+ // Note: The following lines of code only execute when Auto boot
+ // takes affect
+ //
+ PERF_END (NULL, "BdsTimeOut", "BDS", 0);
+}
+
+/**
+ This function will change video resolution and text mode
+ according to defined setup mode or defined boot mode
+
+ @param IsSetupMode Indicate mode is changed to setup mode or boot mode.
+
+ @retval EFI_SUCCESS Mode is changed successfully.
+ @retval Others Mode failed to be changed.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsSetConsoleMode (
+ BOOLEAN IsSetupMode
+ )
+{
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ UINTN SizeOfInfo;
+ EFI_GRAPHICS_OUTPUT_MODE_INFORMATION *Info;
+ UINT32 MaxGopMode;
+ UINT32 MaxTextMode;
+ UINT32 ModeNumber;
+ UINT32 NewHorizontalResolution;
+ UINT32 NewVerticalResolution;
+ UINT32 NewColumns;
+ UINT32 NewRows;
+ UINTN HandleCount;
+ EFI_HANDLE *HandleBuffer;
+ EFI_STATUS Status;
+ UINTN Index;
+ UINTN CurrentColumn;
+ UINTN CurrentRow;
+
+ MaxGopMode = 0;
+ MaxTextMode = 0;
+
+ //
+ // Get current video resolution and text mode
+ //
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID**)&GraphicsOutput
+ );
+ if (EFI_ERROR (Status)) {
+ GraphicsOutput = NULL;
+ }
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID**)&SimpleTextOut
+ );
+ if (EFI_ERROR (Status)) {
+ SimpleTextOut = NULL;
+ }
+
+ if ((GraphicsOutput == NULL) || (SimpleTextOut == NULL)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ if (IsSetupMode) {
+ //
+ // The requried resolution and text mode is setup mode.
+ //
+ NewHorizontalResolution = mSetupHorizontalResolution;
+ NewVerticalResolution = mSetupVerticalResolution;
+ NewColumns = mSetupTextModeColumn;
+ NewRows = mSetupTextModeRow;
+ } else {
+ //
+ // The required resolution and text mode is boot mode.
+ //
+ NewHorizontalResolution = mBootHorizontalResolution;
+ NewVerticalResolution = mBootVerticalResolution;
+ NewColumns = mBootTextModeColumn;
+ NewRows = mBootTextModeRow;
+ }
+
+ if (GraphicsOutput != NULL) {
+ MaxGopMode = GraphicsOutput->Mode->MaxMode;
+ }
+
+ if (SimpleTextOut != NULL) {
+ MaxTextMode = SimpleTextOut->Mode->MaxMode;
+ }
+
+ //
+ // 1. If current video resolution is same with required video resolution,
+ // video resolution need not be changed.
+ // 1.1. If current text mode is same with required text mode, text mode need not be changed.
+ // 1.2. If current text mode is different from required text mode, text mode need be changed.
+ // 2. If current video resolution is different from required video resolution, we need restart whole console drivers.
+ //
+ for (ModeNumber = 0; ModeNumber < MaxGopMode; ModeNumber++) {
+ Status = GraphicsOutput->QueryMode (
+ GraphicsOutput,
+ ModeNumber,
+ &SizeOfInfo,
+ &Info
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((Info->HorizontalResolution == NewHorizontalResolution) &&
+ (Info->VerticalResolution == NewVerticalResolution)) {
+ if ((GraphicsOutput->Mode->Info->HorizontalResolution == NewHorizontalResolution) &&
+ (GraphicsOutput->Mode->Info->VerticalResolution == NewVerticalResolution)) {
+ //
+ // Current resolution is same with required resolution, check if text mode need be set
+ //
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, SimpleTextOut->Mode->Mode, &CurrentColumn, &CurrentRow);
+ ASSERT_EFI_ERROR (Status);
+ if (CurrentColumn == NewColumns && CurrentRow == NewRows) {
+ //
+ // If current text mode is same with required text mode. Do nothing
+ //
+ FreePool (Info);
+ return EFI_SUCCESS;
+ } else {
+ //
+ // If current text mode is different from requried text mode. Set new video mode
+ //
+ for (Index = 0; Index < MaxTextMode; Index++) {
+ Status = SimpleTextOut->QueryMode (SimpleTextOut, Index, &CurrentColumn, &CurrentRow);
+ if (!EFI_ERROR(Status)) {
+ if ((CurrentColumn == NewColumns) && (CurrentRow == NewRows)) {
+ //
+ // Required text mode is supported, set it.
+ //
+ Status = SimpleTextOut->SetMode (SimpleTextOut, Index);
+ ASSERT_EFI_ERROR (Status);
+ //
+ // Update text mode PCD.
+ //
+ Status = PcdSet32S (PcdConOutColumn, mSetupTextModeColumn);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdConOutRow, mSetupTextModeRow);
+ ASSERT_EFI_ERROR (Status);
+ FreePool (Info);
+ return EFI_SUCCESS;
+ }
+ }
+ }
+ if (Index == MaxTextMode) {
+ //
+ // If requried text mode is not supported, return error.
+ //
+ FreePool (Info);
+ return EFI_UNSUPPORTED;
+ }
+ }
+ } else {
+ //
+ // If current video resolution is not same with the new one, set new video resolution.
+ // In this case, the driver which produces simple text out need be restarted.
+ //
+ Status = GraphicsOutput->SetMode (GraphicsOutput, ModeNumber);
+ if (!EFI_ERROR (Status)) {
+ FreePool (Info);
+ break;
+ }
+ }
+ }
+ FreePool (Info);
+ }
+ }
+
+ if (ModeNumber == MaxGopMode) {
+ //
+ // If the resolution is not supported, return error.
+ //
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Set PCD to Inform GraphicsConsole to change video resolution.
+ // Set PCD to Inform Consplitter to change text mode.
+ //
+ Status = PcdSet32S (PcdVideoHorizontalResolution, NewHorizontalResolution);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdVideoVerticalResolution, NewVerticalResolution);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdConOutColumn, NewColumns);
+ ASSERT_EFI_ERROR (Status);
+ Status = PcdSet32S (PcdConOutRow, NewRows);
+ ASSERT_EFI_ERROR (Status);
+
+
+ //
+ // Video mode is changed, so restart graphics console driver and higher level driver.
+ // Reconnect graphics console driver and higher level driver.
+ // Locate all the handles with GOP protocol and reconnect it.
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiSimpleTextOutProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->DisconnectController (HandleBuffer[Index], NULL, NULL);
+ }
+ for (Index = 0; Index < HandleCount; Index++) {
+ gBS->ConnectController (HandleBuffer[Index], NULL, NULL, TRUE);
+ }
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.h
new file mode 100644
index 0000000000..a7b1c5bca0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPage.h
@@ -0,0 +1,254 @@
+/** @file
+ FrontPage routines to handle the callbacks and browser calls
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _FRONT_PAGE_H_
+#define _FRONT_PAGE_H_
+
+#include "DeviceMngr/DeviceManager.h"
+#include "BootMaint/BootMaint.h"
+#include "BootMngr/BootManager.h"
+#include "String.h"
+
+
+//
+// These are the VFR compiler generated data representing our VFR data.
+//
+extern UINT8 FrontPageVfrBin[];
+
+extern EFI_FORM_BROWSER2_PROTOCOL *gFormBrowser2;
+
+extern UINTN gCallbackKey;
+extern BOOLEAN gConnectAllHappened;
+
+//
+// Boot video resolution and text mode.
+//
+extern UINT32 mBootHorizontalResolution;
+extern UINT32 mBootVerticalResolution;
+extern UINT32 mBootTextModeColumn;
+extern UINT32 mBootTextModeRow;
+//
+// BIOS setup video resolution and text mode.
+//
+extern UINT32 mSetupTextModeColumn;
+extern UINT32 mSetupTextModeRow;
+extern UINT32 mSetupHorizontalResolution;
+extern UINT32 mSetupVerticalResolution;
+
+
+#define ONE_SECOND 10000000
+
+///
+/// The size of a 3 character ISO639 language code.
+///
+#define ISO_639_2_ENTRY_SIZE 3
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+#define PRINTABLE_LANGUAGE_NAME_STRING_ID 0x0001
+
+//
+// These are defined as the same with vfr file
+//
+#define FRONT_PAGE_FORM_ID 0x1000
+
+#define FRONT_PAGE_KEY_CONTINUE 0x1000
+#define FRONT_PAGE_KEY_LANGUAGE 0x1234
+#define FRONT_PAGE_KEY_BOOT_MANAGER 0x1064
+#define FRONT_PAGE_KEY_DEVICE_MANAGER 0x8567
+#define FRONT_PAGE_KEY_BOOT_MAINTAIN 0x9876
+
+#define LABEL_SELECT_LANGUAGE 0x1000
+#define LABEL_END 0xffff
+
+#define FRONT_PAGE_CALLBACK_DATA_SIGNATURE SIGNATURE_32 ('F', 'P', 'C', 'B')
+
+typedef struct {
+ UINTN Signature;
+
+ //
+ // HII relative handles
+ //
+ EFI_HII_HANDLE HiiHandle;
+ EFI_HANDLE DriverHandle;
+ EFI_STRING_ID *LanguageToken;
+
+ //
+ // Produced protocols
+ //
+ EFI_HII_CONFIG_ACCESS_PROTOCOL ConfigAccess;
+} FRONT_PAGE_CALLBACK_DATA;
+
+#define EFI_FP_CALLBACK_DATA_FROM_THIS(a) \
+ CR (a, \
+ FRONT_PAGE_CALLBACK_DATA, \
+ ConfigAccess, \
+ FRONT_PAGE_CALLBACK_DATA_SIGNATURE \
+ )
+
+/**
+ This function allows a caller to extract the current configuration for one
+ or more named elements from the target driver.
+
+
+ @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Request - A null-terminated Unicode string in <ConfigRequest> format.
+ @param Progress - On return, points to a character in the Request string.
+ Points to the string's null terminator if request was successful.
+ Points to the most recent '&' before the first failing name/value
+ pair (or the beginning of the string if the failure is in the
+ first name/value pair) if the request was not successful.
+ @param Results - A null-terminated Unicode string in <ConfigAltResp> format which
+ has all values filled in for the names in the Request string.
+ String to be allocated by the called function.
+
+ @retval EFI_SUCCESS The Results is filled with the requested values.
+ @retval EFI_OUT_OF_RESOURCES Not enough memory to store the results.
+ @retval EFI_INVALID_PARAMETER Request is NULL, illegal syntax, or unknown name.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeExtractConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Request,
+ OUT EFI_STRING *Progress,
+ OUT EFI_STRING *Results
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Configuration - A null-terminated Unicode string in <ConfigResp> format.
+ @param Progress - A pointer to a string filled in with the offset of the most
+ recent '&' before the first failing name/value pair (or the
+ beginning of the string if the failure is in the first
+ name/value pair) or the terminating NULL if all was successful.
+
+ @retval EFI_SUCCESS The Results is processed successfully.
+ @retval EFI_INVALID_PARAMETER Configuration is NULL.
+ @retval EFI_NOT_FOUND Routing data doesn't match any storage in this driver.
+
+**/
+EFI_STATUS
+EFIAPI
+FakeRouteConfig (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN CONST EFI_STRING Configuration,
+ OUT EFI_STRING *Progress
+ );
+
+/**
+ This function processes the results of changes in configuration.
+
+
+ @param This - Points to the EFI_HII_CONFIG_ACCESS_PROTOCOL.
+ @param Action - Specifies the type of action taken by the browser.
+ @param QuestionId - A unique value which is sent to the original exporting driver
+ so that it can identify the type of data to expect.
+ @param Type - The type of value for the question.
+ @param Value - A pointer to the data being sent to the original exporting driver.
+ @param ActionRequest - On return, points to the action requested by the callback function.
+
+ @retval EFI_SUCCESS The callback successfully handled the action.
+ @retval EFI_OUT_OF_RESOURCES Not enough storage is available to hold the variable and its data.
+ @retval EFI_DEVICE_ERROR The variable could not be saved.
+ @retval EFI_UNSUPPORTED The specified Action is not supported by the callback.
+
+**/
+EFI_STATUS
+EFIAPI
+FrontPageCallback (
+ IN CONST EFI_HII_CONFIG_ACCESS_PROTOCOL *This,
+ IN EFI_BROWSER_ACTION Action,
+ IN EFI_QUESTION_ID QuestionId,
+ IN UINT8 Type,
+ IN EFI_IFR_TYPE_VALUE *Value,
+ OUT EFI_BROWSER_ACTION_REQUEST *ActionRequest
+ );
+
+/**
+ Initialize HII information for the FrontPage
+
+
+ @param InitializeHiiData TRUE if HII elements need to be initialized.
+
+ @retval EFI_SUCCESS The operation is successful.
+ @retval EFI_DEVICE_ERROR If the dynamic opcode creation failed.
+
+**/
+EFI_STATUS
+InitializeFrontPage (
+ IN BOOLEAN InitializeHiiData
+ );
+
+/**
+ Acquire the string associated with the ProducerGuid and return it.
+
+
+ @param ProducerGuid - The Guid to search the HII database for
+ @param Token - The token value of the string to extract
+ @param String - The string that is extracted
+
+ @retval EFI_SUCCESS The function returns EFI_SUCCESS always.
+
+**/
+EFI_STATUS
+GetProducerString (
+ IN EFI_GUID *ProducerGuid,
+ IN EFI_STRING_ID Token,
+ OUT CHAR16 **String
+ );
+
+/**
+ This function is the main entry of the platform setup entry.
+ The function will present the main menu of the system setup,
+ this is the platform reference part and can be customize.
+
+
+ @param TimeoutDefault - The fault time out value before the system
+ continue to boot.
+ @param ConnectAllHappened - The indicater to check if the connect all have
+ already happened.
+
+**/
+VOID
+PlatformBdsEnterFrontPage (
+ IN UINT16 TimeoutDefault,
+ IN BOOLEAN ConnectAllHappened
+ );
+
+/**
+ This function will change video resolution and text mode
+ according to defined setup mode or defined boot mode
+
+ @param IsSetupMode Indicate mode is changed to setup mode or boot mode.
+
+ @retval EFI_SUCCESS Mode is changed successfully.
+ @retval Others Mode failed to be changed.
+
+**/
+EFI_STATUS
+EFIAPI
+BdsSetConsoleMode (
+ BOOLEAN IsSetupMode
+ );
+
+#endif // _FRONT_PAGE_H_
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageStrings.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageStrings.uni
new file mode 100644
index 0000000000..3c083b4998
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr
new file mode 100644
index 0000000000..a2d92dff51
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/FrontPageVfr.Vfr
@@ -0,0 +1,137 @@
+///** @file
+//
+// Browser formset.
+//
+// Copyright (c) 2007 - 2015, Intel Corporation. All rights reserved.<BR>
+// This program and the accompanying materials
+// are licensed and made available under the terms and conditions of the BSD License
+// which accompanies this distribution. The full text of the license may be found at
+// http://opensource.org/licenses/bsd-license.php
+//
+// THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+// WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+//
+//**/
+
+#include <Guid/BdsHii.h>
+
+#define FRONT_PAGE_CLASS 0x0000
+#define FRONT_PAGE_SUBCLASS 0x0002
+
+#define FRONT_PAGE_FORM_ID 0x1000
+
+#define FRONT_PAGE_ITEM_ONE 0x0001
+#define FRONT_PAGE_ITEM_TWO 0x0002
+#define FRONT_PAGE_ITEM_THREE 0x0003
+#define FRONT_PAGE_ITEM_FOUR 0x0004
+#define FRONT_PAGE_ITEM_FIVE 0x0005
+
+#define FRONT_PAGE_KEY_CONTINUE 0x1000
+#define FRONT_PAGE_KEY_LANGUAGE 0x1234
+#define FRONT_PAGE_KEY_BOOT_MANAGER 0x1064
+#define FRONT_PAGE_KEY_DEVICE_MANAGER 0x8567
+#define FRONT_PAGE_KEY_BOOT_MAINTAIN 0x9876
+
+#define LABEL_SELECT_LANGUAGE 0x1000
+#define LABEL_TIMEOUT 0x2000
+#define LABEL_END 0xffff
+
+formset
+ guid = FRONT_PAGE_FORMSET_GUID,
+ title = STRING_TOKEN(STR_FRONT_PAGE_TITLE),
+ help = STRING_TOKEN(STR_NULL_STRING),
+ classguid = FRONT_PAGE_FORMSET_GUID,
+
+ form formid = FRONT_PAGE_FORM_ID,
+ title = STRING_TOKEN(STR_FRONT_PAGE_TITLE);
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_COMPUTER_MODEL),
+ line 1,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_CPU_MODEL),
+ line 2,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_CPU_SPEED),
+ line 2,
+ align right;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_BIOS_VERSION),
+ line 3,
+ align left;
+
+ banner
+ title = STRING_TOKEN(STR_FRONT_PAGE_MEMORY_SIZE),
+ line 3,
+ align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_LEFT),
+// line 0,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_0_RIGHT),
+// line 0,
+// align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_LEFT),
+// line 1,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_1_RIGHT),
+// line 1,
+// align right;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_2_LEFT),
+// line 2,
+// align left;
+
+// banner
+// title = STRING_TOKEN(STR_FRONT_PAGE_BANNER_3_LEFT),
+// line 3,
+// align left;
+
+
+ text
+ help = STRING_TOKEN(STR_CONTINUE_HELP),
+ text = STRING_TOKEN(STR_CONTINUE_PROMPT),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_CONTINUE;
+
+ label LABEL_SELECT_LANGUAGE;
+ //
+ // This is where we will dynamically add a OneOf type op-code to select
+ // Languages from the currently available choices
+ //
+ label LABEL_END;
+
+ goto FRONT_PAGE_ITEM_THREE,
+ prompt = STRING_TOKEN(STR_BOOT_MANAGER),
+ help = STRING_TOKEN(STR_BOOT_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_BOOT_MANAGER;
+
+ goto FRONT_PAGE_ITEM_FOUR,
+ prompt = STRING_TOKEN(STR_DEVICE_MANAGER),
+ help = STRING_TOKEN(STR_DEVICE_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_DEVICE_MANAGER;
+
+ goto FRONT_PAGE_ITEM_FIVE,
+ prompt = STRING_TOKEN(STR_BOOT_MAINT_MANAGER),
+ help = STRING_TOKEN(STR_BOOT_MAINT_MANAGER_HELP),
+ flags = INTERACTIVE,
+ key = FRONT_PAGE_KEY_BOOT_MAINTAIN;
+
+ endform;
+
+endformset;
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.c
new file mode 100644
index 0000000000..e061991ea2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.c
@@ -0,0 +1,597 @@
+/** @file
+ Provides a way for 3rd party applications to register themselves for launch by the
+ Boot Manager based on hot key
+
+Copyright (c) 2007 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Hotkey.h"
+
+
+LIST_ENTRY mHotkeyList = INITIALIZE_LIST_HEAD_VARIABLE (mHotkeyList);
+BDS_COMMON_OPTION *mHotkeyBootOption = NULL;
+EFI_EVENT mHotkeyEvent;
+VOID *mHotkeyRegistration;
+
+
+/**
+ Check if the Key Option is valid or not.
+
+ @param KeyOption The Hot Key Option to be checked.
+
+ @retval TRUE The Hot Key Option is valid.
+ @retval FALSE The Hot Key Option is invalid.
+
+**/
+BOOLEAN
+IsKeyOptionValid (
+ IN EFI_KEY_OPTION *KeyOption
+)
+{
+ UINT16 BootOptionName[10];
+ UINT8 *BootOptionVar;
+ UINTN BootOptionSize;
+ UINT32 Crc;
+
+ //
+ // Check whether corresponding Boot Option exist
+ //
+ UnicodeSPrint (BootOptionName, sizeof (BootOptionName), L"Boot%04x", KeyOption->BootOption);
+ BootOptionVar = BdsLibGetVariableAndSize (
+ BootOptionName,
+ &gEfiGlobalVariableGuid,
+ &BootOptionSize
+ );
+
+ if (BootOptionVar == NULL || BootOptionSize == 0) {
+ return FALSE;
+ }
+
+ //
+ // Check CRC for Boot Option
+ //
+ gBS->CalculateCrc32 (BootOptionVar, BootOptionSize, &Crc);
+ FreePool (BootOptionVar);
+
+ return (BOOLEAN) ((KeyOption->BootOptionCrc == Crc) ? TRUE : FALSE);
+}
+
+/**
+ Try to boot the boot option triggered by hotkey.
+ @retval EFI_SUCCESS There is HotkeyBootOption & it is processed
+ @retval EFI_NOT_FOUND There is no HotkeyBootOption
+**/
+EFI_STATUS
+HotkeyBoot (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINTN ExitDataSize;
+ CHAR16 *ExitData;
+
+ if (mHotkeyBootOption == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ BdsLibConnectDevicePath (mHotkeyBootOption->DevicePath);
+
+ //
+ // Clear the screen before launch this BootOption
+ //
+ gST->ConOut->Reset (gST->ConOut, FALSE);
+
+ Status = BdsLibBootViaBootOption (mHotkeyBootOption, mHotkeyBootOption->DevicePath, &ExitDataSize, &ExitData);
+
+ if (EFI_ERROR (Status)) {
+ //
+ // Call platform action to indicate the boot fail
+ //
+ mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_FAILED));
+ PlatformBdsBootFail (mHotkeyBootOption, Status, ExitData, ExitDataSize);
+ } else {
+ //
+ // Call platform action to indicate the boot success
+ //
+ mHotkeyBootOption->StatusString = GetStringById (STRING_TOKEN (STR_BOOT_SUCCEEDED));
+ PlatformBdsBootSuccess (mHotkeyBootOption);
+ }
+ FreePool (mHotkeyBootOption->Description);
+ FreePool (mHotkeyBootOption->DevicePath);
+ FreePool (mHotkeyBootOption->LoadOptions);
+ FreePool (mHotkeyBootOption);
+
+ mHotkeyBootOption = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+
+ This is the common notification function for HotKeys, it will be registered
+ with SimpleTextInEx protocol interface - RegisterKeyNotify() of ConIn handle.
+
+ @param KeyData A pointer to a buffer that is filled in with the keystroke
+ information for the key that was pressed.
+
+ @retval EFI_SUCCESS KeyData is successfully processed.
+ @return EFI_NOT_FOUND Fail to find boot option variable.
+**/
+EFI_STATUS
+EFIAPI
+HotkeyCallback (
+ IN EFI_KEY_DATA *KeyData
+)
+{
+ BOOLEAN HotkeyCatched;
+ LIST_ENTRY BootLists;
+ LIST_ENTRY *Link;
+ BDS_HOTKEY_OPTION *Hotkey;
+ UINT16 Buffer[10];
+ EFI_STATUS Status;
+ EFI_KEY_DATA *HotkeyData;
+
+ if (mHotkeyBootOption != NULL) {
+ //
+ // Do not process sequential hotkey stroke until the current boot option returns
+ //
+ return EFI_SUCCESS;
+ }
+
+ Status = EFI_SUCCESS;
+
+ for ( Link = GetFirstNode (&mHotkeyList)
+ ; !IsNull (&mHotkeyList, Link)
+ ; Link = GetNextNode (&mHotkeyList, Link)
+ ) {
+ HotkeyCatched = FALSE;
+ Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
+
+ //
+ // Is this Key Stroke we are waiting for?
+ //
+ ASSERT (Hotkey->WaitingKey < (sizeof (Hotkey->KeyData) / sizeof (Hotkey->KeyData[0])));
+ HotkeyData = &Hotkey->KeyData[Hotkey->WaitingKey];
+ if ((KeyData->Key.ScanCode == HotkeyData->Key.ScanCode) &&
+ (KeyData->Key.UnicodeChar == HotkeyData->Key.UnicodeChar) &&
+ (((KeyData->KeyState.KeyShiftState & EFI_SHIFT_STATE_VALID) != 0) ?
+ (KeyData->KeyState.KeyShiftState == HotkeyData->KeyState.KeyShiftState) : TRUE
+ )
+ ) {
+ //
+ // For hotkey of key combination, transit to next waiting state
+ //
+ Hotkey->WaitingKey++;
+
+ if (Hotkey->WaitingKey == Hotkey->CodeCount) {
+ //
+ // Received the whole key stroke sequence
+ //
+ HotkeyCatched = TRUE;
+ }
+ } else {
+ //
+ // Receive an unexpected key stroke, reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+ }
+
+ if (HotkeyCatched) {
+ //
+ // Reset to initial waiting state
+ //
+ Hotkey->WaitingKey = 0;
+
+ //
+ // Launch its BootOption
+ //
+ InitializeListHead (&BootLists);
+
+ UnicodeSPrint (Buffer, sizeof (Buffer), L"Boot%04x", Hotkey->BootOptionNumber);
+ mHotkeyBootOption = BdsLibVariableToOption (&BootLists, Buffer);
+ }
+ }
+
+ return Status;
+}
+
+/**
+ Register the common HotKey notify function to given SimpleTextInEx protocol instance.
+
+ @param SimpleTextInEx Simple Text Input Ex protocol instance
+
+ @retval EFI_SUCCESS Register hotkey notification function successfully.
+ @retval EFI_OUT_OF_RESOURCES Unable to allocate necessary data structures.
+
+**/
+EFI_STATUS
+HotkeyRegisterNotify (
+ IN EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx
+)
+{
+ UINTN Index;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ BDS_HOTKEY_OPTION *Hotkey;
+
+ //
+ // Register notification function for each hotkey
+ //
+ Link = GetFirstNode (&mHotkeyList);
+
+ while (!IsNull (&mHotkeyList, Link)) {
+ Hotkey = BDS_HOTKEY_OPTION_FROM_LINK (Link);
+
+ Index = 0;
+ do {
+ Status = SimpleTextInEx->RegisterKeyNotify (
+ SimpleTextInEx,
+ &Hotkey->KeyData[Index],
+ HotkeyCallback,
+ &Hotkey->NotifyHandle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // some of the hotkey registry failed
+ //
+ return Status;
+ }
+ Index ++;
+ } while ((Index < Hotkey->CodeCount) && (Index < (sizeof (Hotkey->KeyData) / sizeof (EFI_KEY_DATA))));
+
+ Link = GetNextNode (&mHotkeyList, Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Callback function for SimpleTextInEx protocol install events
+
+ @param Event the event that is signaled.
+ @param Context not used here.
+
+**/
+VOID
+EFIAPI
+HotkeyEvent (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ UINTN BufferSize;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_INPUT_EX_PROTOCOL *SimpleTextInEx;
+
+ while (TRUE) {
+ BufferSize = sizeof (EFI_HANDLE);
+ Status = gBS->LocateHandle (
+ ByRegisterNotify,
+ NULL,
+ mHotkeyRegistration,
+ &BufferSize,
+ &Handle
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If no more notification events exist
+ //
+ return ;
+ }
+
+ Status = gBS->HandleProtocol (
+ Handle,
+ &gEfiSimpleTextInputExProtocolGuid,
+ (VOID **) &SimpleTextInEx
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ HotkeyRegisterNotify (SimpleTextInEx);
+ }
+}
+
+/**
+ Insert Key Option to hotkey list.
+
+ @param KeyOption The Hot Key Option to be added to hotkey list.
+
+ @retval EFI_SUCCESS Add to hotkey list success.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory resource.
+**/
+EFI_STATUS
+HotkeyInsertList (
+ IN EFI_KEY_OPTION *KeyOption
+)
+{
+ BDS_HOTKEY_OPTION *HotkeyLeft;
+ BDS_HOTKEY_OPTION *HotkeyRight;
+ UINTN Index;
+ EFI_BOOT_KEY_DATA KeyOptions;
+ UINT32 KeyShiftStateLeft;
+ UINT32 KeyShiftStateRight;
+ EFI_INPUT_KEY *InputKey;
+ EFI_KEY_DATA *KeyData;
+
+ HotkeyLeft = AllocateZeroPool (sizeof (BDS_HOTKEY_OPTION));
+ if (HotkeyLeft == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ HotkeyLeft->Signature = BDS_HOTKEY_OPTION_SIGNATURE;
+ HotkeyLeft->BootOptionNumber = KeyOption->BootOption;
+
+ KeyOptions = KeyOption->KeyData;
+
+ HotkeyLeft->CodeCount = (UINT8) KeyOptions.Options.InputKeyCount;
+
+ //
+ // Map key shift state from KeyOptions to EFI_KEY_DATA.KeyState
+ //
+ KeyShiftStateRight = EFI_SHIFT_STATE_VALID;
+ if (KeyOptions.Options.ShiftPressed) {
+ KeyShiftStateRight |= EFI_RIGHT_SHIFT_PRESSED;
+ }
+ if (KeyOptions.Options.ControlPressed) {
+ KeyShiftStateRight |= EFI_RIGHT_CONTROL_PRESSED;
+ }
+ if (KeyOptions.Options.AltPressed) {
+ KeyShiftStateRight |= EFI_RIGHT_ALT_PRESSED;
+ }
+ if (KeyOptions.Options.LogoPressed) {
+ KeyShiftStateRight |= EFI_RIGHT_LOGO_PRESSED;
+ }
+ if (KeyOptions.Options.MenuPressed) {
+ KeyShiftStateRight |= EFI_MENU_KEY_PRESSED;
+ }
+ if (KeyOptions.Options.SysReqPressed) {
+ KeyShiftStateRight |= EFI_SYS_REQ_PRESSED;
+ }
+
+ KeyShiftStateLeft = (KeyShiftStateRight & 0xffffff00) | ((KeyShiftStateRight & 0xff) << 1);
+
+ InputKey = (EFI_INPUT_KEY *) (((UINT8 *) KeyOption) + sizeof (EFI_KEY_OPTION));
+
+ Index = 0;
+ KeyData = &HotkeyLeft->KeyData[0];
+ do {
+ //
+ // If Key CodeCount is 0, then only KeyData[0] is used;
+ // if Key CodeCount is n, then KeyData[0]~KeyData[n-1] are used
+ //
+ KeyData->Key.ScanCode = InputKey[Index].ScanCode;
+ KeyData->Key.UnicodeChar = InputKey[Index].UnicodeChar;
+ KeyData->KeyState.KeyShiftState = KeyShiftStateLeft;
+
+ Index++;
+ KeyData++;
+ } while (Index < HotkeyLeft->CodeCount);
+ InsertTailList (&mHotkeyList, &HotkeyLeft->Link);
+
+ if (KeyShiftStateLeft != KeyShiftStateRight) {
+ //
+ // Need an extra hotkey for shift key on right
+ //
+ HotkeyRight = AllocateCopyPool (sizeof (BDS_HOTKEY_OPTION), HotkeyLeft);
+ if (HotkeyRight == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Index = 0;
+ KeyData = &HotkeyRight->KeyData[0];
+ do {
+ //
+ // Key.ScanCode and Key.UnicodeChar have already been initialized,
+ // only need to update KeyState.KeyShiftState
+ //
+ KeyData->KeyState.KeyShiftState = KeyShiftStateRight;
+
+ Index++;
+ KeyData++;
+ } while (Index < HotkeyRight->CodeCount);
+ InsertTailList (&mHotkeyList, &HotkeyRight->Link);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return TRUE when the variable pointed by Name and Guid is a Key#### variable.
+
+ @param Name The name of the variable.
+ @param Guid The GUID of the variable.
+ @param OptionNumber Return the option number parsed from the Name.
+
+ @retval TRUE The variable pointed by Name and Guid is a Key#### variable.
+ @retval FALSE The variable pointed by Name and Guid isn't a Key#### variable.
+**/
+BOOLEAN
+IsKeyOptionVariable (
+ CHAR16 *Name,
+ EFI_GUID *Guid,
+ UINT16 *OptionNumber
+ )
+{
+ UINTN Index;
+
+ if (!CompareGuid (Guid, &gEfiGlobalVariableGuid) ||
+ (StrSize (Name) != sizeof (L"Key####")) ||
+ (StrnCmp (Name, L"Key", 3) != 0)
+ ) {
+ return FALSE;
+ }
+
+ *OptionNumber = 0;
+ for (Index = 3; Index < 7; Index++) {
+ if ((Name[Index] >= L'0') && (Name[Index] <= L'9')) {
+ *OptionNumber = *OptionNumber * 16 + Name[Index] - L'0';
+ } else if ((Name[Index] >= L'A') && (Name[Index] <= L'F')) {
+ *OptionNumber = *OptionNumber * 16 + Name[Index] - L'A' + 10;
+ } else {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Return an array of key option numbers.
+
+ @param Count Return the count of key option numbers.
+
+ @return UINT16* Pointer to an array of key option numbers;
+**/
+UINT16 *
+EFIAPI
+HotkeyGetOptionNumbers (
+ OUT UINTN *Count
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ CHAR16 *Name;
+ EFI_GUID Guid;
+ UINTN NameSize;
+ UINTN NewNameSize;
+ UINT16 *OptionNumbers;
+ UINT16 OptionNumber;
+
+ if (Count == NULL) {
+ return NULL;
+ }
+
+ *Count = 0;
+ OptionNumbers = NULL;
+
+ NameSize = sizeof (CHAR16);
+ Name = AllocateZeroPool (NameSize);
+ ASSERT (Name != NULL);
+ while (TRUE) {
+ NewNameSize = NameSize;
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ Name = ReallocatePool (NameSize, NewNameSize, Name);
+ ASSERT (Name != NULL);
+ Status = gRT->GetNextVariableName (&NewNameSize, Name, &Guid);
+ NameSize = NewNameSize;
+ }
+
+ if (Status == EFI_NOT_FOUND) {
+ break;
+ }
+ ASSERT_EFI_ERROR (Status);
+
+ if (IsKeyOptionVariable (Name ,&Guid, &OptionNumber)) {
+ OptionNumbers = ReallocatePool (
+ *Count * sizeof (UINT16),
+ (*Count + 1) * sizeof (UINT16),
+ OptionNumbers
+ );
+ ASSERT (OptionNumbers != NULL);
+ for (Index = 0; Index < *Count; Index++) {
+ if (OptionNumber < OptionNumbers[Index]) {
+ break;
+ }
+ }
+ CopyMem (&OptionNumbers[Index + 1], &OptionNumbers[Index], (*Count - Index) * sizeof (UINT16));
+ OptionNumbers[Index] = OptionNumber;
+ (*Count)++;
+ }
+ }
+
+ FreePool (Name);
+
+ return OptionNumbers;
+}
+
+/**
+
+ Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
+
+ @retval EFI_SUCCESS Hotkey services successfully initialized.
+**/
+EFI_STATUS
+InitializeHotkeyService (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT32 BootOptionSupport;
+ UINT16 *KeyOptionNumbers;
+ UINTN KeyOptionCount;
+ UINTN Index;
+ CHAR16 KeyOptionName[8];
+ EFI_KEY_OPTION *KeyOption;
+
+ //
+ // Export our capability - EFI_BOOT_OPTION_SUPPORT_KEY and EFI_BOOT_OPTION_SUPPORT_APP.
+ // with maximum number of key presses of 3
+ // Do not report the hotkey capability if PcdConInConnectOnDemand is enabled.
+ //
+ BootOptionSupport = EFI_BOOT_OPTION_SUPPORT_APP;
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {
+ BootOptionSupport |= EFI_BOOT_OPTION_SUPPORT_KEY;
+ SET_BOOT_OPTION_SUPPORT_KEY_COUNT (BootOptionSupport, 3);
+ }
+
+ Status = gRT->SetVariable (
+ L"BootOptionSupport",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ sizeof (UINT32),
+ &BootOptionSupport
+ );
+ //
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+
+ KeyOptionNumbers = HotkeyGetOptionNumbers (&KeyOptionCount);
+ for (Index = 0; Index < KeyOptionCount; Index ++) {
+ UnicodeSPrint (KeyOptionName, sizeof (KeyOptionName), L"Key%04x", KeyOptionNumbers[Index]);
+ GetEfiGlobalVariable2 (KeyOptionName, (VOID **) &KeyOption, NULL);
+ ASSERT (KeyOption != NULL);
+ if (IsKeyOptionValid (KeyOption)) {
+ HotkeyInsertList (KeyOption);
+ }
+ FreePool (KeyOption);
+ }
+
+ if (KeyOptionNumbers != NULL) {
+ FreePool (KeyOptionNumbers);
+ }
+
+ //
+ // Register Protocol notify for Hotkey service
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ HotkeyEvent,
+ NULL,
+ &mHotkeyEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifications on this event
+ //
+ Status = gBS->RegisterProtocolNotify (
+ &gEfiSimpleTextInputExProtocolGuid,
+ mHotkeyEvent,
+ &mHotkeyRegistration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.h
new file mode 100644
index 0000000000..4ee5563a22
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Hotkey.h
@@ -0,0 +1,67 @@
+/** @file
+ Provides a way for 3rd party applications to register themselves for launch by the
+ Boot Manager based on hot key
+
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HOTKEY_H_
+#define _HOTKEY_H_
+
+#include "Bds.h"
+#include "String.h"
+
+#define SET_BOOT_OPTION_SUPPORT_KEY_COUNT(a, c) { \
+ (a) = ((a) & ~EFI_BOOT_OPTION_SUPPORT_COUNT) | (((c) << LowBitSet32 (EFI_BOOT_OPTION_SUPPORT_COUNT)) & EFI_BOOT_OPTION_SUPPORT_COUNT); \
+ }
+
+#define BDS_HOTKEY_OPTION_SIGNATURE SIGNATURE_32 ('B', 'd', 'K', 'O')
+
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Link;
+
+ VOID *NotifyHandle;
+ UINT16 BootOptionNumber;
+ UINT8 CodeCount;
+ UINT8 WaitingKey;
+ EFI_KEY_DATA KeyData[3];
+} BDS_HOTKEY_OPTION;
+
+#define BDS_HOTKEY_OPTION_FROM_LINK(a) CR (a, BDS_HOTKEY_OPTION, Link, BDS_HOTKEY_OPTION_SIGNATURE)
+
+/**
+
+ Process all the "Key####" variables, associate Hotkeys with corresponding Boot Options.
+
+
+ @param VOID
+
+ @retval EFI_SUCCESS Hotkey services successfully initialized.
+
+**/
+EFI_STATUS
+InitializeHotkeyService (
+ VOID
+ );
+
+/**
+ Try to boot the boot option triggered by hotkey.
+ @retval EFI_SUCCESS There is HotkeyBootOption & it is processed
+ @retval EFI_NOT_FOUND There is no HotkeyBootOption
+**/
+EFI_STATUS
+HotkeyBoot (
+ VOID
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.c
new file mode 100644
index 0000000000..ddb2f93980
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.c
@@ -0,0 +1,48 @@
+/** @file
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Copyright (c) 2007 - 2013, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "HwErrRecSupport.h"
+
+/**
+ Set the HwErrRecSupport variable contains a binary UINT16 that supplies the
+ level of support for Hardware Error Record Persistence that is implemented
+ by the platform.
+
+**/
+VOID
+InitializeHwErrRecSupport (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+ UINT16 HardwareErrorRecordLevel;
+
+ HardwareErrorRecordLevel = PcdGet16 (PcdHardwareErrorRecordLevel);
+
+ if (HardwareErrorRecordLevel != 0) {
+ //
+ // If level value equal 0, no need set to 0 to variable area because UEFI specification
+ // define same behavior between no value or 0 value for L"HwErrRecSupport".
+ //
+ Status = gRT->SetVariable (
+ L"HwErrRecSupport",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS | EFI_VARIABLE_NON_VOLATILE,
+ sizeof (UINT16),
+ &HardwareErrorRecordLevel
+ );
+ ASSERT_EFI_ERROR(Status);
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.h
new file mode 100644
index 0000000000..0cf597acc7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/HwErrRecSupport.h
@@ -0,0 +1,32 @@
+/** @file
+ Set the level of support for Hardware Error Record Persistence that is
+ implemented by the platform.
+
+Copyright (c) 2007 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _HW_ERR_REC_SUPPORT_H_
+#define _HW_ERR_REC_SUPPORT_H_
+
+#include "Bds.h"
+
+/**
+ Set the HwErrRecSupport variable contains a binary UINT16 that supplies the
+ level of support for Hardware Error Record Persistence that is implemented
+ by the platform.
+
+**/
+VOID
+InitializeHwErrRecSupport (
+ VOID
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.c
new file mode 100644
index 0000000000..39455e44da
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.c
@@ -0,0 +1,499 @@
+/** @file
+ Language settings
+
+Copyright (c) 2004 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Language.h"
+#include "FrontPage.h"
+
+EFI_GUID mFontPackageGuid = {
+ 0x78941450, 0x90ab, 0x4fb1, {0xb7, 0x5f, 0x58, 0x92, 0x14, 0xe2, 0x4a, 0xc}
+};
+
+#define NARROW_GLYPH_NUMBER 8
+#define WIDE_GLYPH_NUMBER 75
+
+typedef struct {
+ ///
+ /// This 4-bytes total array length is required by HiiAddPackages()
+ ///
+ UINT32 Length;
+
+ //
+ // This is the Font package definition
+ //
+ EFI_HII_PACKAGE_HEADER Header;
+ UINT16 NumberOfNarrowGlyphs;
+ UINT16 NumberOfWideGlyphs;
+ EFI_NARROW_GLYPH NarrowArray[NARROW_GLYPH_NUMBER];
+ EFI_WIDE_GLYPH WideArray[WIDE_GLYPH_NUMBER];
+} FONT_PACK_BIN;
+
+FONT_PACK_BIN mFontBin = {
+ sizeof (FONT_PACK_BIN),
+ {
+ sizeof (FONT_PACK_BIN) - sizeof (UINT32),
+ EFI_HII_PACKAGE_SIMPLE_FONTS,
+ },
+ NARROW_GLYPH_NUMBER,
+ 0,
+ { // Narrow Glyphs
+ {
+ 0x05d0,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x4E,
+ 0x6E,
+ 0x62,
+ 0x32,
+ 0x32,
+ 0x3C,
+ 0x68,
+ 0x4C,
+ 0x4C,
+ 0x46,
+ 0x76,
+ 0x72,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d1,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x7C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x7E,
+ 0x7E,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d2,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x78,
+ 0x7C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x1C,
+ 0x3E,
+ 0x66,
+ 0x66,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d3,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7E,
+ 0x7E,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d4,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x7C,
+ 0x7E,
+ 0x06,
+ 0x06,
+ 0x06,
+ 0x06,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x66,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d5,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x3C,
+ 0x3C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x0C,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x05d6,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x38,
+ 0x38,
+ 0x1E,
+ 0x1E,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x18,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ },
+ {
+ 0x0000,
+ 0x00,
+ {
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00,
+ 0x00
+ }
+ }
+ }
+};
+
+/**
+ Routine to export glyphs to the HII database. This is in addition to whatever is defined in the Graphics Console driver.
+
+**/
+VOID
+ExportFonts (
+ VOID
+ )
+{
+ EFI_HII_HANDLE HiiHandle;
+
+ HiiHandle = HiiAddPackages (
+ &mFontPackageGuid,
+ gImageHandle,
+ &mFontBin,
+ NULL
+ );
+ ASSERT (HiiHandle != NULL);
+}
+
+/**
+ Get next language from language code list (with separator ';').
+
+ If LangCode is NULL, then ASSERT.
+ If Lang is NULL, then ASSERT.
+
+ @param LangCode On input: point to first language in the list. On
+ output: point to next language in the list, or
+ NULL if no more language in the list.
+ @param Lang The first language in the list.
+
+**/
+VOID
+EFIAPI
+GetNextLanguage (
+ IN OUT CHAR8 **LangCode,
+ OUT CHAR8 *Lang
+ )
+{
+ UINTN Index;
+ CHAR8 *StringPtr;
+
+ ASSERT (LangCode != NULL);
+ ASSERT (*LangCode != NULL);
+ ASSERT (Lang != NULL);
+
+ Index = 0;
+ StringPtr = *LangCode;
+ while (StringPtr[Index] != 0 && StringPtr[Index] != ';') {
+ Index++;
+ }
+
+ CopyMem (Lang, StringPtr, Index);
+ Lang[Index] = 0;
+
+ if (StringPtr[Index] == ';') {
+ Index++;
+ }
+ *LangCode = StringPtr + Index;
+}
+
+/**
+ Check if lang is in supported language codes according to language string.
+
+ This code is used to check if lang is in in supported language codes. It can handle
+ RFC4646 and ISO639 language tags.
+ In ISO639 language tags, take 3-characters as a delimitation to find matched string.
+ In RFC4646 language tags, take semicolon as a delimitation to find matched string.
+
+ For example:
+ SupportedLang = "engfraengfra"
+ Iso639Language = TRUE
+ Lang = "eng", the return value is "TRUE", or
+ Lang = "chs", the return value is "FALSE".
+ Another example:
+ SupportedLang = "en;fr;en-US;fr-FR"
+ Iso639Language = FALSE
+ Lang = "en", the return value is "TRUE", or
+ Lang = "zh", the return value is "FALSE".
+
+ @param SupportedLang Platform supported language codes.
+ @param Lang Configured language.
+ @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646.
+
+ @retval TRUE lang is in supported language codes.
+ @retval FALSE lang is not in supported language codes.
+
+**/
+BOOLEAN
+IsLangInSupportedLangCodes(
+ IN CHAR8 *SupportedLang,
+ IN CHAR8 *Lang,
+ IN BOOLEAN Iso639Language
+ )
+{
+ UINTN Index;
+ UINTN CompareLength;
+ UINTN LanguageLength;
+
+ if (Iso639Language) {
+ CompareLength = ISO_639_2_ENTRY_SIZE;
+ for (Index = 0; Index < AsciiStrLen (SupportedLang); Index += CompareLength) {
+ if (AsciiStrnCmp (Lang, SupportedLang + Index, CompareLength) == 0) {
+ //
+ // Successfully find the Lang string in SupportedLang string.
+ //
+ return TRUE;
+ }
+ }
+ return FALSE;
+ } else {
+ //
+ // Compare RFC4646 language code
+ //
+ for (LanguageLength = 0; Lang[LanguageLength] != '\0'; LanguageLength++);
+
+ for (; *SupportedLang != '\0'; SupportedLang += CompareLength) {
+ //
+ // Skip ';' characters in SupportedLang
+ //
+ for (; *SupportedLang != '\0' && *SupportedLang == ';'; SupportedLang++);
+ //
+ // Determine the length of the next language code in SupportedLang
+ //
+ for (CompareLength = 0; SupportedLang[CompareLength] != '\0' && SupportedLang[CompareLength] != ';'; CompareLength++);
+
+ if ((CompareLength == LanguageLength) &&
+ (AsciiStrnCmp (Lang, SupportedLang, CompareLength) == 0)) {
+ //
+ // Successfully find the Lang string in SupportedLang string.
+ //
+ return TRUE;
+ }
+ }
+ return FALSE;
+ }
+}
+
+/**
+ Initialize Lang or PlatformLang variable, if Lang or PlatformLang variable is not found,
+ or it has been set to an unsupported value(not one of platform supported language codes),
+ set the default language code to it.
+
+ @param LangName Language name, L"Lang" or L"PlatformLang".
+ @param SupportedLang Platform supported language codes.
+ @param DefaultLang Default language code.
+ @param Iso639Language A bool value to signify if the handler is operated on ISO639 or RFC4646,
+ TRUE for L"Lang" LangName or FALSE for L"PlatformLang" LangName.
+
+**/
+VOID
+InitializeLangVariable (
+ IN CHAR16 *LangName,
+ IN CHAR8 *SupportedLang,
+ IN CHAR8 *DefaultLang,
+ IN BOOLEAN Iso639Language
+ )
+{
+ CHAR8 *Lang;
+
+ //
+ // Find current Lang or PlatformLang from EFI Variable.
+ //
+ GetEfiGlobalVariable2 (LangName, (VOID **) &Lang, NULL);
+ //
+ // If Lang or PlatformLang variable is not found,
+ // or it has been set to an unsupported value(not one of the supported language codes),
+ // set the default language code to it.
+ //
+ if ((Lang == NULL) || !IsLangInSupportedLangCodes (SupportedLang, Lang, Iso639Language)) {
+ //
+ // The default language code should be one of the supported language codes.
+ //
+ ASSERT (IsLangInSupportedLangCodes (SupportedLang, DefaultLang, Iso639Language));
+ BdsDxeSetVariableAndReportStatusCodeOnError (
+ LangName,
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_NON_VOLATILE | EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (DefaultLang),
+ DefaultLang
+ );
+ }
+
+ if (Lang != NULL) {
+ FreePool (Lang);
+ }
+}
+
+/**
+ Determine the current language that will be used
+ based on language related EFI Variables.
+
+ @param LangCodesSettingRequired - If required to set LangCodes variable
+
+**/
+VOID
+InitializeLanguage (
+ BOOLEAN LangCodesSettingRequired
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *LangCodes;
+ CHAR8 *PlatformLangCodes;
+
+ ExportFonts ();
+
+ LangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultLangCodes);
+ PlatformLangCodes = (CHAR8 *)PcdGetPtr (PcdUefiVariableDefaultPlatformLangCodes);
+ if (LangCodesSettingRequired) {
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+ //
+ // UEFI 2.0 depricated this variable so we support turning it off
+ //
+ Status = gRT->SetVariable (
+ L"LangCodes",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (LangCodes),
+ LangCodes
+ );
+ //
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ Status = gRT->SetVariable (
+ L"PlatformLangCodes",
+ &gEfiGlobalVariableGuid,
+ EFI_VARIABLE_BOOTSERVICE_ACCESS | EFI_VARIABLE_RUNTIME_ACCESS,
+ AsciiStrSize (PlatformLangCodes),
+ PlatformLangCodes
+ );
+ //
+ // Platform needs to make sure setting volatile variable before calling 3rd party code shouldn't fail.
+ //
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ if (!FeaturePcdGet (PcdUefiVariableDefaultLangDeprecate)) {
+ //
+ // UEFI 2.0 depricated this variable so we support turning it off
+ //
+ InitializeLangVariable (L"Lang", LangCodes, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultLang), TRUE);
+ }
+ InitializeLangVariable (L"PlatformLang", PlatformLangCodes, (CHAR8 *) PcdGetPtr (PcdUefiVariableDefaultPlatformLang), FALSE);
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.h
new file mode 100644
index 0000000000..31c65f1824
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Language.h
@@ -0,0 +1,51 @@
+/** @file
+ Language setting
+
+Copyright (c) 2004 - 2008, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _LANGUAGE_H_
+#define _LANGUAGE_H_
+
+#include "String.h"
+
+/**
+ Get next language from language code list (with separator ';').
+
+ If LangCode is NULL, then ASSERT.
+ If Lang is NULL, then ASSERT.
+
+ @param LangCode On input: point to first language in the list. On
+ output: point to next language in the list, or
+ NULL if no more language in the list.
+ @param Lang The first language in the list.
+
+**/
+VOID
+EFIAPI
+GetNextLanguage (
+ IN OUT CHAR8 **LangCode,
+ OUT CHAR8 *Lang
+ );
+
+/**
+ Determine the current language that will be used
+ based on language related EFI Variables.
+
+ @param LangCodesSettingRequired If required to set LangCode variable
+
+**/
+VOID
+InitializeLanguage (
+ BOOLEAN LangCodesSettingRequired
+ );
+
+#endif // _LANGUAGE_H_
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/MemoryTest.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/MemoryTest.c
new file mode 100644
index 0000000000..700e3e6626
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/MemoryTest.c
@@ -0,0 +1,436 @@
+/** @file
+ Perform the platform memory test
+
+Copyright (c) 2004 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Bds.h"
+#include "String.h"
+
+//
+// BDS Platform Functions
+//
+/**
+
+ Show progress bar with title above it. It only works in Graphics mode.
+
+
+ @param TitleForeground Foreground color for Title.
+ @param TitleBackground Background color for Title.
+ @param Title Title above progress bar.
+ @param ProgressColor Progress bar color.
+ @param Progress Progress (0-100)
+ @param PreviousValue The previous value of the progress.
+
+ @retval EFI_STATUS Success update the progress bar
+
+**/
+EFI_STATUS
+PlatformBdsShowProgress (
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleForeground,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL TitleBackground,
+ IN CHAR16 *Title,
+ IN EFI_GRAPHICS_OUTPUT_BLT_PIXEL ProgressColor,
+ IN UINTN Progress,
+ IN UINTN PreviousValue
+ )
+{
+ EFI_STATUS Status;
+ EFI_GRAPHICS_OUTPUT_PROTOCOL *GraphicsOutput;
+ EFI_UGA_DRAW_PROTOCOL *UgaDraw;
+ UINT32 SizeOfX;
+ UINT32 SizeOfY;
+ UINT32 ColorDepth;
+ UINT32 RefreshRate;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+ UINTN BlockHeight;
+ UINTN BlockWidth;
+ UINTN BlockNum;
+ UINTN PosX;
+ UINTN PosY;
+ UINTN Index;
+
+ if (Progress > 100) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ UgaDraw = NULL;
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiGraphicsOutputProtocolGuid,
+ (VOID **) &GraphicsOutput
+ );
+ if (EFI_ERROR (Status) && FeaturePcdGet (PcdUgaConsumeSupport)) {
+ GraphicsOutput = NULL;
+
+ Status = gBS->HandleProtocol (
+ gST->ConsoleOutHandle,
+ &gEfiUgaDrawProtocolGuid,
+ (VOID **) &UgaDraw
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SizeOfX = 0;
+ SizeOfY = 0;
+ if (GraphicsOutput != NULL) {
+ SizeOfX = GraphicsOutput->Mode->Info->HorizontalResolution;
+ SizeOfY = GraphicsOutput->Mode->Info->VerticalResolution;
+ } else if (UgaDraw != NULL) {
+ Status = UgaDraw->GetMode (
+ UgaDraw,
+ &SizeOfX,
+ &SizeOfY,
+ &ColorDepth,
+ &RefreshRate
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+
+ BlockWidth = SizeOfX / 100;
+ BlockHeight = SizeOfY / 50;
+
+ BlockNum = Progress;
+
+ PosX = 0;
+ PosY = SizeOfY * 48 / 50;
+
+ if (BlockNum == 0) {
+ //
+ // Clear progress area
+ //
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &Color,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ 0,
+ PosY - EFI_GLYPH_HEIGHT - 1,
+ SizeOfX,
+ SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
+ SizeOfX * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) &Color,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ 0,
+ PosY - EFI_GLYPH_HEIGHT - 1,
+ SizeOfX,
+ SizeOfY - (PosY - EFI_GLYPH_HEIGHT - 1),
+ SizeOfX * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+ //
+ // Show progress by drawing blocks
+ //
+ for (Index = PreviousValue; Index < BlockNum; Index++) {
+ PosX = Index * BlockWidth;
+ if (GraphicsOutput != NULL) {
+ Status = GraphicsOutput->Blt (
+ GraphicsOutput,
+ &ProgressColor,
+ EfiBltVideoFill,
+ 0,
+ 0,
+ PosX,
+ PosY,
+ BlockWidth - 1,
+ BlockHeight,
+ (BlockWidth) * sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL)
+ );
+ } else if (FeaturePcdGet (PcdUgaConsumeSupport)) {
+ Status = UgaDraw->Blt (
+ UgaDraw,
+ (EFI_UGA_PIXEL *) &ProgressColor,
+ EfiUgaVideoFill,
+ 0,
+ 0,
+ PosX,
+ PosY,
+ BlockWidth - 1,
+ BlockHeight,
+ (BlockWidth) * sizeof (EFI_UGA_PIXEL)
+ );
+ } else {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ PrintXY (
+ (SizeOfX - StrLen (Title) * EFI_GLYPH_WIDTH) / 2,
+ PosY - EFI_GLYPH_HEIGHT - 1,
+ &TitleForeground,
+ &TitleBackground,
+ Title
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Perform the memory test base on the memory test intensive level,
+ and update the memory resource.
+
+ @param Level The memory test intensive level.
+
+ @retval EFI_STATUS Success test all the system memory and update
+ the memory resource
+
+**/
+EFI_STATUS
+EFIAPI
+BdsMemoryTest (
+ IN EXTENDMEM_COVERAGE_LEVEL Level
+ )
+{
+ EFI_STATUS Status;
+ EFI_STATUS KeyStatus;
+ EFI_STATUS InitStatus;
+ EFI_STATUS ReturnStatus;
+ BOOLEAN RequireSoftECCInit;
+ EFI_GENERIC_MEMORY_TEST_PROTOCOL *GenMemoryTest;
+ UINT64 TestedMemorySize;
+ UINT64 TotalMemorySize;
+ UINTN TestPercent;
+ UINT64 PreviousValue;
+ BOOLEAN ErrorOut;
+ BOOLEAN TestAbort;
+ EFI_INPUT_KEY Key;
+ CHAR16 StrPercent[80];
+ CHAR16 *StrTotalMemory;
+ CHAR16 *Pos;
+ CHAR16 *TmpStr;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Foreground;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Background;
+ EFI_GRAPHICS_OUTPUT_BLT_PIXEL Color;
+ BOOLEAN IsFirstBoot;
+ UINT32 TempData;
+ UINTN StrTotalMemorySize;
+
+ ReturnStatus = EFI_SUCCESS;
+ ZeroMem (&Key, sizeof (EFI_INPUT_KEY));
+
+ StrTotalMemorySize = 128;
+ Pos = AllocateZeroPool (StrTotalMemorySize);
+
+ if (Pos == NULL) {
+ return ReturnStatus;
+ }
+
+ StrTotalMemory = Pos;
+
+ TestedMemorySize = 0;
+ TotalMemorySize = 0;
+ PreviousValue = 0;
+ ErrorOut = FALSE;
+ TestAbort = FALSE;
+
+ SetMem (&Foreground, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+ SetMem (&Background, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0x0);
+ SetMem (&Color, sizeof (EFI_GRAPHICS_OUTPUT_BLT_PIXEL), 0xff);
+
+ RequireSoftECCInit = FALSE;
+
+ Status = gBS->LocateProtocol (
+ &gEfiGenericMemTestProtocolGuid,
+ NULL,
+ (VOID **) &GenMemoryTest
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Pos);
+ return EFI_SUCCESS;
+ }
+
+ InitStatus = GenMemoryTest->MemoryTestInit (
+ GenMemoryTest,
+ Level,
+ &RequireSoftECCInit
+ );
+ if (InitStatus == EFI_NO_MEDIA) {
+ //
+ // The PEI codes also have the relevant memory test code to check the memory,
+ // it can select to test some range of the memory or all of them. If PEI code
+ // checks all the memory, this BDS memory test will has no not-test memory to
+ // do the test, and then the status of EFI_NO_MEDIA will be returned by
+ // "MemoryTestInit". So it does not need to test memory again, just return.
+ //
+ FreePool (Pos);
+ return EFI_SUCCESS;
+ }
+
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ TmpStr = GetStringById (STRING_TOKEN (STR_ESC_TO_SKIP_MEM_TEST));
+
+ if (TmpStr != NULL) {
+ PrintXY (10, 10, NULL, NULL, TmpStr);
+ FreePool (TmpStr);
+ }
+ } else {
+ DEBUG ((EFI_D_INFO, "Enter memory test.\n"));
+ }
+ do {
+ Status = GenMemoryTest->PerformMemoryTest (
+ GenMemoryTest,
+ &TestedMemorySize,
+ &TotalMemorySize,
+ &ErrorOut,
+ TestAbort
+ );
+ if (ErrorOut && (Status == EFI_DEVICE_ERROR)) {
+ TmpStr = GetStringById (STRING_TOKEN (STR_SYSTEM_MEM_ERROR));
+ if (TmpStr != NULL) {
+ PrintXY (10, 10, NULL, NULL, TmpStr);
+ FreePool (TmpStr);
+ }
+
+ ASSERT (0);
+ }
+
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ TempData = (UINT32) DivU64x32 (TotalMemorySize, 16);
+ TestPercent = (UINTN) DivU64x32 (
+ DivU64x32 (MultU64x32 (TestedMemorySize, 100), 16),
+ TempData
+ );
+ if (TestPercent != PreviousValue) {
+ UnicodeValueToString (StrPercent, 0, TestPercent, 0);
+ TmpStr = GetStringById (STRING_TOKEN (STR_MEMORY_TEST_PERCENT));
+ if (TmpStr != NULL) {
+ //
+ // TmpStr size is 64, StrPercent is reserved to 16.
+ //
+ StrnCatS (
+ StrPercent,
+ sizeof (StrPercent) / sizeof (CHAR16),
+ TmpStr,
+ sizeof (StrPercent) / sizeof (CHAR16) - StrLen (StrPercent) - 1
+ );
+ PrintXY (10, 10, NULL, NULL, StrPercent);
+ FreePool (TmpStr);
+ }
+
+ TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ TestPercent,
+ (UINTN) PreviousValue
+ );
+ FreePool (TmpStr);
+ }
+ }
+
+ PreviousValue = TestPercent;
+ } else {
+ DEBUG ((EFI_D_INFO, "Perform memory test (ESC to skip).\n"));
+ }
+
+ if (!PcdGetBool (PcdConInConnectOnDemand)) {
+ KeyStatus = gST->ConIn->ReadKeyStroke (gST->ConIn, &Key);
+ if (!EFI_ERROR (KeyStatus) && (Key.ScanCode == SCAN_ESC)) {
+ if (!RequireSoftECCInit) {
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ TmpStr = GetStringById (STRING_TOKEN (STR_PERFORM_MEM_TEST));
+ if (TmpStr != NULL) {
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ TmpStr,
+ Color,
+ 100,
+ (UINTN) PreviousValue
+ );
+ FreePool (TmpStr);
+ }
+
+ PrintXY (10, 10, NULL, NULL, L"100");
+ }
+ Status = GenMemoryTest->Finished (GenMemoryTest);
+ goto Done;
+ }
+
+ TestAbort = TRUE;
+ }
+ }
+ } while (Status != EFI_NOT_FOUND);
+
+ Status = GenMemoryTest->Finished (GenMemoryTest);
+
+Done:
+ if (!FeaturePcdGet(PcdBootlogoOnlyEnable)) {
+ UnicodeValueToString (StrTotalMemory, COMMA_TYPE, TotalMemorySize, 0);
+ if (StrTotalMemory[0] == L',') {
+ StrTotalMemory++;
+ StrTotalMemorySize -= sizeof (CHAR16);
+ }
+
+ TmpStr = GetStringById (STRING_TOKEN (STR_MEM_TEST_COMPLETED));
+ if (TmpStr != NULL) {
+ StrnCatS (
+ StrTotalMemory,
+ StrTotalMemorySize / sizeof (CHAR16),
+ TmpStr,
+ StrTotalMemorySize / sizeof (CHAR16) - StrLen (StrTotalMemory) - 1
+ );
+ FreePool (TmpStr);
+ }
+
+ PrintXY (10, 10, NULL, NULL, StrTotalMemory);
+ PlatformBdsShowProgress (
+ Foreground,
+ Background,
+ StrTotalMemory,
+ Color,
+ 100,
+ (UINTN) PreviousValue
+ );
+
+ } else {
+ DEBUG ((EFI_D_INFO, "%d bytes of system memory tested OK\r\n", TotalMemorySize));
+ }
+
+ FreePool (Pos);
+
+
+ //
+ // Use a DynamicHii type pcd to save the boot status, which is used to
+ // control configuration mode, such as FULL/MINIMAL/NO_CHANGES configuration.
+ //
+ IsFirstBoot = PcdGetBool(PcdBootState);
+ if (IsFirstBoot) {
+ Status = PcdSetBoolS(PcdBootState, FALSE);
+ if (EFI_ERROR (Status)) {
+ DEBUG ((EFI_D_ERROR, "Set PcdBootState to FALSE failed.\n"));
+ }
+ }
+
+ return ReturnStatus;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.c b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.c
new file mode 100644
index 0000000000..d02001b4d1
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.c
@@ -0,0 +1,59 @@
+/** @file
+ String support
+
+Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "Bds.h"
+#include "Language.h"
+#include "FrontPage.h"
+
+EFI_HII_HANDLE gStringPackHandle;
+
+EFI_GUID mBdsStringPackGuid = {
+ 0x7bac95d3, 0xddf, 0x42f3, {0x9e, 0x24, 0x7c, 0x64, 0x49, 0x40, 0x37, 0x9a}
+};
+
+/**
+ Initialize HII global accessor for string support.
+
+**/
+VOID
+InitializeStringSupport (
+ VOID
+ )
+{
+ gStringPackHandle = HiiAddPackages (
+ &mBdsStringPackGuid,
+ gImageHandle,
+ BdsDxeStrings,
+ NULL
+ );
+ ASSERT (gStringPackHandle != NULL);
+}
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ )
+{
+ return HiiGetString (gStringPackHandle, Id, NULL);
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.h b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.h
new file mode 100644
index 0000000000..005b2bdbd2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/String.h
@@ -0,0 +1,65 @@
+/** @file
+ String support
+
+Copyright (c) 2004 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _STRING_H_
+#define _STRING_H_
+
+#include "Bds.h"
+
+extern EFI_HII_HANDLE gStringPackHandle;
+
+//
+// This is the VFR compiler generated header file which defines the
+// string identifiers.
+//
+
+extern UINT8 BdsDxeStrings[];
+
+/**
+ Get string by string id from HII Interface
+
+
+ @param Id String ID.
+
+ @retval CHAR16 * String from ID.
+ @retval NULL If error occurs.
+
+**/
+CHAR16 *
+GetStringById (
+ IN EFI_STRING_ID Id
+ );
+
+/**
+ Initialize HII global accessor for string support.
+
+**/
+VOID
+InitializeStringSupport (
+ VOID
+ );
+
+/**
+ Call the browser and display the front page
+
+ @return Status code that will be returned by
+ EFI_FORM_BROWSER2_PROTOCOL.SendForm ().
+
+**/
+EFI_STATUS
+CallFrontPage (
+ VOID
+ );
+
+#endif // _STRING_H_
diff --git a/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Strings.uni b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Strings.uni
new file mode 100644
index 0000000000..040ed92c36
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/BdsDxe/Strings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/ComponentName.c b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/ComponentName.c
new file mode 100644
index 0000000000..d637decb94
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/ComponentName.c
@@ -0,0 +1,167 @@
+/** @file
+ UEFI Component Name(2) protocol implementation for VGA Class Driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VgaClass.h"
+
+//
+// EFI Component Name Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME_PROTOCOL gVgaClassComponentName = {
+ VgaClassComponentNameGetDriverName,
+ VgaClassComponentNameGetControllerName,
+ "eng"
+};
+
+//
+// EFI Component Name 2 Protocol
+//
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_COMPONENT_NAME2_PROTOCOL gVgaClassComponentName2 = {
+ (EFI_COMPONENT_NAME2_GET_DRIVER_NAME) VgaClassComponentNameGetDriverName,
+ (EFI_COMPONENT_NAME2_GET_CONTROLLER_NAME) VgaClassComponentNameGetControllerName,
+ "en"
+};
+
+
+GLOBAL_REMOVE_IF_UNREFERENCED EFI_UNICODE_STRING_TABLE mVgaClassDriverNameTable[] = {
+ {
+ "eng;en",
+ L"VGA Class Driver"
+ },
+ {
+ NULL,
+ NULL
+ }
+};
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ )
+{
+ return LookupUnicodeString2 (
+ Language,
+ This->SupportedLanguages,
+ mVgaClassDriverNameTable,
+ DriverName,
+ (BOOLEAN)(This == &gVgaClassComponentName)
+ );
+}
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.c b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.c
new file mode 100644
index 0000000000..ca13989d5f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.c
@@ -0,0 +1,1288 @@
+/** @file
+ VGA Class Driver that managers VGA devices and produces Simple Text Output Protocol.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "VgaClass.h"
+
+//
+// EFI Driver Binding Protocol for the VGA Class Driver
+//
+EFI_DRIVER_BINDING_PROTOCOL gVgaClassDriverBinding = {
+ VgaClassDriverBindingSupported,
+ VgaClassDriverBindingStart,
+ VgaClassDriverBindingStop,
+ 0xa,
+ NULL,
+ NULL
+};
+
+//
+// Local variables
+//
+CHAR16 CrLfString[3] = { CHAR_CARRIAGE_RETURN, CHAR_LINEFEED, CHAR_NULL };
+
+//
+// This list is used to define the valid extend chars.
+// It also provides a mapping from Unicode to PCANSI or
+// ASCII. The ASCII mapping we just made up.
+//
+//
+UNICODE_TO_CHAR UnicodeToPcAnsiOrAscii[] = {
+ {
+ BOXDRAW_HORIZONTAL,
+ 0xc4,
+ L'-'
+ },
+ {
+ BOXDRAW_VERTICAL,
+ 0xb3,
+ L'|'
+ },
+ {
+ BOXDRAW_DOWN_RIGHT,
+ 0xda,
+ L'/'
+ },
+ {
+ BOXDRAW_DOWN_LEFT,
+ 0xbf,
+ L'\\'
+ },
+ {
+ BOXDRAW_UP_RIGHT,
+ 0xc0,
+ L'\\'
+ },
+ {
+ BOXDRAW_UP_LEFT,
+ 0xd9,
+ L'/'
+ },
+ {
+ BOXDRAW_VERTICAL_RIGHT,
+ 0xc3,
+ L'|'
+ },
+ {
+ BOXDRAW_VERTICAL_LEFT,
+ 0xb4,
+ L'|'
+ },
+ {
+ BOXDRAW_DOWN_HORIZONTAL,
+ 0xc2,
+ L'+'
+ },
+ {
+ BOXDRAW_UP_HORIZONTAL,
+ 0xc1,
+ L'+'
+ },
+ {
+ BOXDRAW_VERTICAL_HORIZONTAL,
+ 0xc5,
+ L'+'
+ },
+ {
+ BOXDRAW_DOUBLE_HORIZONTAL,
+ 0xcd,
+ L'-'
+ },
+ {
+ BOXDRAW_DOUBLE_VERTICAL,
+ 0xba,
+ L'|'
+ },
+ {
+ BOXDRAW_DOWN_RIGHT_DOUBLE,
+ 0xd5,
+ L'/'
+ },
+ {
+ BOXDRAW_DOWN_DOUBLE_RIGHT,
+ 0xd6,
+ L'/'
+ },
+ {
+ BOXDRAW_DOUBLE_DOWN_RIGHT,
+ 0xc9,
+ L'/'
+ },
+ {
+ BOXDRAW_DOWN_LEFT_DOUBLE,
+ 0xb8,
+ L'\\'
+ },
+ {
+ BOXDRAW_DOWN_DOUBLE_LEFT,
+ 0xb7,
+ L'\\'
+ },
+ {
+ BOXDRAW_DOUBLE_DOWN_LEFT,
+ 0xbb,
+ L'\\'
+ },
+ {
+ BOXDRAW_UP_RIGHT_DOUBLE,
+ 0xd4,
+ L'\\'
+ },
+ {
+ BOXDRAW_UP_DOUBLE_RIGHT,
+ 0xd3,
+ L'\\'
+ },
+ {
+ BOXDRAW_DOUBLE_UP_RIGHT,
+ 0xc8,
+ L'\\'
+ },
+ {
+ BOXDRAW_UP_LEFT_DOUBLE,
+ 0xbe,
+ L'/'
+ },
+ {
+ BOXDRAW_UP_DOUBLE_LEFT,
+ 0xbd,
+ L'/'
+ },
+ {
+ BOXDRAW_DOUBLE_UP_LEFT,
+ 0xbc,
+ L'/'
+ },
+ {
+ BOXDRAW_VERTICAL_RIGHT_DOUBLE,
+ 0xc6,
+ L'|'
+ },
+ {
+ BOXDRAW_VERTICAL_DOUBLE_RIGHT,
+ 0xc7,
+ L'|'
+ },
+ {
+ BOXDRAW_DOUBLE_VERTICAL_RIGHT,
+ 0xcc,
+ L'|'
+ },
+ {
+ BOXDRAW_VERTICAL_LEFT_DOUBLE,
+ 0xb5,
+ L'|'
+ },
+ {
+ BOXDRAW_VERTICAL_DOUBLE_LEFT,
+ 0xb6,
+ L'|'
+ },
+ {
+ BOXDRAW_DOUBLE_VERTICAL_LEFT,
+ 0xb9,
+ L'|'
+ },
+ {
+ BOXDRAW_DOWN_HORIZONTAL_DOUBLE,
+ 0xd1,
+ L'+'
+ },
+ {
+ BOXDRAW_DOWN_DOUBLE_HORIZONTAL,
+ 0xd2,
+ L'+'
+ },
+ {
+ BOXDRAW_DOUBLE_DOWN_HORIZONTAL,
+ 0xcb,
+ L'+'
+ },
+ {
+ BOXDRAW_UP_HORIZONTAL_DOUBLE,
+ 0xcf,
+ L'+'
+ },
+ {
+ BOXDRAW_UP_DOUBLE_HORIZONTAL,
+ 0xd0,
+ L'+'
+ },
+ {
+ BOXDRAW_DOUBLE_UP_HORIZONTAL,
+ 0xca,
+ L'+'
+ },
+ {
+ BOXDRAW_VERTICAL_HORIZONTAL_DOUBLE,
+ 0xd8,
+ L'+'
+ },
+ {
+ BOXDRAW_VERTICAL_DOUBLE_HORIZONTAL,
+ 0xd7,
+ L'+'
+ },
+ {
+ BOXDRAW_DOUBLE_VERTICAL_HORIZONTAL,
+ 0xce,
+ L'+'
+ },
+
+ {
+ BLOCKELEMENT_FULL_BLOCK,
+ 0xdb,
+ L'*'
+ },
+ {
+ BLOCKELEMENT_LIGHT_SHADE,
+ 0xb0,
+ L'+'
+ },
+
+ {
+ GEOMETRICSHAPE_UP_TRIANGLE,
+ 0x1e,
+ L'^'
+ },
+ {
+ GEOMETRICSHAPE_RIGHT_TRIANGLE,
+ 0x10,
+ L'>'
+ },
+ {
+ GEOMETRICSHAPE_DOWN_TRIANGLE,
+ 0x1f,
+ L'v'
+ },
+ {
+ GEOMETRICSHAPE_LEFT_TRIANGLE,
+ 0x11,
+ L'<'
+ },
+
+ {
+ ARROW_LEFT,
+ 0x3c,
+ L'<'
+ },
+
+ {
+ ARROW_UP,
+ 0x18,
+ L'^'
+ },
+
+ {
+ ARROW_RIGHT,
+ 0x3e,
+ L'>'
+ },
+
+ {
+ ARROW_DOWN,
+ 0x19,
+ L'v'
+ },
+
+ {
+ 0x0000,
+ 0x00,
+ 0x00
+ }
+};
+
+/**
+ Entrypoint of this VGA Class Driver.
+
+ This function is the entrypoint of this VGA Class Driver. It installs Driver Binding
+ Protocols together with Component Name Protocols.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeVgaClass(
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install driver model protocol(s).
+ //
+ Status = EfiLibInstallDriverBindingComponentName2 (
+ ImageHandle,
+ SystemTable,
+ &gVgaClassDriverBinding,
+ ImageHandle,
+ &gVgaClassComponentName,
+ &gVgaClassComponentName2
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Internal worker function to program CRTC register via PCI I/O Protocol.
+
+ @param VgaClassDev device instance object
+ @param Address Address of register to write
+ @param Data Data to write to register.
+
+**/
+VOID
+WriteCrtc (
+ IN VGA_CLASS_DEV *VgaClassDev,
+ IN UINT16 Address,
+ IN UINT8 Data
+ )
+{
+ VgaClassDev->PciIo->Io.Write (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthUint8,
+ VgaClassDev->VgaMiniPort->CrtcAddressRegisterBar,
+ VgaClassDev->VgaMiniPort->CrtcAddressRegisterOffset,
+ 1,
+ &Address
+ );
+
+ VgaClassDev->PciIo->Io.Write (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthUint8,
+ VgaClassDev->VgaMiniPort->CrtcDataRegisterBar,
+ VgaClassDev->VgaMiniPort->CrtcDataRegisterOffset,
+ 1,
+ &Data
+ );
+}
+
+/**
+ Internal worker function to set cursor's position to VgaClass device
+
+ @param VgaClassDev Private data structure for device instance.
+ @param Column Colomn of position to set cursor to.
+ @param Row Row of position to set cursor to.
+ @param MaxColumn Max value of column.
+
+**/
+VOID
+SetVideoCursorPosition (
+ IN VGA_CLASS_DEV *VgaClassDev,
+ IN UINTN Column,
+ IN UINTN Row,
+ IN UINTN MaxColumn
+ )
+{
+ Column = Column & 0xff;
+ Row = Row & 0xff;
+ MaxColumn = MaxColumn & 0xff;
+
+ WriteCrtc (
+ VgaClassDev,
+ CRTC_CURSOR_LOCATION_HIGH,
+ (UINT8) ((Row * MaxColumn + Column) >> 8)
+ );
+ WriteCrtc (
+ VgaClassDev,
+ CRTC_CURSOR_LOCATION_LOW,
+ (UINT8) ((Row * MaxColumn + Column) & 0xff)
+ );
+}
+
+/**
+ Internal worker function to detect if a Unicode char is for Box Drawing text graphics.
+
+ @param Graphic Unicode char to test.
+ @param PcAnsi Pointer to PCANSI equivalent of Graphic for output.
+ If NULL, then PCANSI value is not returned.
+ @param Ascii Pointer to ASCII equivalent of Graphic for output.
+ If NULL, then ASCII value is not returned.
+
+ @retval TRUE Gpaphic is a supported Unicode Box Drawing character.
+ @retval FALSE Gpaphic is not a supported Unicode Box Drawing character.
+
+**/
+BOOLEAN
+LibIsValidTextGraphics (
+ IN CHAR16 Graphic,
+ OUT CHAR8 *PcAnsi, OPTIONAL
+ OUT CHAR8 *Ascii OPTIONAL
+ )
+{
+ UNICODE_TO_CHAR *Table;
+
+ //
+ // Unicode drawing code charts are all in the 0x25xx range, arrows are 0x21xx.
+ // So first filter out values not in these 2 ranges.
+ //
+ if ((((Graphic & 0xff00) != 0x2500) && ((Graphic & 0xff00) != 0x2100))) {
+ return FALSE;
+ }
+
+ //
+ // Search UnicodeToPcAnsiOrAscii table for matching entry.
+ //
+ for (Table = UnicodeToPcAnsiOrAscii; Table->Unicode != 0x0000; Table++) {
+ if (Graphic == Table->Unicode) {
+ if (PcAnsi != NULL) {
+ *PcAnsi = Table->PcAnsi;
+ }
+
+ if (Ascii != NULL) {
+ *Ascii = Table->Ascii;
+ }
+
+ return TRUE;
+ }
+ }
+
+ //
+ // If value is not found in UnicodeToPcAnsiOrAscii table, then return FALSE.
+ //
+ return FALSE;
+}
+
+/**
+ Internal worker function to check whether input value is an ASCII char.
+
+ @param Char Character to check.
+
+ @retval TRUE Input value is an ASCII char.
+ @retval FALSE Input value is not an ASCII char.
+
+**/
+BOOLEAN
+IsValidAscii (
+ IN CHAR16 Char
+ )
+{
+ if ((Char >= 0x20) && (Char <= 0x7f)) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Internal worker function to check whether input value is a unicode control char.
+
+ @param Char Character to check.
+
+ @retval TRUE Input value is a unicode control char.
+ @retval FALSE Input value is not a unicode control char.
+
+**/
+BOOLEAN
+IsValidEfiCntlChar (
+ IN CHAR16 Char
+ )
+{
+ if (Char == CHAR_NULL || Char == CHAR_BACKSPACE || Char == CHAR_LINEFEED || Char == CHAR_CARRIAGE_RETURN) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+/**
+ Tests to see if this driver supports a given controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Supported().
+ It Checks if this driver supports the controller specified. Any Controller
+ with VgaMiniPort Protocol and Pci I/O protocol can be supported.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Checks if Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the IO Abstraction(s) needed to perform the supported test
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ NULL,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_TEST_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return Status;
+}
+
+/**
+ Starts the device controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Start().
+ It starts the device specified by Controller with the driver based on PCI I/O Protocol
+ and VgaMiniPort Protocol. It creates context for device instance and install EFI_SIMPLE_TEXT_OUT_PROTOCOL.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval other Fail to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ VGA_CLASS_DEV *VgaClassPrivate;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+
+ Status = gBS->HandleProtocol (
+ Controller,
+ &gEfiDevicePathProtocolGuid,
+ (VOID **) &DevicePath
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Report that VGA Class driver is being enabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_ENABLE,
+ DevicePath
+ );
+
+ //
+ // Open the PCI I/O Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ (VOID **) &PciIo,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Open the VGA Mini Port Protocol
+ //
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ (VOID **) &VgaMiniPort,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_BY_DRIVER
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Allocate the private device structure
+ //
+ VgaClassPrivate = AllocateZeroPool (sizeof (VGA_CLASS_DEV));
+ ASSERT (VgaClassPrivate != NULL);
+
+ //
+ // Initialize the private device structure
+ //
+ VgaClassPrivate->Signature = VGA_CLASS_DEV_SIGNATURE;
+ VgaClassPrivate->Handle = Controller;
+ VgaClassPrivate->VgaMiniPort = VgaMiniPort;
+ VgaClassPrivate->PciIo = PciIo;
+
+ VgaClassPrivate->SimpleTextOut.Reset = VgaClassReset;
+ VgaClassPrivate->SimpleTextOut.OutputString = VgaClassOutputString;
+ VgaClassPrivate->SimpleTextOut.TestString = VgaClassTestString;
+ VgaClassPrivate->SimpleTextOut.ClearScreen = VgaClassClearScreen;
+ VgaClassPrivate->SimpleTextOut.SetAttribute = VgaClassSetAttribute;
+ VgaClassPrivate->SimpleTextOut.SetCursorPosition = VgaClassSetCursorPosition;
+ VgaClassPrivate->SimpleTextOut.EnableCursor = VgaClassEnableCursor;
+ VgaClassPrivate->SimpleTextOut.QueryMode = VgaClassQueryMode;
+ VgaClassPrivate->SimpleTextOut.SetMode = VgaClassSetMode;
+
+ VgaClassPrivate->SimpleTextOut.Mode = &VgaClassPrivate->SimpleTextOutputMode;
+ VgaClassPrivate->SimpleTextOutputMode.MaxMode = VgaMiniPort->MaxMode;
+ VgaClassPrivate->DevicePath = DevicePath;
+
+ //
+ // Initialize the VGA device.
+ //
+ Status = VgaClassPrivate->SimpleTextOut.SetAttribute (
+ &VgaClassPrivate->SimpleTextOut,
+ EFI_TEXT_ATTR (EFI_WHITE, EFI_BLACK)
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = VgaClassPrivate->SimpleTextOut.Reset (
+ &VgaClassPrivate->SimpleTextOut,
+ FALSE
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = VgaClassPrivate->SimpleTextOut.EnableCursor (
+ &VgaClassPrivate->SimpleTextOut,
+ TRUE
+ );
+ if (EFI_ERROR (Status)) {
+ goto ErrorExit;
+ }
+
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &VgaClassPrivate->SimpleTextOut,
+ NULL
+ );
+
+ return Status;
+
+ErrorExit:
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_ERROR_CODE | EFI_ERROR_MINOR,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_EC_CONTROLLER_ERROR,
+ DevicePath
+ );
+
+ return Status;
+
+}
+
+/**
+ Starts the device controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Stop().
+ It stops this driver on Controller. Support stoping any child handles
+ created by this driver.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle A handle to the device being stopped.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ )
+{
+ EFI_STATUS Status;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *SimpleTextOut;
+ VGA_CLASS_DEV *VgaClassPrivate;
+
+ Status = gBS->OpenProtocol (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ (VOID **) &SimpleTextOut,
+ This->DriverBindingHandle,
+ Controller,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ VgaClassPrivate = VGA_CLASS_DEV_FROM_THIS (SimpleTextOut);
+
+ //
+ // Report that VGA Class driver is being disabled
+ //
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_DISABLE,
+ VgaClassPrivate->DevicePath
+ );
+
+ Status = gBS->UninstallProtocolInterface (
+ Controller,
+ &gEfiSimpleTextOutProtocolGuid,
+ &VgaClassPrivate->SimpleTextOut
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Release PCI I/O and VGA Mini Port Protocols on the controller handle.
+ //
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiPciIoProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ gBS->CloseProtocol (
+ Controller,
+ &gEfiVgaMiniPortProtocolGuid,
+ This->DriverBindingHandle,
+ Controller
+ );
+
+ FreePool (VgaClassPrivate);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Resets the text output device hardware.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+ It resets the text output device hardware. The cursor position is set to (0, 0),
+ and the screen is cleared to the default background color for the output device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ )
+{
+ EFI_STATUS Status;
+ VGA_CLASS_DEV *VgaClassPrivate;
+
+ VgaClassPrivate = VGA_CLASS_DEV_FROM_THIS (This);
+
+ REPORT_STATUS_CODE_WITH_DEVICE_PATH (
+ EFI_PROGRESS_CODE,
+ EFI_PERIPHERAL_LOCAL_CONSOLE | EFI_P_PC_RESET,
+ VgaClassPrivate->DevicePath
+ );
+
+ This->SetAttribute (This, EFI_TEXT_ATTR (This->Mode->Attribute & 0x0F, EFI_BACKGROUND_BLACK));
+
+ Status = This->SetMode (This, 0);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ return This->ClearScreen (This);
+}
+
+/**
+ Writes a Unicode string to the output device.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+ It writes a Unicode string to the output device. This is the most basic output mechanism
+ on an output device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param String The Null-terminated Unicode string to be displayed on the output device(s).
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the characters in
+ the Unicode string could not be rendered and were skipped.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ )
+{
+ EFI_STATUS Status;
+ VGA_CLASS_DEV *VgaClassDev;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE *Mode;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+ UINT32 VideoChar;
+ CHAR8 GraphicChar;
+
+ VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
+ Mode = This->Mode;
+
+ Status = This->QueryMode (
+ This,
+ Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Parse each character of the string to output
+ //
+ for (; *String != CHAR_NULL; String++) {
+
+ switch (*String) {
+ case CHAR_BACKSPACE:
+ if (Mode->CursorColumn > 0) {
+ Mode->CursorColumn--;
+ }
+ break;
+
+ case CHAR_LINEFEED:
+ if (Mode->CursorRow == (INT32) (MaxRow - 1)) {
+ //
+ // Scroll the screen by copying the contents
+ // of the VGA display up one line
+ //
+ VgaClassDev->PciIo->CopyMem (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthUint32,
+ VgaClassDev->VgaMiniPort->VgaMemoryBar,
+ VgaClassDev->VgaMiniPort->VgaMemoryOffset,
+ VgaClassDev->VgaMiniPort->VgaMemoryBar,
+ VgaClassDev->VgaMiniPort->VgaMemoryOffset + MaxColumn * 2,
+ ((MaxRow - 1) * MaxColumn) >> 1
+ );
+
+ //
+ // Print Blank Line of spaces with the current color attributes
+ //
+ VideoChar = (Mode->Attribute << 8) | ' ';
+ VideoChar = (VideoChar << 16) | VideoChar;
+ VgaClassDev->PciIo->Mem.Write (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthFillUint32,
+ VgaClassDev->VgaMiniPort->VgaMemoryBar,
+ VgaClassDev->VgaMiniPort->VgaMemoryOffset + (MaxRow - 1) * MaxColumn * 2,
+ MaxColumn >> 1,
+ &VideoChar
+ );
+ }
+
+ if (Mode->CursorRow < (INT32) (MaxRow - 1)) {
+ Mode->CursorRow++;
+ }
+ break;
+
+ case CHAR_CARRIAGE_RETURN:
+ Mode->CursorColumn = 0;
+ break;
+
+ default:
+ if (!LibIsValidTextGraphics (*String, &GraphicChar, NULL)) {
+ //
+ // If this character is not ,Box Drawing text graphics, then convert it to ASCII.
+ //
+ GraphicChar = (CHAR8) *String;
+ if (!IsValidAscii (GraphicChar)) {
+ //
+ // If not valid ASCII char, convert it to "?"
+ //
+ GraphicChar = '?';
+ }
+ }
+
+ VideoChar = (Mode->Attribute << 8) | GraphicChar;
+ VgaClassDev->PciIo->Mem.Write (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthUint16,
+ VgaClassDev->VgaMiniPort->VgaMemoryBar,
+ VgaClassDev->VgaMiniPort->VgaMemoryOffset + ((Mode->CursorRow * MaxColumn + Mode->CursorColumn) * 2),
+ 1,
+ &VideoChar
+ );
+
+ if (Mode->CursorColumn >= (INT32) (MaxColumn - 1)) {
+ This->OutputString (This, CrLfString);
+ } else {
+ Mode->CursorColumn++;
+ }
+ break;
+ }
+ }
+
+ SetVideoCursorPosition (
+ VgaClassDev,
+ (UINTN) Mode->CursorColumn,
+ (UINTN) Mode->CursorRow,
+ MaxColumn
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Verifies that all characters in a Unicode string can be output to the target device.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+ It verifies that all characters in a Unicode string can be output to the target device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param String The Null-terminated Unicode string to be examined for the output device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered by
+ one or more of the output devices mapped by the EFI handle.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ )
+{
+ while (*String != CHAR_NULL) {
+ if (!(IsValidAscii (*String) || IsValidEfiCntlChar (*String) || LibIsValidTextGraphics (*String, NULL, NULL))) {
+ return EFI_UNSUPPORTED;
+ }
+
+ String++;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Clears the output device(s) display to the currently selected background color.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ The ClearScreen() function clears the output device(s) display to the currently
+ selected background color. The cursor position is set to (0, 0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+
+ @retval EFI_SUCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ )
+{
+ EFI_STATUS Status;
+ VGA_CLASS_DEV *VgaClassDev;
+ UINTN MaxRow;
+ UINTN MaxColumn;
+ UINT32 VideoChar;
+
+ VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
+
+ Status = This->QueryMode (
+ This,
+ This->Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ VideoChar = (This->Mode->Attribute << 8) | ' ';
+ VideoChar = (VideoChar << 16) | VideoChar;
+ VgaClassDev->PciIo->Mem.Write (
+ VgaClassDev->PciIo,
+ EfiPciIoWidthFillUint32,
+ VgaClassDev->VgaMiniPort->VgaMemoryBar,
+ VgaClassDev->VgaMiniPort->VgaMemoryOffset,
+ (MaxRow * MaxColumn) >> 1,
+ &VideoChar
+ );
+
+ This->SetCursorPosition (This, 0, 0);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the background and foreground colors for theOutputString() and ClearScreen() functions.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+ It sets the background and foreground colors for the OutputString() and ClearScreen() functions.
+ The color mask can be set even when the device is in an invalid text mode.
+ Devices supporting a different number of text colors are required to emulate the above colors
+ to the best of the device's capabilities.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Attribute The attribute to set.
+ Bits 0..3 are the foreground color,
+ and bits 4..6 are the background color.
+
+ @retval EFI_SUCCESS The requested attributes were set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ )
+{
+ if (Attribute <= EFI_MAX_ATTRIBUTE) {
+ This->Mode->Attribute = (INT32) Attribute;
+ return EFI_SUCCESS;
+ }
+
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+ It sets the current coordinates of the cursor position.
+ The upper left corner of the screen is defined as coordinate (0, 0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Column Column of position to set the cursor to.
+ @param Row Row of position to set the cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the cursor
+ position is invalid for the current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ )
+{
+ EFI_STATUS Status;
+ VGA_CLASS_DEV *VgaClassDev;
+ UINTN MaxColumn;
+ UINTN MaxRow;
+
+ VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
+
+ Status = This->QueryMode (
+ This,
+ This->Mode->Mode,
+ &MaxColumn,
+ &MaxRow
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if (Column >= MaxColumn || Row >= MaxRow) {
+ return EFI_UNSUPPORTED;
+ }
+
+ SetVideoCursorPosition (VgaClassDev, Column, Row, MaxColumn);
+
+ This->Mode->CursorColumn = (INT32) Column;
+ This->Mode->CursorRow = (INT32) Row;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Makes the cursor visible or invisible.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.EnableCursor().
+ It makes the cursor visible or invisible.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Visible If TRUE, the cursor is set to be visible.
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request or the
+ device does not support changing the cursor mode.
+ @retval EFI_UNSUPPORTED The output device does not support visibility control of the cursor.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ )
+{
+ VGA_CLASS_DEV *VgaClassDev;
+
+ VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
+ if (Visible) {
+ if (This->Mode->Mode == 1) {
+ //
+ // 80 * 50
+ //
+ WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x06);
+ WriteCrtc (VgaClassDev, CRTC_CURSOR_END, 0x07);
+ } else {
+ //
+ // 80 * 25
+ //
+ WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x0e);
+ WriteCrtc (VgaClassDev, CRTC_CURSOR_END, 0x0f);
+ }
+ } else {
+ WriteCrtc (VgaClassDev, CRTC_CURSOR_START, 0x20);
+ }
+
+ This->Mode->CursorVisible = Visible;
+ return EFI_SUCCESS;
+}
+
+/**
+ Returns information for an available text mode that the output device(s) supports.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It returns information for an available text mode that the output device(s) supports.
+ It is required that all output devices support at least 80x25 text mode. This mode is defined to be mode 0.
+ If the output devices support 80x50, that is defined to be mode 1.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Columen in current mode number
+ @param Rows Row in current mode number.
+
+ @retval EFI_SUCCESS The requested mode information was returned.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ )
+{
+ if ((INT32) ModeNumber >= This->Mode->MaxMode) {
+ *Columns = 0;
+ *Rows = 0;
+ return EFI_UNSUPPORTED;
+ }
+
+ switch (ModeNumber) {
+ case 0:
+ *Columns = 80;
+ *Rows = 25;
+ break;
+
+ case 1:
+ *Columns = 80;
+ *Rows = 50;
+ break;
+
+ default:
+ *Columns = 0;
+ *Rows = 0;
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It sets the output device(s) to the requested mode.
+ On success the device is in the geometry for the requested mode,
+ and the device has been cleared to the current background color with the cursor at (0,0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ )
+{
+ VGA_CLASS_DEV *VgaClassDev;
+
+ VgaClassDev = VGA_CLASS_DEV_FROM_THIS (This);
+
+ if ((INT32) ModeNumber >= This->Mode->MaxMode) {
+ return EFI_UNSUPPORTED;
+ }
+
+ This->ClearScreen (This);
+
+ This->Mode->Mode = (INT32) ModeNumber;
+
+ return VgaClassDev->VgaMiniPort->SetMode (VgaClassDev->VgaMiniPort, ModeNumber);
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.h b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.h
new file mode 100644
index 0000000000..5cfa704001
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClass.h
@@ -0,0 +1,484 @@
+/** @file
+ Internal include file of the VGA Class Driver.
+
+Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+
+#ifndef _VGA_CLASS_H__
+#define _VGA_CLASS_H__
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/SimpleTextOut.h>
+#include <Protocol/PciIo.h>
+#include <Protocol/VgaMiniPort.h>
+#include <Protocol/DevicePath.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/ReportStatusCodeLib.h>
+
+#include <IndustryStandard/Pci.h>
+
+//
+// Global Variables
+//
+extern EFI_DRIVER_BINDING_PROTOCOL gVgaClassDriverBinding;
+extern EFI_COMPONENT_NAME_PROTOCOL gVgaClassComponentName;
+extern EFI_COMPONENT_NAME2_PROTOCOL gVgaClassComponentName2;
+
+
+//
+// Structure for tuple containing mapping among uniocde, PC Ansi and ASCII code.
+//
+typedef struct {
+ CHAR16 Unicode;
+ CHAR8 PcAnsi;
+ CHAR8 Ascii;
+} UNICODE_TO_CHAR;
+
+//
+// VGA specific registers
+//
+#define CRTC_CURSOR_START 0xA
+#define CRTC_CURSOR_END 0xB
+
+#define CRTC_CURSOR_LOCATION_HIGH 0xE
+#define CRTC_CURSOR_LOCATION_LOW 0xF
+
+#define EFI_MAX_ATTRIBUTE 0x7f
+
+//
+// VGA Class Device Structure
+//
+#define VGA_CLASS_DEV_SIGNATURE SIGNATURE_32 ('V', 'G', 'A', 'C')
+
+typedef struct {
+ UINTN Signature;
+ EFI_HANDLE Handle;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL SimpleTextOut;
+ EFI_SIMPLE_TEXT_OUTPUT_MODE SimpleTextOutputMode;
+ EFI_VGA_MINI_PORT_PROTOCOL *VgaMiniPort;
+ EFI_PCI_IO_PROTOCOL *PciIo;
+ EFI_DEVICE_PATH_PROTOCOL *DevicePath;
+} VGA_CLASS_DEV;
+
+#define VGA_CLASS_DEV_FROM_THIS(a) CR (a, VGA_CLASS_DEV, SimpleTextOut, VGA_CLASS_DEV_SIGNATURE)
+
+//
+// Driver Binding Protocol functions
+//
+
+/**
+ Tests to see if this driver supports a given controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Supported().
+ It Checks if this driver supports the controller specified. Any Controller
+ with VgaMiniPort Protocol and Pci I/O protocol can be supported.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle Handle of device to test
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS This driver supports this device.
+ @retval EFI_ALREADY_STARTED This driver is already running on this device.
+ @retval EFI_UNSUPPORTED This driver does not support this device.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingSupported (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts the device controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Start().
+ It starts the device specified by Controller with the driver based on PCI I/O Protocol
+ and VgaMiniPort Protocol. It creates context for device instance and install EFI_SIMPLE_TEXT_OUT_PROTOCOL.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle Handle of device to bind driver to
+ @param RemainingDevicePath Optional parameter use to pick a specific child
+ device to start.
+
+ @retval EFI_SUCCESS The device was started.
+ @retval other Fail to start the device.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingStart (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN EFI_DEVICE_PATH_PROTOCOL *RemainingDevicePath OPTIONAL
+ );
+
+/**
+ Starts the device controller.
+
+ This function implments EFI_DRIVER_BINDING_PROTOCOL.Stop().
+ It stops this driver on Controller. Support stoping any child handles
+ created by this driver.
+
+ @param This A pointer to the EFI_DRIVER_BINDING_PROTOCOL instance.
+ @param ControllerHandle A handle to the device being stopped.
+ @param NumberOfChildren The number of child device handles in ChildHandleBuffer.
+ @param ChildHandleBuffer An array of child handles to be freed.
+
+ @retval EFI_SUCCESS This driver is removed ControllerHandle
+ @retval other This driver was not removed from this device
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassDriverBindingStop (
+ IN EFI_DRIVER_BINDING_PROTOCOL *This,
+ IN EFI_HANDLE Controller,
+ IN UINTN NumberOfChildren,
+ IN EFI_HANDLE *ChildHandleBuffer OPTIONAL
+ );
+
+//
+// EFI Component Name Functions
+//
+
+/**
+ Retrieves a Unicode string that is the user readable name of the driver.
+
+ This function retrieves the user readable name of a driver in the form of a
+ Unicode string. If the driver specified by This has a user readable name in
+ the language specified by Language, then a pointer to the driver name is
+ returned in DriverName, and EFI_SUCCESS is returned. If the driver specified
+ by This does not support the language specified by Language,
+ then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified
+ in RFC 4646 or ISO 639-2 language code format.
+ @param DriverName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ driver specified by This in the language
+ specified by Language.
+
+ @retval EFI_SUCCESS The Unicode string for the Driver specified by
+ This and the language specified by Language was
+ returned in DriverName.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER DriverName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassComponentNameGetDriverName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN CHAR8 *Language,
+ OUT CHAR16 **DriverName
+ );
+
+/**
+ Retrieves a Unicode string that is the user readable name of the controller
+ that is being managed by a driver.
+
+ This function retrieves the user readable name of the controller specified by
+ ControllerHandle and ChildHandle in the form of a Unicode string. If the
+ driver specified by This has a user readable name in the language specified by
+ Language, then a pointer to the controller name is returned in ControllerName,
+ and EFI_SUCCESS is returned. If the driver specified by This is not currently
+ managing the controller specified by ControllerHandle and ChildHandle,
+ then EFI_UNSUPPORTED is returned. If the driver specified by This does not
+ support the language specified by Language, then EFI_UNSUPPORTED is returned.
+
+ @param This A pointer to the EFI_COMPONENT_NAME2_PROTOCOL or
+ EFI_COMPONENT_NAME_PROTOCOL instance.
+ @param ControllerHandle The handle of a controller that the driver
+ specified by This is managing. This handle
+ specifies the controller whose name is to be
+ returned.
+ @param ChildHandle The handle of the child controller to retrieve
+ the name of. This is an optional parameter that
+ may be NULL. It will be NULL for device
+ drivers. It will also be NULL for a bus drivers
+ that wish to retrieve the name of the bus
+ controller. It will not be NULL for a bus
+ driver that wishes to retrieve the name of a
+ child controller.
+ @param Language A pointer to a Null-terminated ASCII string
+ array indicating the language. This is the
+ language of the driver name that the caller is
+ requesting, and it must match one of the
+ languages specified in SupportedLanguages. The
+ number of languages supported by a driver is up
+ to the driver writer. Language is specified in
+ RFC 4646 or ISO 639-2 language code format.
+ @param ControllerName A pointer to the Unicode string to return.
+ This Unicode string is the name of the
+ controller specified by ControllerHandle and
+ ChildHandle in the language specified by
+ Language from the point of view of the driver
+ specified by This.
+
+ @retval EFI_SUCCESS The Unicode string for the user readable name in
+ the language specified by Language for the
+ driver specified by This was returned in
+ DriverName.
+ @retval EFI_INVALID_PARAMETER ControllerHandle is NULL.
+ @retval EFI_INVALID_PARAMETER ChildHandle is not NULL and it is not a valid
+ EFI_HANDLE.
+ @retval EFI_INVALID_PARAMETER Language is NULL.
+ @retval EFI_INVALID_PARAMETER ControllerName is NULL.
+ @retval EFI_UNSUPPORTED The driver specified by This is not currently
+ managing the controller specified by
+ ControllerHandle and ChildHandle.
+ @retval EFI_UNSUPPORTED The driver specified by This does not support
+ the language specified by Language.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassComponentNameGetControllerName (
+ IN EFI_COMPONENT_NAME_PROTOCOL *This,
+ IN EFI_HANDLE ControllerHandle,
+ IN EFI_HANDLE ChildHandle OPTIONAL,
+ IN CHAR8 *Language,
+ OUT CHAR16 **ControllerName
+ );
+
+//
+// Simple Text Output Protocol functions
+//
+/**
+ Resets the text output device hardware.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.Reset().
+ It resets the text output device hardware. The cursor position is set to (0, 0),
+ and the screen is cleared to the default background color for the output device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ExtendedVerification Indicates that the driver may perform a more exhaustive
+ verification operation of the device during reset.
+
+ @retval EFI_SUCCESS The text output device was reset.
+ @retval EFI_DEVICE_ERROR The text output device is not functioning correctly and could not be reset.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassReset (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN ExtendedVerification
+ );
+
+/**
+ Writes a Unicode string to the output device.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.OutputString().
+ It writes a Unicode string to the output device. This is the most basic output mechanism
+ on an output device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param String The Null-terminated Unicode string to be displayed on the output device(s).
+
+ @retval EFI_SUCCESS The string was output to the device.
+ @retval EFI_DEVICE_ERROR The device reported an error while attempting to output the text.
+ @retval EFI_UNSUPPORTED The output device's mode is not currently in a defined text mode.
+ @retval EFI_WARN_UNKNOWN_GLYPH This warning code indicates that some of the characters in
+ the Unicode string could not be rendered and were skipped.
+**/
+EFI_STATUS
+EFIAPI
+VgaClassOutputString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Verifies that all characters in a Unicode string can be output to the target device.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.TestString().
+ It verifies that all characters in a Unicode string can be output to the target device.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param String The Null-terminated Unicode string to be examined for the output device(s).
+
+ @retval EFI_SUCCESS The device(s) are capable of rendering the output string.
+ @retval EFI_UNSUPPORTED Some of the characters in the Unicode string cannot be rendered by
+ one or more of the output devices mapped by the EFI handle.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassTestString (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN CHAR16 *String
+ );
+
+/**
+ Clears the output device(s) display to the currently selected background color.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.ClearScreen().
+ The ClearScreen() function clears the output device(s) display to the currently
+ selected background color. The cursor position is set to (0, 0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+
+ @retval EFI_SUCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassClearScreen (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This
+ );
+
+/**
+ Sets the background and foreground colors for theOutputString() and ClearScreen() functions.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetAttribute().
+ It sets the background and foreground colors for the OutputString() and ClearScreen() functions.
+ The color mask can be set even when the device is in an invalid text mode.
+ Devices supporting a different number of text colors are required to emulate the above colors
+ to the best of the device's capabilities.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Attribute The attribute to set.
+ Bits 0..3 are the foreground color,
+ and bits 4..6 are the background color.
+
+ @retval EFI_SUCCESS The requested attributes were set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetAttribute (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Attribute
+ );
+
+/**
+ Sets the current coordinates of the cursor position.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.SetCursorPosition().
+ It sets the current coordinates of the cursor position.
+ The upper left corner of the screen is defined as coordinate (0, 0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Column Column of position to set the cursor to.
+ @param Row Row of position to set the cursor to.
+
+ @retval EFI_SUCCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The output device is not in a valid text mode, or the cursor
+ position is invalid for the current mode.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetCursorPosition (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN Column,
+ IN UINTN Row
+ );
+
+/**
+ Makes the cursor visible or invisible.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.EnableCursor().
+ It makes the cursor visible or invisible.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param Visible If TRUE, the cursor is set to be visible.
+ If FALSE, the cursor is set to be invisible.
+
+ @retval EFI_SUCESS The operation completed successfully.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request or the
+ device does not support changing the cursor mode.
+ @retval EFI_UNSUPPORTED The output device does not support visibility control of the cursor.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassEnableCursor (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN BOOLEAN Visible
+ );
+
+/**
+ Returns information for an available text mode that the output device(s) supports.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It returns information for an available text mode that the output device(s) supports.
+ It is required that all output devices support at least 80x25 text mode. This mode is defined to be mode 0.
+ If the output devices support 80x50, that is defined to be mode 1.
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The mode number to return information on.
+ @param Columns Columen in current mode number
+ @param Rows Row in current mode number.
+
+ @retval EFI_SUCCESS The requested mode information was returned.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassQueryMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber,
+ OUT UINTN *Columns,
+ OUT UINTN *Rows
+ );
+
+/**
+ Sets the output device(s) to a specified mode.
+
+ This function implements EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL.QueryMode().
+ It sets the output device(s) to the requested mode.
+ On success the device is in the geometry for the requested mode,
+ and the device has been cleared to the current background color with the cursor at (0,0).
+
+ @param This Pointer to EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL instance.
+ @param ModeNumber The text mode to set.
+
+ @retval EFI_SUCCESS The requested text mode was set.
+ @retval EFI_DEVICE_ERROR The device had an error and could not complete the request.
+ @retval EFI_UNSUPPORTED The mode number was not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+VgaClassSetMode (
+ IN EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *This,
+ IN UINTN ModeNumber
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf
new file mode 100644
index 0000000000..2faba9d6f7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.inf
@@ -0,0 +1,64 @@
+## @file
+# VGA Class Driver that managers VGA devices and produces Simple Text Output Protocol.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = VgaClassDxe
+ MODULE_UNI_FILE = VgaClassDxe.uni
+ FILE_GUID = BF89F10D-B205-474f-96E3-7A7BB1B4A407
+ MODULE_TYPE = UEFI_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeVgaClass
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+# DRIVER_BINDING = gVgaClassDriverBinding
+# COMPONENT_NAME = gVgaClassComponentName
+# COMPONENT_NAME2 = gVgaClassComponentName2
+#
+
+[Sources]
+ ComponentName.c
+ VgaClass.h
+ VgaClass.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+
+[LibraryClasses]
+ ReportStatusCodeLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Protocols]
+ gEfiSimpleTextOutProtocolGuid ## BY_START
+ gEfiVgaMiniPortProtocolGuid ## TO_START
+ gEfiPciIoProtocolGuid ## TO_START
+ gEfiDevicePathProtocolGuid ## TO_START
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ VgaClassDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.uni b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.uni
new file mode 100644
index 0000000000..23bb5c3693
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxeExtra.uni
new file mode 100644
index 0000000000..4c0cda97c0
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/Console/VgaClassDxe/VgaClassDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.c b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.c
new file mode 100644
index 0000000000..e48b6382ff
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.c
@@ -0,0 +1,536 @@
+/** @file
+ Uses the services of the I/O Library to produce the CPU I/O Protocol
+
+Copyright (c) 2004 - 2012, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "CpuIo.h"
+
+//
+// Handle for the CPU I/O Protocol
+//
+EFI_HANDLE mHandle = NULL;
+
+//
+// CPU I/O Protocol inatance
+//
+EFI_CPU_IO_PROTOCOL mCpuIo = {
+ {
+ CpuMemoryServiceRead,
+ CpuMemoryServiceWrite
+ },
+ {
+ CpuIoServiceRead,
+ CpuIoServiceWrite
+ }
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mInStride[] = {
+ 1, // EfiCpuIoWidthUint8
+ 2, // EfiCpuIoWidthUint16
+ 4, // EfiCpuIoWidthUint32
+ 8, // EfiCpuIoWidthUint64
+ 0, // EfiCpuIoWidthFifoUint8
+ 0, // EfiCpuIoWidthFifoUint16
+ 0, // EfiCpuIoWidthFifoUint32
+ 0, // EfiCpuIoWidthFifoUint64
+ 1, // EfiCpuIoWidthFillUint8
+ 2, // EfiCpuIoWidthFillUint16
+ 4, // EfiCpuIoWidthFillUint32
+ 8 // EfiCpuIoWidthFillUint64
+};
+
+//
+// Lookup table for increment values based on transfer widths
+//
+UINT8 mOutStride[] = {
+ 1, // EfiCpuIoWidthUint8
+ 2, // EfiCpuIoWidthUint16
+ 4, // EfiCpuIoWidthUint32
+ 8, // EfiCpuIoWidthUint64
+ 1, // EfiCpuIoWidthFifoUint8
+ 2, // EfiCpuIoWidthFifoUint16
+ 4, // EfiCpuIoWidthFifoUint32
+ 8, // EfiCpuIoWidthFifoUint64
+ 0, // EfiCpuIoWidthFillUint8
+ 0, // EfiCpuIoWidthFillUint16
+ 0, // EfiCpuIoWidthFillUint32
+ 0 // EfiCpuIoWidthFillUint64
+};
+
+/**
+ Check parameters to a CPU I/O Protocol service request.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ @param[in] MmioOperation TRUE for an MMIO operation, FALSE for I/O Port operation.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The parameters for this request pass the checks.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+CpuIoCheckParameter (
+ IN BOOLEAN MmioOperation,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ UINT64 MaxCount;
+ UINT64 Limit;
+
+ //
+ // Check to see if Buffer is NULL
+ //
+ if (Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Width is in the valid range
+ //
+ if ((UINT32)Width >= EfiCpuIoWidthMaximum) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // For FIFO type, the target address won't increase during the access,
+ // so treat Count as 1
+ //
+ if (Width >= EfiCpuIoWidthFifoUint8 && Width <= EfiCpuIoWidthFifoUint64) {
+ Count = 1;
+ }
+
+ //
+ // Check to see if Width is in the valid range for I/O Port operations
+ //
+ Width = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ if (!MmioOperation && (Width == EfiCpuIoWidthUint64)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see if Address is aligned
+ //
+ if ((Address & (UINT64)(mInStride[Width] - 1)) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ //
+ // Check to see if any address associated with this transfer exceeds the maximum
+ // allowed address. The maximum address implied by the parameters passed in is
+ // Address + Size * Count. If the following condition is met, then the transfer
+ // is not supported.
+ //
+ // Address + Size * Count > (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS) + 1
+ //
+ // Since MAX_ADDRESS can be the maximum integer value supported by the CPU and Count
+ // can also be the maximum integer value supported by the CPU, this range
+ // check must be adjusted to avoid all overflow conditions.
+ //
+ // The following form of the range check is equivalent but assumes that
+ // MAX_ADDRESS and MAX_IO_PORT_ADDRESS are of the form (2^n - 1).
+ //
+ Limit = (MmioOperation ? MAX_ADDRESS : MAX_IO_PORT_ADDRESS);
+ if (Count == 0) {
+ if (Address > Limit) {
+ return EFI_UNSUPPORTED;
+ }
+ } else {
+ MaxCount = RShiftU64 (Limit, Width);
+ if (MaxCount < (Count - 1)) {
+ return EFI_UNSUPPORTED;
+ }
+ if (Address > LShiftU64 (MaxCount - Count + 1, Width)) {
+ return EFI_UNSUPPORTED;
+ }
+ }
+
+ //
+ // Check to see if Buffer is aligned
+ // (IA-32 allows UINT64 and INT64 data types to be 32-bit aligned.)
+ //
+ if (((UINTN)Buffer & ((MIN (sizeof (UINTN), mInStride[Width]) - 1))) != 0) {
+ return EFI_UNSUPPORTED;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ *Uint8Buffer = MmioRead8 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ *((UINT16 *)Uint8Buffer) = MmioRead16 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ *((UINT32 *)Uint8Buffer) = MmioRead32 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint64) {
+ *((UINT64 *)Uint8Buffer) = MmioRead64 ((UINTN)Address);
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ Status = CpuIoCheckParameter (TRUE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ MmioWrite8 ((UINTN)Address, *Uint8Buffer);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ MmioWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ MmioWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint64) {
+ MmioWrite64 ((UINTN)Address, *((UINT64 *)Uint8Buffer));
+ }
+ }
+ return EFI_SUCCESS;
+}
+
+/**
+ Reads I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ *Uint8Buffer = IoRead8 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ *((UINT16 *)Uint8Buffer) = IoRead16 ((UINTN)Address);
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ *((UINT32 *)Uint8Buffer) = IoRead32 ((UINTN)Address);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINT8 InStride;
+ UINT8 OutStride;
+ EFI_CPU_IO_PROTOCOL_WIDTH OperationWidth;
+ UINT8 *Uint8Buffer;
+
+ //
+ // Make sure the parameters are valid
+ //
+ Status = CpuIoCheckParameter (FALSE, Width, Address, Count, Buffer);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Select loop based on the width of the transfer
+ //
+ InStride = mInStride[Width];
+ OutStride = mOutStride[Width];
+ OperationWidth = (EFI_CPU_IO_PROTOCOL_WIDTH) (Width & 0x03);
+ for (Uint8Buffer = (UINT8 *)Buffer; Count > 0; Address += InStride, Uint8Buffer += OutStride, Count--) {
+ if (OperationWidth == EfiCpuIoWidthUint8) {
+ IoWrite8 ((UINTN)Address, *Uint8Buffer);
+ } else if (OperationWidth == EfiCpuIoWidthUint16) {
+ IoWrite16 ((UINTN)Address, *((UINT16 *)Uint8Buffer));
+ } else if (OperationWidth == EfiCpuIoWidthUint32) {
+ IoWrite32 ((UINTN)Address, *((UINT32 *)Uint8Buffer));
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ The user Entry Point for module CpuIo. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiCpuIoProtocolGuid);
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiCpuIoProtocolGuid, &mCpuIo,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.h b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.h
new file mode 100644
index 0000000000..6eba9c09e7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIo.h
@@ -0,0 +1,226 @@
+/** @file
+ Internal include file of CPU I/O DXE Driver.
+
+ Copyright (c) 2004 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __CPU_IO_DXE_H__
+#define __CPU_IO_DXE_H__
+
+
+#include <PiDxe.h>
+
+#include <Protocol/CpuIo.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/IoLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define MAX_IO_PORT_ADDRESS 0xFFFF
+
+/**
+ Reads memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceRead (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Writes memory-mapped registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuMemoryServiceWrite (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+/**
+ Reads I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[out] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceRead (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ OUT VOID *Buffer
+ );
+
+/**
+ Write I/O registers.
+
+ The I/O operations are carried out exactly as requested. The caller is responsible
+ for satisfying any alignment and I/O width restrictions that a PI System on a
+ platform might require. For example on some platforms, width requests of
+ EfiCpuIoWidthUint64 do not work. Misaligned buffers, on the other hand, will
+ be handled by the driver.
+
+ If Width is EfiCpuIoWidthUint8, EfiCpuIoWidthUint16, EfiCpuIoWidthUint32,
+ or EfiCpuIoWidthUint64, then both Address and Buffer are incremented for
+ each of the Count operations that is performed.
+
+ If Width is EfiCpuIoWidthFifoUint8, EfiCpuIoWidthFifoUint16,
+ EfiCpuIoWidthFifoUint32, or EfiCpuIoWidthFifoUint64, then only Buffer is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times on the same Address.
+
+ If Width is EfiCpuIoWidthFillUint8, EfiCpuIoWidthFillUint16,
+ EfiCpuIoWidthFillUint32, or EfiCpuIoWidthFillUint64, then only Address is
+ incremented for each of the Count operations that is performed. The read or
+ write operation is performed Count times from the first element of Buffer.
+
+ @param[in] This A pointer to the EFI_CPU_IO_PROTOCOL instance.
+ @param[in] Width Signifies the width of the I/O or Memory operation.
+ @param[in] Address The base address of the I/O operation.
+ @param[in] Count The number of I/O operations to perform. The number of
+ bytes moved is Width size * Count, starting at Address.
+ @param[in] Buffer For read operations, the destination buffer to store the results.
+ For write operations, the source buffer from which to write data.
+
+ @retval EFI_SUCCESS The data was read from or written to the PI system.
+ @retval EFI_INVALID_PARAMETER Width is invalid for this PI system.
+ @retval EFI_INVALID_PARAMETER Buffer is NULL.
+ @retval EFI_UNSUPPORTED The Buffer is not aligned for the given Width.
+ @retval EFI_UNSUPPORTED The address range specified by Address, Width,
+ and Count is not valid for this PI system.
+
+**/
+EFI_STATUS
+EFIAPI
+CpuIoServiceWrite (
+ IN EFI_CPU_IO_PROTOCOL *This,
+ IN EFI_CPU_IO_PROTOCOL_WIDTH Width,
+ IN UINT64 Address,
+ IN UINTN Count,
+ IN VOID *Buffer
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf
new file mode 100644
index 0000000000..368fa75bbb
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.inf
@@ -0,0 +1,51 @@
+## @file
+# Module that produces the Framework CPU I/O Protocol using the services of the I/O Library
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = CpuIoDxe
+ MODULE_UNI_FILE = CpuIoDxe.uni
+ FILE_GUID = BAE7599F-3C6B-43b7-BDF0-9CE07AA91AA6
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = CpuIoInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64
+#
+
+[Sources]
+ CpuIo.c
+ CpuIo.h
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ BaseLib
+ DebugLib
+ IoLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiCpuIoProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ CpuIoDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.uni b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.uni
new file mode 100644
index 0000000000..68fa4ec31a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxeExtra.uni
new file mode 100644
index 0000000000..6bc7525414
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/CpuIoDxe/CpuIoDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.c b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.c
new file mode 100644
index 0000000000..91f7c7ecf9
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.c
@@ -0,0 +1,587 @@
+/** @file
+ This code produces the Data Hub protocol. It preloads the data hub
+ with status information copied in from PEI HOBs.
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DataHub.h"
+
+//
+// Since this driver will only ever produce one instance of the Logging Hub
+// protocol you are not required to dynamically allocate the PrivateData.
+//
+DATA_HUB_INSTANCE mPrivateData;
+
+/**
+ Log data record into the data logging hub
+
+ @param This Protocol instance structure
+ @param DataRecordGuid GUID that defines record contents
+ @param ProducerName GUID that defines the name of the producer of the data
+ @param DataRecordClass Class that defines generic record type
+ @param RawData Data Log record as defined by DataRecordGuid
+ @param RawDataSize Size of Data Log data in bytes
+
+ @retval EFI_SUCCESS If data was logged
+ @retval EFI_OUT_OF_RESOURCES If data was not logged due to lack of system
+ resources.
+**/
+EFI_STATUS
+EFIAPI
+DataHubLogData (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_GUID *DataRecordGuid,
+ IN EFI_GUID *ProducerName,
+ IN UINT64 DataRecordClass,
+ IN VOID *RawData,
+ IN UINT32 RawDataSize
+ )
+{
+ EFI_STATUS Status;
+ DATA_HUB_INSTANCE *Private;
+ EFI_DATA_ENTRY *LogEntry;
+ UINT32 TotalSize;
+ UINT32 RecordSize;
+ EFI_DATA_RECORD_HEADER *Record;
+ VOID *Raw;
+ DATA_HUB_FILTER_DRIVER *FilterEntry;
+ LIST_ENTRY *Link;
+ LIST_ENTRY *Head;
+ EFI_TIME LogTime;
+
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);
+
+ //
+ // Combine the storage for the internal structs and a copy of the log record.
+ // Record follows PrivateLogEntry. The consumer will be returned a pointer
+ // to Record so we don't what it to be the thing that was allocated from
+ // pool, so the consumer can't free an data record by mistake.
+ //
+ RecordSize = sizeof (EFI_DATA_RECORD_HEADER) + RawDataSize;
+ TotalSize = sizeof (EFI_DATA_ENTRY) + RecordSize;
+
+ //
+ // First try to get log time at TPL level <= TPL_CALLBACK.
+ //
+ ZeroMem (&LogTime, sizeof (LogTime));
+ if (EfiGetCurrentTpl() <= TPL_CALLBACK) {
+ gRT->GetTime (&LogTime, NULL);
+ }
+
+ //
+ // The Logging action is the critical section, so it is locked.
+ // The MTC asignment & update and logging must be an
+ // atomic operation, so use the lock.
+ //
+ Status = EfiAcquireLockOrFail (&Private->DataLock);
+ if (EFI_ERROR (Status)) {
+ //
+ // Reentrancy detected so exit!
+ //
+ return Status;
+ }
+
+ LogEntry = AllocatePool (TotalSize);
+
+ if (LogEntry == NULL) {
+ EfiReleaseLock (&Private->DataLock);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ ZeroMem (LogEntry, TotalSize);
+
+ Record = (EFI_DATA_RECORD_HEADER *) (LogEntry + 1);
+ Raw = (VOID *) (Record + 1);
+
+ //
+ // Build Standard Log Header
+ //
+ Record->Version = EFI_DATA_RECORD_HEADER_VERSION;
+ Record->HeaderSize = (UINT16) sizeof (EFI_DATA_RECORD_HEADER);
+ Record->RecordSize = RecordSize;
+ CopyMem (&Record->DataRecordGuid, DataRecordGuid, sizeof (EFI_GUID));
+ CopyMem (&Record->ProducerName, ProducerName, sizeof (EFI_GUID));
+ Record->DataRecordClass = DataRecordClass;
+
+ //
+ // Ensure LogMonotonicCount is not zero
+ //
+ Record->LogMonotonicCount = ++Private->GlobalMonotonicCount;
+
+ CopyMem (&Record->LogTime, &LogTime, sizeof (LogTime));
+
+ //
+ // Insert log into the internal linked list.
+ //
+ LogEntry->Signature = EFI_DATA_ENTRY_SIGNATURE;
+ LogEntry->Record = Record;
+ LogEntry->RecordSize = sizeof (EFI_DATA_ENTRY) + RawDataSize;
+ InsertTailList (&Private->DataListHead, &LogEntry->Link);
+
+ CopyMem (Raw, RawData, RawDataSize);
+
+ EfiReleaseLock (&Private->DataLock);
+
+ //
+ // Send Signal to all the filter drivers which are interested
+ // in the record's class and guid.
+ //
+ Head = &Private->FilterDriverListHead;
+ for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) {
+ FilterEntry = FILTER_ENTRY_FROM_LINK (Link);
+ if (((FilterEntry->ClassFilter & DataRecordClass) != 0) &&
+ (CompareGuid (&FilterEntry->FilterDataRecordGuid, &gZeroGuid) ||
+ CompareGuid (&FilterEntry->FilterDataRecordGuid, DataRecordGuid))) {
+ gBS->SignalEvent (FilterEntry->Event);
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Search the Head doubly linked list for the passed in MTC. Return the
+ matching element in Head and the MTC on the next entry.
+
+ @param Head Head of Data Log linked list.
+ @param ClassFilter Only match the MTC if it is in the same Class as the
+ ClassFilter.
+ @param PtrCurrentMTC On IN contians MTC to search for. On OUT contians next
+ MTC in the data log list or zero if at end of the list.
+
+ @retval EFI_DATA_LOG_ENTRY Return pointer to data log data from Head list.
+ @retval NULL If no data record exists.
+
+**/
+EFI_DATA_RECORD_HEADER *
+GetNextDataRecord (
+ IN LIST_ENTRY *Head,
+ IN UINT64 ClassFilter,
+ IN OUT UINT64 *PtrCurrentMTC
+ )
+
+{
+ EFI_DATA_ENTRY *LogEntry;
+ LIST_ENTRY *Link;
+ BOOLEAN ReturnFirstEntry;
+ EFI_DATA_RECORD_HEADER *Record;
+ EFI_DATA_ENTRY *NextLogEntry;
+
+ //
+ // If MonotonicCount == 0 just return the first one
+ //
+ ReturnFirstEntry = (BOOLEAN) (*PtrCurrentMTC == 0);
+
+ Record = NULL;
+ for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) {
+ LogEntry = DATA_ENTRY_FROM_LINK (Link);
+ if ((LogEntry->Record->DataRecordClass & ClassFilter) == 0) {
+ //
+ // Skip any entry that does not have the correct ClassFilter
+ //
+ continue;
+ }
+
+ if ((LogEntry->Record->LogMonotonicCount == *PtrCurrentMTC) || ReturnFirstEntry) {
+ //
+ // Return record to the user
+ //
+ Record = LogEntry->Record;
+
+ //
+ // Calculate the next MTC value. If there is no next entry set
+ // MTC to zero.
+ //
+ *PtrCurrentMTC = 0;
+ for (Link = GetNextNode(Head, Link); Link != Head; Link = GetNextNode(Head, Link)) {
+ NextLogEntry = DATA_ENTRY_FROM_LINK (Link);
+ if ((NextLogEntry->Record->DataRecordClass & ClassFilter) != 0) {
+ //
+ // Return the MTC of the next thing to search for if found
+ //
+ *PtrCurrentMTC = NextLogEntry->Record->LogMonotonicCount;
+ break;
+ }
+ }
+ //
+ // Record found exit loop and return
+ //
+ break;
+ }
+ }
+
+ return Record;
+}
+
+/**
+ Search the Head list for a EFI_DATA_HUB_FILTER_DRIVER member that
+ represents Event and return it.
+
+ @param Head Pointer to head of dual linked list of EFI_DATA_HUB_FILTER_DRIVER structures.
+ @param Event Event to be search for in the Head list.
+
+ @retval EFI_DATA_HUB_FILTER_DRIVER Returned if Event stored in the Head doubly linked list.
+ @retval NULL If Event is not in the list
+
+**/
+DATA_HUB_FILTER_DRIVER *
+FindFilterDriverByEvent (
+ IN LIST_ENTRY *Head,
+ IN EFI_EVENT Event
+ )
+{
+ DATA_HUB_FILTER_DRIVER *FilterEntry;
+ LIST_ENTRY *Link;
+
+ for (Link = GetFirstNode(Head); Link != Head; Link = GetNextNode(Head, Link)) {
+ FilterEntry = FILTER_ENTRY_FROM_LINK (Link);
+ if (FilterEntry->Event == Event) {
+ return FilterEntry;
+ }
+ }
+
+ return NULL;
+}
+
+/**
+
+ Get a previously logged data record and the MonotonicCount for the next
+ availible Record. This allows all records or all records later
+ than a give MonotonicCount to be returned. If an optional FilterDriverEvent
+ is passed in with a MonotonicCout of zero return the first record
+ not yet read by the filter driver. If FilterDriverEvent is NULL and
+ MonotonicCount is zero return the first data record.
+
+ @param This Pointer to the EFI_DATA_HUB_PROTOCOL instance.
+ @param MonotonicCount Specifies the Record to return. On input, zero means
+ return the first record. On output, contains the next
+ record to availible. Zero indicates no more records.
+ @param FilterDriverEvent If FilterDriverEvent is not passed in a MonotonicCount
+ of zero, it means to return the first data record.
+ If FilterDriverEvent is passed in, then a MonotonicCount
+ of zero means to return the first data not yet read by
+ FilterDriverEvent.
+ @param Record Returns a dynamically allocated memory buffer with a data
+ record that matches MonotonicCount.
+
+ @retval EFI_SUCCESS Data was returned in Record.
+ @retval EFI_INVALID_PARAMETER FilterDriverEvent was passed in but does not exist.
+ @retval EFI_NOT_FOUND MonotonicCount does not match any data record in the
+ system. If a MonotonicCount of zero was passed in, then
+ no data records exist in the system.
+ @retval EFI_OUT_OF_RESOURCES Record was not returned due to lack of system resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DataHubGetNextRecord (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN OUT UINT64 *MonotonicCount,
+ IN EFI_EVENT *FilterDriverEvent, OPTIONAL
+ OUT EFI_DATA_RECORD_HEADER **Record
+ )
+{
+ DATA_HUB_INSTANCE *Private;
+ DATA_HUB_FILTER_DRIVER *FilterDriver;
+ UINT64 ClassFilter;
+
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);
+
+ FilterDriver = NULL;
+ ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |
+ EFI_DATA_RECORD_CLASS_ERROR |
+ EFI_DATA_RECORD_CLASS_DATA |
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+
+ //
+ // If FilterDriverEvent is NULL, then return the next record
+ //
+ if (FilterDriverEvent == NULL) {
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);
+ if (*Record == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // For events the beginning is the last unread record. This info is
+ // stored in the instance structure, so we must look up the event
+ // to get the data.
+ //
+ FilterDriver = FindFilterDriverByEvent (
+ &Private->FilterDriverListHead,
+ *FilterDriverEvent
+ );
+ if (FilterDriver == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Use the Class filter the event was created with.
+ //
+ ClassFilter = FilterDriver->ClassFilter;
+
+ //
+ // Retrieve the next record or the first record.
+ //
+ if (*MonotonicCount != 0 || FilterDriver->GetNextMonotonicCount == 0) {
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);
+ if (*Record == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*MonotonicCount != 0) {
+ //
+ // If this was not the last record then update the count associated with the filter
+ //
+ FilterDriver->GetNextMonotonicCount = *MonotonicCount;
+ } else {
+ //
+ // Save the MonotonicCount of the last record which has been read
+ //
+ FilterDriver->GetNextMonotonicCount = (*Record)->LogMonotonicCount;
+ }
+ return EFI_SUCCESS;
+ }
+
+ //
+ // This is a request to read the first record that has not been read yet.
+ // Set MonotoicCount to the last record successfuly read
+ //
+ *MonotonicCount = FilterDriver->GetNextMonotonicCount;
+
+ //
+ // Retrieve the last record successfuly read again, but do not return it since
+ // it has already been returned before.
+ //
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);
+ if (*Record == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (*MonotonicCount != 0) {
+ //
+ // Update the count associated with the filter
+ //
+ FilterDriver->GetNextMonotonicCount = *MonotonicCount;
+
+ //
+ // Retrieve the record after the last record successfuly read
+ //
+ *Record = GetNextDataRecord (&Private->DataListHead, ClassFilter, MonotonicCount);
+ if (*Record == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ This function registers the data hub filter driver that is represented
+ by FilterEvent. Only one instance of each FilterEvent can be registered.
+ After the FilterEvent is registered, it will be signaled so it can sync
+ with data records that have been recorded prior to the FilterEvent being
+ registered.
+
+ @param This Pointer to The EFI_DATA_HUB_PROTOCOL instance.
+ @param FilterEvent The EFI_EVENT to signal whenever data that matches
+ FilterClass is logged in the system.
+ @param FilterTpl The maximum EFI_TPL at which FilterEvent can be
+ signaled. It is strongly recommended that you use the
+ lowest EFI_TPL possible.
+ @param FilterClass FilterEvent will be signaled whenever a bit in
+ EFI_DATA_RECORD_HEADER.DataRecordClass is also set in
+ FilterClass. If FilterClass is zero, no class-based
+ filtering will be performed.
+ @param FilterDataRecordGuid FilterEvent will be signaled whenever FilterDataRecordGuid
+ matches EFI_DATA_RECORD_HEADER.DataRecordGuid. If
+ FilterDataRecordGuid is NULL, then no GUID-based filtering
+ will be performed.
+
+ @retval EFI_SUCCESS The filter driver event was registered.
+ @retval EFI_ALREADY_STARTED FilterEvent was previously registered and cannot be
+ registered again.
+ @retval EFI_OUT_OF_RESOURCES The filter driver event was not registered due to lack of
+ system resources.
+
+**/
+EFI_STATUS
+EFIAPI
+DataHubRegisterFilterDriver (
+ IN EFI_DATA_HUB_PROTOCOL * This,
+ IN EFI_EVENT FilterEvent,
+ IN EFI_TPL FilterTpl,
+ IN UINT64 FilterClass,
+ IN EFI_GUID * FilterDataRecordGuid OPTIONAL
+ )
+
+{
+ DATA_HUB_INSTANCE *Private;
+ DATA_HUB_FILTER_DRIVER *FilterDriver;
+
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);
+
+ FilterDriver = (DATA_HUB_FILTER_DRIVER *) AllocateZeroPool (sizeof (DATA_HUB_FILTER_DRIVER));
+ if (FilterDriver == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Initialize filter driver info
+ //
+ FilterDriver->Signature = EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE;
+ FilterDriver->Event = FilterEvent;
+ FilterDriver->Tpl = FilterTpl;
+ FilterDriver->GetNextMonotonicCount = 0;
+ if (FilterClass == 0) {
+ FilterDriver->ClassFilter = EFI_DATA_RECORD_CLASS_DEBUG |
+ EFI_DATA_RECORD_CLASS_ERROR |
+ EFI_DATA_RECORD_CLASS_DATA |
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ } else {
+ FilterDriver->ClassFilter = FilterClass;
+ }
+
+ if (FilterDataRecordGuid != NULL) {
+ CopyMem (&FilterDriver->FilterDataRecordGuid, FilterDataRecordGuid, sizeof (EFI_GUID));
+ }
+ //
+ // Search for duplicate entries
+ //
+ if (FindFilterDriverByEvent (&Private->FilterDriverListHead, FilterEvent) != NULL) {
+ FreePool (FilterDriver);
+ return EFI_ALREADY_STARTED;
+ }
+ //
+ // Make insertion an atomic operation with the lock.
+ //
+ EfiAcquireLock (&Private->DataLock);
+ InsertTailList (&Private->FilterDriverListHead, &FilterDriver->Link);
+ EfiReleaseLock (&Private->DataLock);
+
+ //
+ // Signal the Filter driver we just loaded so they will recieve all the
+ // previous history. If we did not signal here we would have to wait until
+ // the next data was logged to get the history. In a case where no next
+ // data was logged we would never get synced up.
+ //
+ gBS->SignalEvent (FilterEvent);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Remove a Filter Driver, so it no longer gets called when data
+ information is logged.
+
+ @param This Protocol instance structure
+
+ @param FilterEvent Event that represents a filter driver that is to be
+ Unregistered.
+
+ @retval EFI_SUCCESS If FilterEvent was unregistered
+ @retval EFI_NOT_FOUND If FilterEvent does not exist
+**/
+EFI_STATUS
+EFIAPI
+DataHubUnregisterFilterDriver (
+ IN EFI_DATA_HUB_PROTOCOL *This,
+ IN EFI_EVENT FilterEvent
+ )
+{
+ DATA_HUB_INSTANCE *Private;
+ DATA_HUB_FILTER_DRIVER *FilterDriver;
+
+ Private = DATA_HUB_INSTANCE_FROM_THIS (This);
+
+ //
+ // Search for duplicate entries
+ //
+ FilterDriver = FindFilterDriverByEvent (
+ &Private->FilterDriverListHead,
+ FilterEvent
+ );
+ if (FilterDriver == NULL) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Make removal an atomic operation with the lock
+ //
+ EfiAcquireLock (&Private->DataLock);
+ RemoveEntryList (&FilterDriver->Link);
+ EfiReleaseLock (&Private->DataLock);
+
+ return EFI_SUCCESS;
+}
+
+
+
+/**
+ Driver's Entry point routine that install Driver to produce Data Hub protocol.
+
+ @param ImageHandle Module's image handle
+ @param SystemTable Pointer of EFI_SYSTEM_TABLE
+
+ @retval EFI_SUCCESS Logging Hub protocol installed
+ @retval Other No protocol installed, unload driver.
+
+**/
+EFI_STATUS
+EFIAPI
+DataHubInstall (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT32 HighMontonicCount;
+
+ mPrivateData.Signature = DATA_HUB_INSTANCE_SIGNATURE;
+ mPrivateData.DataHub.LogData = DataHubLogData;
+ mPrivateData.DataHub.GetNextRecord = DataHubGetNextRecord;
+ mPrivateData.DataHub.RegisterFilterDriver = DataHubRegisterFilterDriver;
+ mPrivateData.DataHub.UnregisterFilterDriver = DataHubUnregisterFilterDriver;
+
+ //
+ // Initialize Private Data in CORE_LOGGING_HUB_INSTANCE that is
+ // required by this protocol
+ //
+ InitializeListHead (&mPrivateData.DataListHead);
+ InitializeListHead (&mPrivateData.FilterDriverListHead);
+
+ EfiInitializeLock (&mPrivateData.DataLock, TPL_NOTIFY);
+
+ //
+ // Make sure we get a bigger MTC number on every boot!
+ //
+ Status = gRT->GetNextHighMonotonicCount (&HighMontonicCount);
+ if (EFI_ERROR (Status)) {
+ //
+ // if system service fails pick a sane value.
+ //
+ mPrivateData.GlobalMonotonicCount = 0;
+ } else {
+ mPrivateData.GlobalMonotonicCount = LShiftU64 ((UINT64) HighMontonicCount, 32);
+ }
+ //
+ // Make a new handle and install the protocol
+ //
+ mPrivateData.Handle = NULL;
+ Status = gBS->InstallProtocolInterface (
+ &mPrivateData.Handle,
+ &gEfiDataHubProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mPrivateData.DataHub
+ );
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.h b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.h
new file mode 100644
index 0000000000..de2e3f34ff
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHub.h
@@ -0,0 +1,131 @@
+/** @file
+ This code supports a the private implementation
+ of the Data Hub protocol
+
+Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _DATA_HUB_H_
+#define _DATA_HUB_H_
+
+
+#include <FrameworkDxe.h>
+
+#include <Protocol/DataHub.h>
+
+#include <Guid/ZeroGuid.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+
+#define DATA_HUB_INSTANCE_SIGNATURE SIGNATURE_32 ('D', 'H', 'u', 'b')
+typedef struct {
+ UINT32 Signature;
+
+ EFI_HANDLE Handle;
+
+ //
+ // Produced protocol(s)
+ //
+ EFI_DATA_HUB_PROTOCOL DataHub;
+
+ //
+ // Private Data
+ //
+ //
+ // Updates to GlobalMonotonicCount, LogListHead, and FilterDriverListHead
+ // must be locked.
+ //
+ EFI_LOCK DataLock;
+
+ //
+ // Runing Monotonic Count to use for each error record.
+ // Increment AFTER use in an error record.
+ //
+ UINT64 GlobalMonotonicCount;
+
+ //
+ // List of EFI_DATA_ENTRY structures. This is the data log! The list
+ // must be in assending order of LogMonotonicCount.
+ //
+ LIST_ENTRY DataListHead;
+
+ //
+ // List of EFI_DATA_HUB_FILTER_DRIVER structures. Represents all
+ // the registered filter drivers.
+ //
+ LIST_ENTRY FilterDriverListHead;
+
+} DATA_HUB_INSTANCE;
+
+#define DATA_HUB_INSTANCE_FROM_THIS(this) CR (this, DATA_HUB_INSTANCE, DataHub, DATA_HUB_INSTANCE_SIGNATURE)
+
+//
+// Private data structure to contain the data log. One record per
+// structure. Head pointer to the list is the Log member of
+// EFI_DATA_ENTRY. Record is a copy of the data passed in.
+//
+#define EFI_DATA_ENTRY_SIGNATURE SIGNATURE_32 ('D', 'r', 'e', 'c')
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ EFI_DATA_RECORD_HEADER *Record;
+
+ UINTN RecordSize;
+
+} EFI_DATA_ENTRY;
+
+#define DATA_ENTRY_FROM_LINK(link) CR (link, EFI_DATA_ENTRY, Link, EFI_DATA_ENTRY_SIGNATURE)
+
+//
+// Private data to contain the filter driver Event and it's
+// associated EFI_TPL.
+//
+#define EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE SIGNATURE_32 ('D', 'h', 'F', 'd')
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+
+ //
+ // Store Filter Driver Event and Tpl level it can be Signaled at.
+ //
+ EFI_EVENT Event;
+ EFI_TPL Tpl;
+
+ //
+ // Monotonic count on the get next operation for Event.
+ // Zero indicates get next has not been called for this event yet.
+ //
+ UINT64 GetNextMonotonicCount;
+
+ //
+ // Filter driver will register what class filter should be used.
+ //
+ UINT64 ClassFilter;
+
+ //
+ // Filter driver will register what record guid filter should be used.
+ //
+ EFI_GUID FilterDataRecordGuid;
+
+} DATA_HUB_FILTER_DRIVER;
+
+#define FILTER_ENTRY_FROM_LINK(link) CR (link, DATA_HUB_FILTER_DRIVER, Link, EFI_DATA_HUB_FILTER_DRIVER_SIGNATURE)
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf
new file mode 100644
index 0000000000..834c3b3148
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.inf
@@ -0,0 +1,85 @@
+## @file
+# This driver initializes and installs the Data Hub protocol.
+#
+# The data hub is a volatile database that is intended as the major focus for the accumulation of
+# manageability data.T he hub is fed by "producers" with chunks of data in a defined format.
+# Consumers may then extract the data in temporal "log" order.As an example, progress codes might
+# be recorded in the data hub for future processing.Ot her data contributed to the data hub might
+# include, for example, statistics on enumerated items such as memory, add-in buses, and add-in
+# cards and data on errors encountered during boot (for example, the system did not boot off the
+# network because the cable was not plugged in).
+# Some classes of data have defined formats.For example, the amount of memory in the system is
+# reported in a standard format so that consumers can be written to extract the data.O ther data is
+# system specific.For example, additional detail on errors might be specific to the driver that
+# discovered the error.The consumer might be a driver that tabularizes data from the data hub,
+# providing a mechanism for the raw data to be made available to the OS for post-processing by
+# OS-based applications.
+# The intent of the data hub is for drivers that enumerate and configure parts of the system to report
+# their discoveries to the data hub.This data can then be extracted by other drivers that report those
+# discoveries using standard manageability interfaces such as SMBIOS and Intelligent Platform
+# Management Interface (IPMI).The alternative to a data-hub-like architecture is to require all
+# drivers to be aware of all reporting formats.
+# For more information, please ref http://www.intel.com/technology/framework/
+#
+# Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DataHubDxe
+ MODULE_UNI_FILE = DataHubDxe.uni
+ FILE_GUID = 53BCC14F-C24F-434C-B294-8ED2D4CC1860
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DataHubInstall
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DataHub.h
+ DataHub.c
+
+
+[Packages]
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+
+
+[LibraryClasses]
+ UefiRuntimeServicesTableLib
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gZeroGuid ## SOMETIMES_CONSUMES ## GUID
+
+
+[Protocols]
+ gEfiDataHubProtocolGuid ## PRODUCES
+
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DataHubDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.uni b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.uni
new file mode 100644
index 0000000000..2e62686103
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxeExtra.uni
new file mode 100644
index 0000000000..27b2ae3bdc
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubDxe/DataHubDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErr.c b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErr.c
new file mode 100644
index 0000000000..48522c01af
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErr.c
@@ -0,0 +1,151 @@
+/** @file
+ Data Hub filter driver that takes DEBUG () info from Data Hub and writes it
+ to StdErr if it exists.
+
+Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <FrameworkDxe.h>
+#include <Guid/DataHubStatusCodeRecord.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Protocol/DataHub.h>
+#include <Protocol/SimpleTextOut.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+EFI_DATA_HUB_PROTOCOL *mDataHub = NULL;
+
+EFI_EVENT mDataHubStdErrEvent;
+
+/**
+ Event handler registered with the Data Hub to parse EFI_DEBUG_CODE. This
+ handler reads the Data Hub and sends any DEBUG info to StdErr.
+
+ @param Event The event that occured, not used
+ @param Context DataHub Protocol Pointer
+**/
+VOID
+EFIAPI
+DataHubStdErrEventHandler (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ EFI_STATUS Status;
+ EFI_DATA_HUB_PROTOCOL *DataHub;
+ EFI_DATA_RECORD_HEADER *Record;
+ DATA_HUB_STATUS_CODE_DATA_RECORD *DataRecord;
+ UINT64 Mtc;
+ EFI_SIMPLE_TEXT_OUTPUT_PROTOCOL *Sto;
+ INT32 OldAttribute;
+
+ DataHub = (EFI_DATA_HUB_PROTOCOL *) Context;
+
+ //
+ // If StdErr is not yet initialized just return a DEBUG print in the BDS
+ // after consoles are connect will make sure data gets flushed properly
+ // when StdErr is availible.
+ //
+ if (gST == NULL) {
+ return ;
+ }
+
+ if (gST->StdErr == NULL) {
+ return ;
+ }
+
+ //
+ // Mtc of zero means return the next record that has not been read by the
+ // event handler.
+ //
+ Mtc = 0;
+ do {
+ Status = DataHub->GetNextRecord (DataHub, &Mtc, &mDataHubStdErrEvent, &Record);
+ if (!EFI_ERROR (Status)) {
+ if (CompareGuid (&Record->DataRecordGuid, &gEfiDataHubStatusCodeRecordGuid)) {
+ DataRecord = (DATA_HUB_STATUS_CODE_DATA_RECORD *) (((CHAR8 *) Record) + Record->HeaderSize);
+
+ if (DataRecord->Data.HeaderSize > 0) {
+ if (CompareGuid (&DataRecord->Data.Type, &gEfiStatusCodeDataTypeDebugGuid)) {
+ //
+ // If the Data record is from a DEBUG () then send it to Standard Error
+ //
+ Sto = gST->StdErr;
+ OldAttribute = Sto->Mode->Attribute;
+ Sto->SetAttribute (Sto, EFI_TEXT_ATTR (EFI_MAGENTA, EFI_BLACK));
+ Sto->OutputString (Sto, (CHAR16 *) (DataRecord + 1));
+ Sto->SetAttribute (Sto, OldAttribute);
+ }
+ }
+ }
+ }
+ } while ((Mtc != 0) && !EFI_ERROR (Status));
+}
+
+/**
+ Register an event handler with the Data Hub to parse EFI_DEBUG_CODE. This
+ handler reads the Data Hub and sends any DEBUG info to StdErr.
+
+ @param ImageHandle Image handle of this driver.
+ @param SystemTable Pointer to EFI system table.
+
+ @retval EFI_SUCCESS The event handler was registered.
+ @retval EFI_OUT_OF_RESOURCES The event hadler was not registered due to lack of system resources.
+**/
+EFI_STATUS
+EFIAPI
+DataHubStdErrInitialize (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ UINT64 DataClass;
+
+ gBS->LocateProtocol (&gEfiDataHubProtocolGuid, NULL, (VOID **) &mDataHub);
+ //
+ // Should never fail due to Depex grammer.
+ //
+ ASSERT (mDataHub != NULL);
+
+ //
+ // Create an event and register it with the filter driver
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ DataHubStdErrEventHandler,
+ mDataHub,
+ &mDataHubStdErrEvent
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ DataClass = EFI_DATA_RECORD_CLASS_DEBUG | EFI_DATA_RECORD_CLASS_ERROR;
+ Status = mDataHub->RegisterFilterDriver (
+ mDataHub,
+ mDataHubStdErrEvent,
+ TPL_CALLBACK,
+ DataClass,
+ NULL
+ );
+ if (EFI_ERROR (Status)) {
+ gBS->CloseEvent (mDataHubStdErrEvent);
+ }
+
+ return Status;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf
new file mode 100644
index 0000000000..f9dede864c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.inf
@@ -0,0 +1,57 @@
+## @file
+# This driver takes DEBUG info from Data Hub and writes it to StdErr if it exists.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DataHubStdErrDxe
+ MODULE_UNI_FILE = DataHubStdErrDxe.uni
+ FILE_GUID = CA515306-00CE-4032-874E-11B755FF6866
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DataHubStdErrInitialize
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DataHubStdErr.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ DebugLib
+
+[Guids]
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_CONSUMES ## UNDEFINED # DataRecord Date Type
+ gEfiDataHubStatusCodeRecordGuid ## SOMETIMES_CONSUMES ## UNDEFINED # DataRecordGuid
+
+
+[Protocols]
+ gEfiDataHubProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiDataHubProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DataHubStdErrDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.uni b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.uni
new file mode 100644
index 0000000000..88aac304ad
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxeExtra.uni
new file mode 100644
index 0000000000..9ef673b8a8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/DataHubStdErrDxe/DataHubStdErrDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
new file mode 100644
index 0000000000..12508b4335
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/Ffs.c
@@ -0,0 +1,608 @@
+/** @file
+ FFS file access utilities.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+#define PHYSICAL_ADDRESS_TO_POINTER(Address) ((VOID *) ((UINTN) Address))
+
+/**
+ Set File State in the FfsHeader.
+
+ @param State File state to be set into FFS header.
+ @param FfsHeader Points to the FFS file header
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ //
+ // Set File State in the FfsHeader
+ //
+ FfsHeader->State = (EFI_FFS_FILE_STATE) (FfsHeader->State ^ State);
+ return ;
+}
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 HighestBit;
+
+ FileState = FfsHeader->State;
+
+ if (ErasePolarity != 0) {
+ FileState = (EFI_FFS_FILE_STATE)~FileState;
+ }
+
+ HighestBit = 0x80;
+ while (HighestBit != 0 && ((HighestBit & FileState) == 0)) {
+ HighestBit >>= 1;
+ }
+
+ return (EFI_FFS_FILE_STATE) HighestBit;
+}
+
+/**
+ Convert the Buffer Address to LBA Entry Address.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2LbaEntry (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT LBA_ENTRY **LbaListEntry
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ LIST_ENTRY *Link;
+
+ Link = FvDevice->LbaHeader.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ //
+ // Locate LBA which contains the address
+ //
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ if ((EFI_PHYSICAL_ADDRESS) (UINTN) (LbaEntry->StartingAddress) > BufferAddress) {
+ break;
+ }
+
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ Link = LbaEntry->Link.BackLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ if (&LbaEntry->Link == &FvDevice->LbaHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ *LbaListEntry = LbaEntry;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert the Buffer Address to LBA Address & Offset.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param Lba Pointer to the gob Lba value
+ @param Offset Pointer to the got Offset
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2Lba (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ EFI_STATUS Status;
+
+ LbaEntry = NULL;
+
+ Status = Buffer2LbaEntry (
+ FvDevice,
+ BufferAddress,
+ &LbaEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Lba = LbaEntry->LbaIndex;
+ *Offset = (UINTN) BufferAddress - (UINTN) LbaEntry->StartingAddress;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param Buffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ )
+{
+ UINTN Count;
+ UINT8 EraseByte;
+
+ if (ErasePolarity == 1) {
+ EraseByte = 0xFF;
+ } else {
+ EraseByte = 0;
+ }
+
+ for (Count = 0; Count < BufferSize; Count++) {
+ if (Buffer[Count] != EraseByte) {
+ return FALSE;
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ )
+{
+ UINT16 Checksum;
+
+ Checksum = CalculateSum16 ((UINT16 *) FvHeader, FvHeader->HeaderLength);
+
+ if (Checksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Verify checksum of the FFS file header.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 HeaderChecksum;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ HeaderChecksum = CalculateSum8 ((UINT8 *) FfsHeader, sizeof (EFI_FFS_FILE_HEADER));
+ }
+ HeaderChecksum = (UINT8) (HeaderChecksum - FfsHeader->State - FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (HeaderChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+}
+
+/**
+ Verify checksum of the FFS file data.
+
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT8 FileChecksum;
+ EFI_FV_FILE_ATTRIBUTES Attributes;
+
+ Attributes = FfsHeader->Attributes;
+
+ if ((Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+
+ //
+ // Check checksum of FFS data
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ FileChecksum = CalculateSum8 ((UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER));
+ }
+ FileChecksum = (UINT8) (FileChecksum + FfsHeader->IntegrityCheck.Checksum.File);
+
+ if (FileChecksum == 0) {
+ return TRUE;
+ } else {
+ return FALSE;
+ }
+
+ } else {
+
+ if (FfsHeader->IntegrityCheck.Checksum.File != FFS_FIXED_CHECKSUM) {
+ return FALSE;
+ } else {
+ return TRUE;
+ }
+ }
+
+}
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFFSHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+
+ //
+ // Check if it is a free space
+ //
+ if (IsBufferErased (
+ ErasePolarity,
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ )) {
+ return FALSE;
+ }
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (FileState) {
+ case EFI_FILE_HEADER_CONSTRUCTION:
+ //
+ // fall through
+ //
+ case EFI_FILE_HEADER_INVALID:
+ return FALSE;
+
+ case EFI_FILE_HEADER_VALID:
+ //
+ // fall through
+ //
+ case EFI_FILE_DATA_VALID:
+ //
+ // fall through
+ //
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ //
+ // fall through
+ //
+ case EFI_FILE_DELETED:
+ //
+ // Here we need to verify header checksum
+ //
+ if (!VerifyHeaderChecksum (FfsHeader)) {
+ return FALSE;
+ }
+ break;
+
+ default:
+ //
+ // return
+ //
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
+/**
+ Get next possible of Firmware File System Header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be skipped.
+
+ @return Pointer to next FFS header.
+
+**/
+EFI_PHYSICAL_ADDRESS
+GetNextPossibleFileHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ UINT32 FileLength;
+ UINT32 SkipLength;
+
+ if (!IsValidFFSHeader (ErasePolarity, FfsHeader)) {
+ //
+ // Skip this header
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ }
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FileLength = FFS_FILE2_SIZE (FfsHeader);
+ } else {
+ FileLength = FFS_FILE_SIZE (FfsHeader);
+ }
+
+ //
+ // Since FileLength is not multiple of 8, we need skip some bytes
+ // to get next possible header
+ //
+ SkipLength = FileLength;
+ while ((SkipLength & 0x07) != 0) {
+ SkipLength++;
+ }
+
+ return (EFI_PHYSICAL_ADDRESS) (UINTN) FfsHeader + SkipLength;
+}
+
+/**
+ Search FFS file with the same FFS name in FV Cache.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be skipped.
+ @param StateBit FFS file state bit to be checked.
+
+ @return Pointer to next found FFS header. NULL will return if no found.
+
+**/
+EFI_FFS_FILE_HEADER *
+DuplicateFileExist (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE StateBit
+ )
+{
+ UINT8 *Ptr;
+ EFI_FFS_FILE_HEADER *NextFfsFile;
+
+ //
+ // Search duplicate file, not from the beginning of FV,
+ // just search the next ocurrence of this file
+ //
+ NextFfsFile = FfsHeader;
+
+ do {
+ Ptr = (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (
+ GetNextPossibleFileHeader (FvDevice->ErasePolarity,
+ NextFfsFile)
+ );
+ NextFfsFile = (EFI_FFS_FILE_HEADER *) Ptr;
+
+ if ((UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength - Ptr <
+ sizeof (EFI_FFS_FILE_HEADER)
+ ) {
+ break;
+ }
+
+ if (!IsValidFFSHeader (FvDevice->ErasePolarity, NextFfsFile)) {
+ continue;
+ }
+
+ if (!VerifyFileChecksum (NextFfsFile)) {
+ continue;
+ }
+
+ if (CompareGuid (&NextFfsFile->Name, &FfsHeader->Name)) {
+ if (GetFileState (FvDevice->ErasePolarity, NextFfsFile) == StateBit) {
+ return NextFfsFile;
+ }
+ }
+ } while (Ptr < (UINT8 *) PHYSICAL_ADDRESS_TO_POINTER (FvDevice->CachedFv) + FvDevice->FwVolHeader->FvLength);
+
+ return NULL;
+}
+
+/**
+ Change FFS file header state and write to FV.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be updated.
+ @param State FFS file state to be set.
+
+ @retval EFI_SUCCESS File state is writen into FV.
+ @retval others File state can't be writen into FV.
+
+**/
+EFI_STATUS
+UpdateHeaderBit (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE State
+ )
+{
+ EFI_STATUS Status;
+ EFI_LBA Lba;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+
+ Lba = 0;
+ Offset = 0;
+
+ SetFileState (State, FfsHeader);
+
+ Buffer2Lba (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) (&FfsHeader->State),
+ &Lba,
+ &Offset
+ );
+ //
+ // Write the state byte into FV
+ //
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvDevice->Fvb->Write (
+ FvDevice->Fvb,
+ Lba,
+ Offset,
+ &NumBytesWritten,
+ &FfsHeader->State
+ );
+ return Status;
+}
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFFSFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 ErasePolarity;
+
+ ErasePolarity = FvDevice->ErasePolarity;
+
+ FileState = GetFileState (ErasePolarity, FfsHeader);
+
+ switch (FileState) {
+ case EFI_FILE_DATA_VALID:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ break;
+ }
+ //
+ // Check if there is another duplicated file with the EFI_FILE_DATA_VALID
+ //
+ if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
+ return FALSE;
+ }
+
+ break;
+
+ case EFI_FILE_MARKED_FOR_UPDATE:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ if (FfsHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // since its data area is not unperturbed, it cannot be reclaimed,
+ // marked it as deleted
+ //
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
+ return TRUE;
+
+ } else if (DuplicateFileExist (FvDevice, FfsHeader, EFI_FILE_DATA_VALID) != NULL) {
+ //
+ // Here the found file is more recent than this file,
+ // mark it as deleted
+ //
+ UpdateHeaderBit (FvDevice, FfsHeader, EFI_FILE_DELETED);
+ return TRUE;
+
+ } else {
+ return TRUE;
+ }
+
+ break;
+
+ case EFI_FILE_DELETED:
+ if (!VerifyFileChecksum (FfsHeader)) {
+ return FALSE;
+ }
+
+ break;
+
+ default:
+ return FALSE;
+ }
+
+ return TRUE;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
new file mode 100644
index 0000000000..8d53d879bd
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwPadFile.c
@@ -0,0 +1,1228 @@
+/** @file
+ Implements functions to pad firmware file.
+
+ Copyright (c) 2006 - 2011, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+/**
+ Calculate the checksum for a PAD file.
+
+ @param PadFileHeader The Pad File to be caculeted the checksum.
+
+**/
+VOID
+SetPadFileChecksum (
+ IN EFI_FFS_FILE_HEADER *PadFileHeader
+ )
+{
+ if ((PadFileHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+
+ if (IS_FFS_FILE2 (PadFileHeader)) {
+ //
+ // Calculate checksum of Pad File Data
+ //
+ PadFileHeader->IntegrityCheck.Checksum.File =
+ CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER2), FFS_FILE2_SIZE (PadFileHeader) - sizeof (EFI_FFS_FILE_HEADER2));
+
+ } else {
+ //
+ // Calculate checksum of Pad File Data
+ //
+ PadFileHeader->IntegrityCheck.Checksum.File =
+ CalculateCheckSum8 ((UINT8 *) PadFileHeader + sizeof (EFI_FFS_FILE_HEADER), FFS_FILE_SIZE (PadFileHeader) - sizeof (EFI_FFS_FILE_HEADER));
+ }
+
+ } else {
+
+ PadFileHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+ }
+
+ return ;
+}
+
+/**
+ Create a PAD File in the Free Space.
+
+ @param FvDevice Firmware Volume Device.
+ @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.
+ @param Size Pad file Size, not include the header.
+ @param PadFileEntry The Ffs File Entry that points to this Pad File.
+
+ @retval EFI_SUCCESS Successfully create a PAD file.
+ @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.
+ @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.
+ @retval EFI_DEVICE_ERROR Free space is not erased.
+**/
+EFI_STATUS
+FvCreatePadFileInFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN FREE_SPACE_ENTRY *FreeSpaceEntry,
+ IN UINTN Size,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *PadFileHeader;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINTN StateOffset;
+ UINT8 *StartPos;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINTN HeaderSize;
+ UINTN FileSize;
+
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ FileSize = Size + HeaderSize;
+ if (FileSize > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ FileSize = Size + HeaderSize;
+ }
+
+ if (FreeSpaceEntry->Length < FileSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if ((Size & 0x07) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ StartPos = FreeSpaceEntry->StartingAddress;
+
+ //
+ // First double check the space
+ //
+ if (!IsBufferErased (
+ FvDevice->ErasePolarity,
+ StartPos,
+ FileSize
+ )) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;
+
+ //
+ // Create File Step 1
+ //
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &PadFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
+ return Status;
+ }
+ //
+ // Update Free Space Entry, since header is allocated
+ //
+ FreeSpaceEntry->Length -= HeaderSize;
+ FreeSpaceEntry->StartingAddress += HeaderSize;
+
+ //
+ // Fill File Name Guid, here we assign a NULL-GUID to Pad files
+ //
+ ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
+
+ //
+ // Fill File Type, checksum(0), Attributes(0), Size
+ //
+ PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
+ PadFileHeader->Attributes = 0;
+ if ((FileSize) > 0x00FFFFFF) {
+ ((EFI_FFS_FILE_HEADER2 *) PadFileHeader)->ExtendedSize = (UINT32) FileSize;
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
+ PadFileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
+ *(UINT32 *) PadFileHeader->Size |= FileSize;
+ }
+
+ SetHeaderChecksum (PadFileHeader);
+ SetPadFileChecksum (PadFileHeader);
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+
+ NumBytesWritten = HeaderSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ (UINT8 *) PadFileHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Step 2, then Mark header valid, since no data write,
+ // mark the data valid at the same time.
+ //
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &PadFileHeader->State - (UINT8 *) PadFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &PadFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
+ return Status;
+ }
+ //
+ // Update Free Space Entry, since header is allocated
+ //
+ FreeSpaceEntry->Length -= Size;
+ FreeSpaceEntry->StartingAddress += Size;
+
+ //
+ // If successfully, insert an FfsFileEntry at the end of ffs file list
+ //
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ ASSERT (FfsFileEntry != NULL);
+
+ FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) StartPos;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+
+ *PadFileEntry = FfsFileEntry;
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill pad file header within firmware cache.
+
+ @param PadFileHeader The start of the Pad File Buffer.
+ @param PadFileLength The length of the pad file including the header.
+
+**/
+VOID
+FvFillPadFile (
+ IN EFI_FFS_FILE_HEADER *PadFileHeader,
+ IN UINTN PadFileLength
+ )
+{
+ //
+ // Fill File Name Guid, here we assign a NULL-GUID to Pad files
+ //
+ ZeroMem (&PadFileHeader->Name, sizeof (EFI_GUID));
+
+ //
+ // Fill File Type, checksum(0), Attributes(0), Size
+ //
+ PadFileHeader->Type = EFI_FV_FILETYPE_FFS_PAD;
+ PadFileHeader->Attributes = 0;
+ if (PadFileLength > 0x00FFFFFF) {
+ ((EFI_FFS_FILE_HEADER2 *) PadFileHeader)->ExtendedSize = (UINT32) PadFileLength;
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
+ PadFileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ *(UINT32 *) PadFileHeader->Size &= 0xFF000000;
+ *(UINT32 *) PadFileHeader->Size |= PadFileLength;
+ }
+
+ SetHeaderChecksum (PadFileHeader);
+ SetPadFileChecksum (PadFileHeader);
+
+ //
+ // Set File State to 0x00000111
+ //
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, PadFileHeader);
+ SetFileState (EFI_FILE_HEADER_VALID, PadFileHeader);
+ SetFileState (EFI_FILE_DATA_VALID, PadFileHeader);
+
+ return ;
+}
+
+/**
+ Create entire FFS file.
+
+ @param FileHeader Starting Address of a Buffer that hold the FFS File image.
+ @param FfsFileBuffer The source buffer that contains the File Data.
+ @param BufferSize The length of FfsFileBuffer.
+ @param ActualFileSize Size of FFS file.
+ @param FileName The Guid of Ffs File.
+ @param FileType The type of the written Ffs File.
+ @param FileAttributes The attributes of the written Ffs File.
+
+ @retval EFI_INVALID_PARAMETER File type is not valid.
+ @retval EFI_SUCCESS FFS file is successfully created.
+
+**/
+EFI_STATUS
+FvFillFfsFile (
+ OUT EFI_FFS_FILE_HEADER *FileHeader,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ )
+{
+ EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
+ EFI_FFS_FILE_HEADER *TmpFileHeader;
+
+ //
+ // File Type value 0x0E~0xE0 are reserved
+ //
+ if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ TmpFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
+ //
+ // First fill all fields ready in FfsFileBuffer
+ //
+ CopyGuid (&TmpFileHeader->Name, FileName);
+ TmpFileHeader->Type = FileType;
+
+ //
+ // Convert the FileAttributes to FFSFileAttributes
+ //
+ FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
+
+ TmpFileHeader->Attributes = TmpFileAttribute;
+
+ if (ActualFileSize > 0x00FFFFFF) {
+ ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize;
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ *(UINT32 *) FileHeader->Size |= ActualFileSize;
+ }
+
+ SetHeaderChecksum (TmpFileHeader);
+ SetFileChecksum (TmpFileHeader, ActualFileSize);
+
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, TmpFileHeader);
+ SetFileState (EFI_FILE_HEADER_VALID, TmpFileHeader);
+ SetFileState (EFI_FILE_DATA_VALID, TmpFileHeader);
+
+ //
+ // Copy data from FfsFileBuffer to FileHeader(cache)
+ //
+ CopyMem (FileHeader, FfsFileBuffer, BufferSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Fill some other extra space using 0xFF(Erase Value).
+
+ @param ErasePolarity Fv erase value.
+ @param FileHeader Point to the start of FFS File.
+ @param ExtraLength The pading length.
+
+**/
+VOID
+FvAdjustFfsFile (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FileHeader,
+ IN UINTN ExtraLength
+ )
+{
+ UINT8 *Ptr;
+ UINT8 PadingByte;
+
+ if (IS_FFS_FILE2 (FileHeader)) {
+ Ptr = (UINT8 *) FileHeader + FFS_FILE2_SIZE (FileHeader);
+ } else {
+ Ptr = (UINT8 *) FileHeader + FFS_FILE_SIZE (FileHeader);
+ }
+
+ if (ErasePolarity == 0) {
+ PadingByte = 0;
+ } else {
+ PadingByte = 0xFF;
+ }
+ //
+ // Fill the non-used space with Padding Byte
+ //
+ SetMem (Ptr, ExtraLength, PadingByte);
+
+ return ;
+}
+
+/**
+ Free File List entry pointed by FileListHead.
+
+ @param FileListHeader FileListEntry Header.
+
+**/
+VOID
+FreeFileList (
+ IN LIST_ENTRY *FileListHead
+ )
+{
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) (FileListHead->ForwardLink);
+
+ //
+ // Loop the whole list entry to free resources
+ //
+ while (&FfsFileEntry->Link != FileListHead) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+ FreePool (FfsFileEntry);
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
+ }
+
+ return ;
+}
+
+/**
+ Create a new file within a PAD file area.
+
+ @param FvDevice Firmware Volume Device.
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state).
+ @param BufferSize The size of FfsFileBuffer.
+ @param ActualFileSize The actual file length, it may not be multiples of 8.
+ @param FileName The FFS File Name.
+ @param FileType The FFS File Type.
+ @param FileAttributes The Attributes of the FFS File to be created.
+
+ @retval EFI_SUCCESS Successfully create a new file within the found PAD file area.
+ @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.
+ @retval other errors New file is created failed.
+
+**/
+EFI_STATUS
+FvCreateNewFileInsidePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ )
+{
+ UINTN RequiredAlignment;
+ FFS_FILE_LIST_ENTRY *PadFileEntry;
+ EFI_STATUS Status;
+ UINTN PadAreaLength;
+ UINTN PadSize;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_FFS_FILE_HEADER *OldPadFileHeader;
+ EFI_FFS_FILE_HEADER *PadFileHeader;
+ EFI_FFS_FILE_HEADER *TailPadFileHeader;
+ UINTN StateOffset;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINT8 *StartPos;
+ LIST_ENTRY NewFileList;
+ FFS_FILE_LIST_ENTRY *NewFileListEntry;
+ FFS_FILE_LIST_ENTRY *FfsEntry;
+ FFS_FILE_LIST_ENTRY *NextFfsEntry;
+
+ //
+ // First get the required alignment from the File Attributes
+ //
+ RequiredAlignment = GetRequiredAlignment (FileAttributes);
+
+ //
+ // Find a suitable PAD File
+ //
+ Status = FvLocatePadFile (
+ FvDevice,
+ BufferSize,
+ RequiredAlignment,
+ &PadSize,
+ &PadFileEntry
+ );
+
+ if (EFI_ERROR (Status)) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
+
+ //
+ // Step 1: Update Pad File Header
+ //
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldPadFileHeader);
+
+ StartPos = PadFileEntry->FfsHeader;
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &OldPadFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, OldPadFileHeader);
+ return Status;
+ }
+
+ //
+ // Step 2: Update Pad area
+ //
+ InitializeListHead (&NewFileList);
+
+ if (IS_FFS_FILE2 (OldPadFileHeader)) {
+ PadAreaLength = FFS_FILE2_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ PadAreaLength = FFS_FILE_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+
+ if (PadSize != 0) {
+ //
+ // Insert a PAD file before to achieve required alignment
+ //
+ FvFillPadFile (PadFileHeader, PadSize);
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ ASSERT (NewFileListEntry != NULL);
+ NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize);
+
+ Status = FvFillFfsFile (
+ FileHeader,
+ FfsFileBuffer,
+ BufferSize,
+ ActualFileSize,
+ FileName,
+ FileType,
+ FileAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ return Status;
+ }
+
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ ASSERT (NewFileListEntry != NULL);
+
+ NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+
+ FvDevice->CurrentFfsFile = NewFileListEntry;
+
+ if (PadAreaLength > (BufferSize + PadSize)) {
+ if ((PadAreaLength - BufferSize - PadSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
+ //
+ // we can insert another PAD file
+ //
+ TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize);
+ FvFillPadFile (TailPadFileHeader, PadAreaLength - BufferSize - PadSize);
+
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ ASSERT (NewFileListEntry != NULL);
+
+ NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+ } else {
+ //
+ // because left size cannot hold another PAD file header,
+ // adjust the writing file size (just in cache)
+ //
+ FvAdjustFfsFile (
+ FvDevice->ErasePolarity,
+ FileHeader,
+ PadAreaLength - BufferSize - PadSize
+ );
+ }
+ }
+ //
+ // Start writing to FV
+ //
+ if (IS_FFS_FILE2 (OldPadFileHeader)) {
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+
+ NumBytesWritten = PadAreaLength;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ StartPos
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return Status;
+ }
+
+ //
+ // Step 3: Mark Pad file header as EFI_FILE_HEADER_INVALID
+ //
+ SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
+
+ StartPos = PadFileEntry->FfsHeader;
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &OldPadFileHeader->State - (UINT8 *) OldPadFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &OldPadFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ SetFileState (EFI_FILE_HEADER_INVALID, OldPadFileHeader);
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return Status;
+ }
+
+ //
+ // If all successfully, update FFS_FILE_LIST
+ //
+
+ //
+ // Delete old pad file entry
+ //
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
+ NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
+
+ FreePool (PadFileEntry);
+
+ FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
+ (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
+ NextFfsEntry->Link.BackLink = NewFileList.BackLink;
+ (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free all FfsBuffer.
+
+ @param NumOfFiles Number of FfsBuffer.
+ @param FfsBuffer An array of pointer to an FFS File Buffer
+
+**/
+VOID
+FreeFfsBuffer (
+ IN UINTN NumOfFiles,
+ IN UINT8 **FfsBuffer
+ )
+{
+ UINTN Index;
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ if (FfsBuffer[Index] != NULL) {
+ FreePool (FfsBuffer[Index]);
+ }
+ }
+}
+
+/**
+ Create multiple files within a PAD File area.
+
+ @param FvDevice Firmware Volume Device.
+ @param PadFileEntry The pad file entry to be written in.
+ @param NumOfFiles Total File number to be written.
+ @param BufferSize The array of buffer size of each FfsBuffer.
+ @param ActualFileSize The array of actual file size.
+ @param PadSize The array of leading pad file size for each FFS File
+ @param FfsBuffer The array of Ffs Buffer pointer.
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
+ used to get name, attributes, type, etc.
+
+ @retval EFI_SUCCESS Add the input multiple files into PAD file area.
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval other error Files can't be added into PAD file area.
+
+**/
+EFI_STATUS
+FvCreateMultipleFilesInsidePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN FFS_FILE_LIST_ENTRY *PadFileEntry,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *ActualFileSize,
+ IN UINTN *PadSize,
+ IN UINT8 **FfsBuffer,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *OldPadFileHeader;
+ UINTN Index;
+ EFI_FFS_FILE_HEADER *PadFileHeader;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_FFS_FILE_HEADER *TailPadFileHeader;
+ UINTN TotalSize;
+ UINTN PadAreaLength;
+ LIST_ENTRY NewFileList;
+ FFS_FILE_LIST_ENTRY *NewFileListEntry;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINT8 *StartPos;
+ FFS_FILE_LIST_ENTRY *FfsEntry;
+ FFS_FILE_LIST_ENTRY *NextFfsEntry;
+
+ InitializeListHead (&NewFileList);
+
+ NewFileListEntry = NULL;
+
+ OldPadFileHeader = (EFI_FFS_FILE_HEADER *) PadFileEntry->FfsHeader;
+ if (IS_FFS_FILE2 (OldPadFileHeader)) {
+ PadAreaLength = FFS_FILE2_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ PadAreaLength = FFS_FILE_SIZE (OldPadFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Status = UpdateHeaderBit (
+ FvDevice,
+ OldPadFileHeader,
+ EFI_FILE_MARKED_FOR_UPDATE
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Update PAD area
+ //
+ TotalSize = 0;
+ if (IS_FFS_FILE2 (OldPadFileHeader)) {
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2));
+ } else {
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER));
+ }
+ FileHeader = PadFileHeader;
+
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ if (PadSize[Index] != 0) {
+ FvFillPadFile (PadFileHeader, PadSize[Index]);
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (NewFileListEntry == NULL) {
+ FreeFileList (&NewFileList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]);
+ Status = FvFillFfsFile (
+ FileHeader,
+ FfsBuffer[Index],
+ BufferSize[Index],
+ ActualFileSize[Index],
+ FileData[Index].NameGuid,
+ FileData[Index].Type,
+ FileData[Index].FileAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ return Status;
+ }
+
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (NewFileListEntry == NULL) {
+ FreeFileList (&NewFileList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]);
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+ }
+
+ FvDevice->CurrentFfsFile = NewFileListEntry;
+ //
+ // Maybe we need a tail pad file
+ //
+ if (PadAreaLength > TotalSize) {
+ if ((PadAreaLength - TotalSize) >= sizeof (EFI_FFS_FILE_HEADER)) {
+ //
+ // we can insert another PAD file
+ //
+ TailPadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[NumOfFiles - 1]);
+ FvFillPadFile (TailPadFileHeader, PadAreaLength - TotalSize);
+
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (NewFileListEntry == NULL) {
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileListEntry->FfsHeader = (UINT8 *) TailPadFileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+ } else {
+ //
+ // because left size cannot hold another PAD file header,
+ // adjust the writing file size (just in cache)
+ //
+ FvAdjustFfsFile (
+ FvDevice->ErasePolarity,
+ FileHeader,
+ PadAreaLength - TotalSize
+ );
+ }
+ }
+ //
+ // Start writing to FV
+ //
+ if (IS_FFS_FILE2 (OldPadFileHeader)) {
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ StartPos = (UINT8 *) OldPadFileHeader + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+
+ NumBytesWritten = PadAreaLength;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ StartPos
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return Status;
+ }
+
+ Status = UpdateHeaderBit (
+ FvDevice,
+ OldPadFileHeader,
+ EFI_FILE_HEADER_INVALID
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return Status;
+ }
+
+ //
+ // Update File List Link
+ //
+
+ //
+ // First delete old pad file entry
+ //
+ FfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.BackLink;
+ NextFfsEntry = (FFS_FILE_LIST_ENTRY *) PadFileEntry->Link.ForwardLink;
+
+ FreePool (PadFileEntry);
+
+ FfsEntry->Link.ForwardLink = NewFileList.ForwardLink;
+ (NewFileList.ForwardLink)->BackLink = &FfsEntry->Link;
+ NextFfsEntry->Link.BackLink = NewFileList.BackLink;
+ (NewFileList.BackLink)->ForwardLink = &NextFfsEntry->Link;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Create multiple files within the Free Space.
+
+ @param FvDevice Firmware Volume Device.
+ @param FreeSpaceEntry Indicating in which Free Space(Cache) the multiple files will be inserted.
+ @param NumOfFiles Total File number to be written.
+ @param BufferSize The array of buffer size of each FfsBuffer.
+ @param ActualFileSize The array of actual file size.
+ @param PadSize The array of leading pad file size for each FFS File
+ @param FfsBuffer The array of Ffs Buffer pointer.
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
+ used to get name, attributes, type, etc.
+
+ @retval EFI_SUCCESS Add the input multiple files into PAD file area.
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval other error Files can't be added into PAD file area.
+
+**/
+EFI_STATUS
+FvCreateMultipleFilesInsideFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN FREE_SPACE_ENTRY *FreeSpaceEntry,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *ActualFileSize,
+ IN UINTN *PadSize,
+ IN UINT8 **FfsBuffer,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index;
+ EFI_FFS_FILE_HEADER *PadFileHeader;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINTN TotalSize;
+ LIST_ENTRY NewFileList;
+ FFS_FILE_LIST_ENTRY *NewFileListEntry;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINT8 *StartPos;
+
+ InitializeListHead (&NewFileList);
+
+ NewFileListEntry = NULL;
+
+ TotalSize = 0;
+ StartPos = FreeSpaceEntry->StartingAddress;
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) StartPos;
+ FileHeader = PadFileHeader;
+
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ if (PadSize[Index] != 0) {
+ FvFillPadFile (PadFileHeader, PadSize[Index]);
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (NewFileListEntry == NULL) {
+ FreeFileList (&NewFileList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileListEntry->FfsHeader = (UINT8 *) PadFileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+ }
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) PadFileHeader + PadSize[Index]);
+ Status = FvFillFfsFile (
+ FileHeader,
+ FfsBuffer[Index],
+ BufferSize[Index],
+ ActualFileSize[Index],
+ FileData[Index].NameGuid,
+ FileData[Index].Type,
+ FileData[Index].FileAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ return Status;
+ }
+
+ NewFileListEntry = AllocatePool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (NewFileListEntry == NULL) {
+ FreeFileList (&NewFileList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ NewFileListEntry->FfsHeader = (UINT8 *) FileHeader;
+ InsertTailList (&NewFileList, &NewFileListEntry->Link);
+
+ PadFileHeader = (EFI_FFS_FILE_HEADER *) ((UINT8 *) FileHeader + BufferSize[Index]);
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+ }
+
+ if (FreeSpaceEntry->Length < TotalSize) {
+ FreeFileList (&NewFileList);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvDevice->CurrentFfsFile = NewFileListEntry;
+
+ //
+ // Start writing to FV
+ //
+ Offset = (UINTN) (StartPos - FvDevice->CachedFv);
+
+ NumBytesWritten = TotalSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ StartPos
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFileList (&NewFileList);
+ FvDevice->CurrentFfsFile = NULL;
+ return Status;
+ }
+
+ FreeSpaceEntry->Length -= TotalSize;
+ FreeSpaceEntry->StartingAddress += TotalSize;
+
+ NewFileListEntry = (FFS_FILE_LIST_ENTRY *) (NewFileList.ForwardLink);
+
+ while (NewFileListEntry != (FFS_FILE_LIST_ENTRY *) &NewFileList) {
+ InsertTailList (&FvDevice->FfsFileListHeader, &NewFileListEntry->Link);
+ NewFileListEntry = (FFS_FILE_LIST_ENTRY *) (NewFileListEntry->Link.ForwardLink);
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write multiple files into FV in reliable method.
+
+ @param FvDevice Firmware Volume Device.
+ @param NumOfFiles Total File number to be written.
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
+ used to get name, attributes, type, etc
+ @param FileOperation The array of operation for each file.
+
+ @retval EFI_SUCCESS Files are added into FV.
+ @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.
+ @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.
+ @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.
+
+**/
+EFI_STATUS
+FvCreateMultipleFiles (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN EFI_FV_WRITE_FILE_DATA *FileData,
+ IN BOOLEAN *FileOperation
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *FfsBuffer[MAX_FILES];
+ UINTN Index1;
+ UINTN Index2;
+ UINTN BufferSize[MAX_FILES];
+ UINTN ActualFileSize[MAX_FILES];
+ UINTN RequiredAlignment[MAX_FILES];
+ UINTN PadSize[MAX_FILES];
+ FFS_FILE_LIST_ENTRY *PadFileEntry;
+ UINTN TotalSizeNeeded;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+ EFI_FV_FILETYPE OldFileType;
+ EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
+ UINTN OldFileSize;
+ FFS_FILE_LIST_ENTRY *OldFfsFileEntry[MAX_FILES];
+ EFI_FFS_FILE_HEADER *OldFileHeader[MAX_FILES];
+ BOOLEAN IsCreateFile;
+ UINTN HeaderSize;
+
+ //
+ // To use this function, we must ensure that the NumOfFiles is great
+ // than 1
+ //
+ if (NumOfFiles <= 1) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumOfFiles > MAX_FILES) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Fv = &FvDevice->Fv;
+
+ SetMem (FfsBuffer, NumOfFiles, 0);
+ SetMem (RequiredAlignment, NumOfFiles, 8);
+ SetMem (PadSize, NumOfFiles, 0);
+ ZeroMem (OldFfsFileEntry, sizeof (OldFfsFileEntry));
+ ZeroMem (OldFileHeader, sizeof (OldFileHeader));
+
+ //
+ // Adjust file size
+ //
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ ActualFileSize[Index1] = FileData[Index1].BufferSize + HeaderSize;
+ if (ActualFileSize[Index1] > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ ActualFileSize[Index1] = FileData[Index1].BufferSize + HeaderSize;
+ }
+ BufferSize[Index1] = ActualFileSize[Index1];
+
+ if (BufferSize[Index1] == HeaderSize) {
+ //
+ // clear file attributes, zero-length file does not have any attributes
+ //
+ FileData[Index1].FileAttributes = 0;
+ }
+
+ while ((BufferSize[Index1] & 0x07) != 0) {
+ BufferSize[Index1]++;
+ }
+
+ FfsBuffer[Index1] = AllocateZeroPool (BufferSize[Index1]);
+
+ //
+ // Copy File Data into FileBuffer
+ //
+ CopyMem (
+ FfsBuffer[Index1] + HeaderSize,
+ FileData[Index1].Buffer,
+ FileData[Index1].BufferSize
+ );
+
+ if (FvDevice->ErasePolarity == 1) {
+ for (Index2 = 0; Index2 < HeaderSize; Index2++) {
+ FfsBuffer[Index1][Index2] = (UINT8)~FfsBuffer[Index1][Index2];
+ }
+ }
+
+ if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {
+ RequiredAlignment[Index1] = GetRequiredAlignment (FileData[Index1].FileAttributes);
+ }
+ //
+ // If update file, mark the original file header to
+ // EFI_FILE_MARKED_FOR_UPDATE
+ //
+ IsCreateFile = FileOperation[Index1];
+ if (!IsCreateFile) {
+
+ Key = 0;
+ do {
+ OldFileType = 0;
+ Status = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &OldFileType,
+ &FileNameGuid,
+ &OldFileAttributes,
+ &OldFileSize
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);
+ return Status;
+ }
+ } while (!CompareGuid (&FileNameGuid, FileData[Index1].NameGuid));
+
+ //
+ // Get FfsFileEntry from the search key
+ //
+ OldFfsFileEntry[Index1] = (FFS_FILE_LIST_ENTRY *) Key;
+ OldFileHeader[Index1] = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry[Index1]->FfsHeader;
+ Status = UpdateHeaderBit (
+ FvDevice,
+ OldFileHeader[Index1],
+ EFI_FILE_MARKED_FOR_UPDATE
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);
+ return Status;
+ }
+ }
+ }
+ //
+ // First to search a suitable pad file that can hold so
+ // many files
+ //
+ Status = FvSearchSuitablePadFile (
+ FvDevice,
+ NumOfFiles,
+ BufferSize,
+ RequiredAlignment,
+ PadSize,
+ &TotalSizeNeeded,
+ &PadFileEntry
+ );
+
+ if (Status == EFI_NOT_FOUND) {
+ //
+ // Try to find a free space that can hold these files
+ //
+ Status = FvSearchSuitableFreeSpace (
+ FvDevice,
+ NumOfFiles,
+ BufferSize,
+ RequiredAlignment,
+ PadSize,
+ &TotalSizeNeeded,
+ &FreeSpaceEntry
+ );
+ if (EFI_ERROR (Status)) {
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ Status = FvCreateMultipleFilesInsideFreeSpace (
+ FvDevice,
+ FreeSpaceEntry,
+ NumOfFiles,
+ BufferSize,
+ ActualFileSize,
+ PadSize,
+ FfsBuffer,
+ FileData
+ );
+
+ } else {
+ //
+ // Create multiple files inside such a pad file
+ // to achieve lock-step update
+ //
+ Status = FvCreateMultipleFilesInsidePadFile (
+ FvDevice,
+ PadFileEntry,
+ NumOfFiles,
+ BufferSize,
+ ActualFileSize,
+ PadSize,
+ FfsBuffer,
+ FileData
+ );
+ }
+
+ FreeFfsBuffer (NumOfFiles, FfsBuffer);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Delete those updated files
+ //
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
+ IsCreateFile = FileOperation[Index1];
+ if (!IsCreateFile && OldFfsFileEntry[Index1] != NULL) {
+ (OldFfsFileEntry[Index1]->Link.BackLink)->ForwardLink = OldFfsFileEntry[Index1]->Link.ForwardLink;
+ (OldFfsFileEntry[Index1]->Link.ForwardLink)->BackLink = OldFfsFileEntry[Index1]->Link.BackLink;
+ FreePool (OldFfsFileEntry[Index1]);
+ }
+ }
+ //
+ // Set those files' state to EFI_FILE_DELETED
+ //
+ for (Index1 = 0; Index1 < NumOfFiles; Index1++) {
+ IsCreateFile = FileOperation[Index1];
+ if (!IsCreateFile && OldFileHeader[Index1] != NULL) {
+ Status = UpdateHeaderBit (FvDevice, OldFileHeader[Index1], EFI_FILE_DELETED);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
new file mode 100644
index 0000000000..2ba09c49b5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVol.c
@@ -0,0 +1,798 @@
+/** @file
+
+ Firmware File System driver that produce full Firmware Volume2 protocol.
+ Layers on top of Firmware Block protocol to produce a file abstraction
+ of FV based files.
+
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+#define KEYSIZE sizeof (UINTN)
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER TempFvh;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN FvhLength;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ //
+ // Determine the real length of FV header
+ //
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &FvbAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((FvbAttributes & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ //
+ // Just avoid compiling warning
+ //
+ BaseAddress = 0;
+ FvhLength = sizeof (EFI_FIRMWARE_VOLUME_HEADER);
+
+ //
+ // memory-mapped FV and non memory-mapped has different ways to read
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ Status = Fvb->GetPhysicalAddress (
+ Fvb,
+ &BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ CopyMem (&TempFvh, (VOID *) (UINTN) BaseAddress, FvhLength);
+ } else {
+ Status = Fvb->Read (
+ Fvb,
+ 0,
+ 0,
+ &FvhLength,
+ (UINT8 *) &TempFvh
+ );
+ }
+
+ //
+ // Validate FV Header signature, if not as expected, continue.
+ //
+ if (TempFvh.Signature != EFI_FVH_SIGNATURE) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Check to see that the file system is indeed formatted in a way we can
+ // understand it...
+ //
+ if ((!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem2Guid)) &&
+ (!CompareGuid (&TempFvh.FileSystemGuid, &gEfiFirmwareFileSystem3Guid))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ *FwVolHeader = AllocatePool (TempFvh.HeaderLength);
+ if (*FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Read the whole header
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ CopyMem (*FwVolHeader, (VOID *) (UINTN) BaseAddress, TempFvh.HeaderLength);
+ } else {
+ //
+ // Assumed the first block is bigger than the length of Fv headder
+ //
+ FvhLength = TempFvh.HeaderLength;
+ Status = Fvb->Read (
+ Fvb,
+ 0,
+ 0,
+ &FvhLength,
+ (UINT8 *) *FwVolHeader
+ );
+ //
+ // Check whether Read successes.
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (*FwVolHeader);
+ *FwVolHeader = NULL;
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free FvDevice resource when error happens.
+
+ @param FvDevice Pointer to the FvDevice to be freed.
+**/
+VOID
+FreeFvDeviceResource (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ LBA_ENTRY *LbaEntry;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ LIST_ENTRY *NextEntry;
+
+ //
+ // Free LAB Entry
+ //
+ LbaEntry = (LBA_ENTRY *) FvDevice->LbaHeader.ForwardLink;
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ NextEntry = (&LbaEntry->Link)->ForwardLink;
+ FreePool (LbaEntry);
+ LbaEntry = (LBA_ENTRY *) NextEntry;
+ }
+ //
+ // Free File List Entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+ while (&FfsFileEntry->Link != &FvDevice->FfsFileListHeader) {
+ NextEntry = (&FfsFileEntry->Link)->ForwardLink;
+ FreePool (FfsFileEntry);
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) NextEntry;
+ }
+ //
+ // Free Space Entry
+ //
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) FvDevice->FreeSpaceHeader.ForwardLink;
+ while (&FreeSpaceEntry->Link != &FvDevice->FreeSpaceHeader) {
+ NextEntry = (&FreeSpaceEntry->Link)->ForwardLink;
+ FreePool (FreeSpaceEntry);
+ FreeSpaceEntry = (FREE_SPACE_ENTRY *) NextEntry;
+ }
+ //
+ // Free the cache
+ //
+ FreePool ((UINT8 *) (UINTN) FvDevice->CachedFv);
+
+ return ;
+}
+
+/**
+
+ Firmware volume inherits authentication status from the FV image file and section(in another firmware volume)
+ where it came from.
+
+ @param FvDevice A pointer to the FvDevice.
+
+**/
+VOID
+FwVolInheritAuthenticationStatus (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *CachedFvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *CachedFvExtHeader;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *ParentFvProtocol;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ EFI_FIRMWARE_VOLUME_HEADER *FvHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FvExtHeader;
+ UINTN BufferSize;
+
+ CachedFvHeader = (EFI_FIRMWARE_VOLUME_HEADER *) (UINTN) FvDevice->CachedFv;
+
+ if (FvDevice->Fv.ParentHandle != NULL) {
+ //
+ // By Parent Handle, find out the FV image file and section(in another firmware volume) where the firmware volume came from
+ //
+ Status = gBS->HandleProtocol (FvDevice->Fv.ParentHandle, &gEfiFirmwareVolume2ProtocolGuid, (VOID **) &ParentFvProtocol);
+ if (!EFI_ERROR (Status) && (ParentFvProtocol != NULL)) {
+ Key = 0;
+ do {
+ FileType = EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE;
+ Status = ParentFvProtocol->GetNextFile (
+ ParentFvProtocol,
+ &Key,
+ &FileType,
+ &FileNameGuid,
+ &FileAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return;
+ }
+
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
+ FvHeader = NULL;
+ BufferSize = 0;
+ Status = ParentFvProtocol->ReadSection (
+ ParentFvProtocol,
+ &FileNameGuid,
+ SectionType,
+ 0,
+ (VOID **) &FvHeader,
+ &BufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ if ((FvHeader->FvLength == CachedFvHeader->FvLength) &&
+ (FvHeader->ExtHeaderOffset == CachedFvHeader->ExtHeaderOffset)) {
+ if (FvHeader->ExtHeaderOffset !=0) {
+ //
+ // Both FVs contain extension header, then compare their FV Name GUID
+ //
+ FvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) FvHeader + FvHeader->ExtHeaderOffset);
+ CachedFvExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) ((UINTN) CachedFvHeader + CachedFvHeader->ExtHeaderOffset);
+ if (CompareGuid (&FvExtHeader->FvName, &CachedFvExtHeader->FvName)) {
+ //
+ // Found the FV image section where the firmware volume came from,
+ // and then inherit authentication status from it.
+ //
+ FvDevice->AuthenticationStatus = AuthenticationStatus;
+ FreePool ((VOID *) FvHeader);
+ return;
+ }
+ } else {
+ //
+ // Both FVs don't contain extension header, then compare their whole FV Image.
+ //
+ if (CompareMem ((VOID *) FvHeader, (VOID *) CachedFvHeader, (UINTN) FvHeader->FvLength) == 0) {
+ //
+ // Found the FV image section where the firmware volume came from
+ // and then inherit authentication status from it.
+ //
+ FvDevice->AuthenticationStatus = AuthenticationStatus;
+ FreePool ((VOID *) FvHeader);
+ return;
+ }
+ }
+ }
+ FreePool ((VOID *) FvHeader);
+ }
+ } while (TRUE);
+ }
+ }
+}
+
+/**
+ Check if an FV is consistent and allocate cache for it.
+
+ @param FvDevice A pointer to the FvDevice to be checked.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_VOLUME_CORRUPTED File system is corrupted.
+ @retval EFI_SUCCESS FV is consistent and cache is allocated.
+
+**/
+EFI_STATUS
+FvCheck (
+ IN FV_DEVICE *FvDevice
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_EXT_HEADER *FwVolExtHeader;
+ UINT8 *FwCache;
+ LBA_ENTRY *LbaEntry;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINT8 *LbaStart;
+ UINTN Index;
+ EFI_LBA LbaIndex;
+ UINT8 *Ptr;
+ UINTN Size;
+ UINT8 *FreeStart;
+ UINTN FreeSize;
+ UINT8 ErasePolarity;
+ EFI_FFS_FILE_STATE FileState;
+ UINT8 *TopFvAddress;
+ UINTN TestLength;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+
+ Fvb = FvDevice->Fvb;
+
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ InitializeListHead (&FvDevice->LbaHeader);
+ InitializeListHead (&FvDevice->FreeSpaceHeader);
+ InitializeListHead (&FvDevice->FfsFileListHeader);
+
+ FwVolHeader = NULL;
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (FwVolHeader != NULL);
+
+ FvDevice->IsFfs3Fv = CompareGuid (&FwVolHeader->FileSystemGuid, &gEfiFirmwareFileSystem3Guid);
+
+ //
+ // Double Check firmware volume header here
+ //
+ if (!VerifyFvHeaderChecksum (FwVolHeader)) {
+ FreePool (FwVolHeader);
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ BlockMap = FwVolHeader->BlockMap;
+
+ //
+ // FwVolHeader->FvLength is the whole FV length including FV header
+ //
+ FwCache = AllocateZeroPool ((UINTN) FwVolHeader->FvLength);
+ if (FwCache == NULL) {
+ FreePool (FwVolHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FvDevice->CachedFv = (EFI_PHYSICAL_ADDRESS) (UINTN) FwCache;
+
+ //
+ // Copy to memory
+ //
+ LbaStart = FwCache;
+ LbaIndex = 0;
+ Ptr = NULL;
+
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+ //
+ // Get volume base address
+ //
+ Status = Fvb->GetPhysicalAddress (Fvb, &BaseAddress);
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ return Status;
+ }
+
+ Ptr = (UINT8 *) ((UINTN) BaseAddress);
+
+ DEBUG((EFI_D_INFO, "Fv Base Address is 0x%LX\n", BaseAddress));
+ }
+ //
+ // Copy whole FV into the memory
+ //
+ while ((BlockMap->NumBlocks != 0) || (BlockMap->Length != 0)) {
+
+ for (Index = 0; Index < BlockMap->NumBlocks; Index++) {
+ LbaEntry = AllocatePool (sizeof (LBA_ENTRY));
+ if (LbaEntry == NULL) {
+ FreePool (FwVolHeader);
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ LbaEntry->LbaIndex = LbaIndex;
+ LbaEntry->StartingAddress = LbaStart;
+ LbaEntry->BlockLength = BlockMap->Length;
+
+ //
+ // Copy each LBA into memory
+ //
+ if ((FvbAttributes & EFI_FVB2_MEMORY_MAPPED) != 0) {
+
+ CopyMem (LbaStart, Ptr, BlockMap->Length);
+ Ptr += BlockMap->Length;
+
+ } else {
+
+ Size = BlockMap->Length;
+ Status = Fvb->Read (
+ Fvb,
+ LbaIndex,
+ 0,
+ &Size,
+ LbaStart
+ );
+ //
+ // Not check EFI_BAD_BUFFER_SIZE, for Size = BlockMap->Length
+ //
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ FreeFvDeviceResource (FvDevice);
+ return Status;
+ }
+
+ }
+
+ LbaIndex++;
+ LbaStart += BlockMap->Length;
+
+ InsertTailList (&FvDevice->LbaHeader, &LbaEntry->Link);
+ }
+
+ BlockMap++;
+ }
+
+ FvDevice->FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) FwCache;
+
+ //
+ // it is not used any more, so free FwVolHeader
+ //
+ FreePool (FwVolHeader);
+
+ //
+ // Scan to check the free space & File list
+ //
+ if ((FvbAttributes & EFI_FVB2_ERASE_POLARITY) != 0) {
+ ErasePolarity = 1;
+ } else {
+ ErasePolarity = 0;
+ }
+
+ FvDevice->ErasePolarity = ErasePolarity;
+
+ //
+ // go through the whole FV cache, check the consistence of the FV
+ //
+ if (FvDevice->FwVolHeader->ExtHeaderOffset != 0) {
+ //
+ // Searching for files starts on an 8 byte aligned boundary after the end of the Extended Header if it exists.
+ //
+ FwVolExtHeader = (EFI_FIRMWARE_VOLUME_EXT_HEADER *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->ExtHeaderOffset);
+ Ptr = (UINT8 *) FwVolExtHeader + FwVolExtHeader->ExtHeaderSize;
+ Ptr = (UINT8 *) ALIGN_POINTER (Ptr, 8);
+ } else {
+ Ptr = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->HeaderLength);
+ }
+ TopFvAddress = (UINT8 *) (UINTN) (FvDevice->CachedFv + FvDevice->FwVolHeader->FvLength);
+
+ //
+ // Build FFS list & Free Space List here
+ //
+ while (Ptr < TopFvAddress) {
+ TestLength = TopFvAddress - Ptr;
+
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (IsBufferErased (ErasePolarity, Ptr, TestLength)) {
+ //
+ // We found free space
+ //
+ FreeStart = Ptr;
+ FreeSize = 0;
+
+ do {
+ TestLength = TopFvAddress - Ptr;
+
+ if (TestLength > sizeof (EFI_FFS_FILE_HEADER)) {
+ TestLength = sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (!IsBufferErased (ErasePolarity, Ptr, TestLength)) {
+ break;
+ }
+
+ FreeSize += TestLength;
+ Ptr += TestLength;
+ } while (Ptr < TopFvAddress);
+
+ FreeSpaceEntry = AllocateZeroPool (sizeof (FREE_SPACE_ENTRY));
+ if (FreeSpaceEntry == NULL) {
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Create a Free space entry
+ //
+ FreeSpaceEntry->StartingAddress = FreeStart;
+ FreeSpaceEntry->Length = FreeSize;
+ InsertTailList (&FvDevice->FreeSpaceHeader, &FreeSpaceEntry->Link);
+ continue;
+ }
+ //
+ // double check boundry
+ //
+ if (TestLength < sizeof (EFI_FFS_FILE_HEADER)) {
+ break;
+ }
+
+ if (!IsValidFFSHeader (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ )) {
+ FileState = GetFileState (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ );
+ if ((FileState == EFI_FILE_HEADER_INVALID) || (FileState == EFI_FILE_HEADER_CONSTRUCTION)) {
+ if (IS_FFS_FILE2 (Ptr)) {
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
+ }
+ Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ Ptr = Ptr + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ continue;
+
+ } else {
+ //
+ // File system is corrputed, return
+ //
+ FreeFvDeviceResource (FvDevice);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ if (IS_FFS_FILE2 (Ptr)) {
+ ASSERT (FFS_FILE2_SIZE (Ptr) > 0x00FFFFFF);
+ if (!FvDevice->IsFfs3Fv) {
+ DEBUG ((EFI_D_ERROR, "Found a FFS3 formatted file: %g in a non-FFS3 formatted FV.\n", &((EFI_FFS_FILE_HEADER *) Ptr)->Name));
+ Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
+ //
+ // Adjust Ptr to the next 8-byte aligned boundry.
+ //
+ while (((UINTN) Ptr & 0x07) != 0) {
+ Ptr++;
+ }
+ continue;
+ }
+ }
+
+ if (IsValidFFSFile (FvDevice, (EFI_FFS_FILE_HEADER *) Ptr)) {
+ FileState = GetFileState (
+ FvDevice->ErasePolarity,
+ (EFI_FFS_FILE_HEADER *) Ptr
+ );
+
+ //
+ // check for non-deleted file
+ //
+ if (FileState != EFI_FILE_DELETED) {
+ //
+ // Create a FFS list entry for each non-deleted file
+ //
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ if (FfsFileEntry == NULL) {
+ FreeFvDeviceResource (FvDevice);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ FfsFileEntry->FfsHeader = Ptr;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+ }
+
+ if (IS_FFS_FILE2 (Ptr)) {
+ Ptr = Ptr + FFS_FILE2_SIZE (Ptr);
+ } else {
+ Ptr = Ptr + FFS_FILE_SIZE (Ptr);
+ }
+
+ //
+ // Adjust Ptr to the next 8-byte aligned boundry.
+ //
+ while (((UINTN) Ptr & 0x07) != 0) {
+ Ptr++;
+ }
+ } else {
+ //
+ // File system is corrupted, return
+ //
+ FreeFvDeviceResource (FvDevice);
+ return EFI_VOLUME_CORRUPTED;
+ }
+ }
+
+ FvDevice->CurrentFfsFile = NULL;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point function does install/reinstall FV2 protocol with full functionality.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS At least one Fv protocol install/reinstall successfully.
+ @retval EFI_NOT_FOUND No FV protocol install/reinstall successfully.
+**/
+EFI_STATUS
+EFIAPI
+FwVolDriverInit (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_HANDLE *HandleBuffer;
+ UINTN HandleCount;
+ UINTN Index;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ BOOLEAN Reinstall;
+ BOOLEAN InstallFlag;
+
+ DEBUG ((EFI_D_INFO, "=========FwVol writable driver installed\n"));
+ InstallFlag = FALSE;
+ //
+ // Locate all handles of Fvb protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &HandleCount,
+ &HandleBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ for (Index = 0; Index < HandleCount; Index += 1) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &Fvb
+ );
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+
+ FwVolHeader = NULL;
+ Status = GetFwVolHeader (Fvb, &FwVolHeader);
+ if (EFI_ERROR (Status)) {
+ continue;
+ }
+ ASSERT (FwVolHeader != NULL);
+ FreePool (FwVolHeader);
+
+ Reinstall = FALSE;
+ //
+ // Check if there is an FV protocol already installed in that handle
+ //
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ Reinstall = TRUE;
+ }
+ //
+ // FwVol protocol on the handle so create a new one
+ //
+ FvDevice = AllocateZeroPool (sizeof (FV_DEVICE));
+ if (FvDevice == NULL) {
+ goto Done;
+ }
+
+ FvDevice->Signature = FV_DEVICE_SIGNATURE;
+ FvDevice->Fvb = Fvb;
+
+ //
+ // Firmware Volume Protocol interface
+ //
+ FvDevice->Fv.GetVolumeAttributes = FvGetVolumeAttributes;
+ FvDevice->Fv.SetVolumeAttributes = FvSetVolumeAttributes;
+ FvDevice->Fv.ReadFile = FvReadFile;
+ FvDevice->Fv.ReadSection = FvReadFileSection;
+ FvDevice->Fv.WriteFile = FvWriteFile;
+ FvDevice->Fv.GetNextFile = FvGetNextFile;
+ FvDevice->Fv.KeySize = KEYSIZE;
+ FvDevice->Fv.GetInfo = FvGetVolumeInfo;
+ FvDevice->Fv.SetInfo = FvSetVolumeInfo;
+ FvDevice->Fv.ParentHandle = Fvb->ParentHandle;
+
+ Status = FvCheck (FvDevice);
+ if (EFI_ERROR (Status)) {
+ //
+ // The file system is not consistence
+ //
+ FreePool (FvDevice);
+ continue;
+ }
+
+ FwVolInheritAuthenticationStatus (FvDevice);
+
+ if (Reinstall) {
+ //
+ // Reinstall an New FV protocol
+ //
+ // FvDevice = FV_DEVICE_FROM_THIS (Fv);
+ // FvDevice->Fvb = Fvb;
+ // FreeFvDeviceResource (FvDevice);
+ //
+ Status = gBS->ReinstallProtocolInterface (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolume2ProtocolGuid,
+ Fv,
+ &FvDevice->Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ InstallFlag = TRUE;
+ } else {
+ FreePool (FvDevice);
+ }
+
+ DEBUG ((EFI_D_INFO, "Reinstall FV protocol as writable - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ } else {
+ //
+ // Install an New FV protocol
+ //
+ Status = gBS->InstallProtocolInterface (
+ &FvDevice->Handle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &FvDevice->Fv
+ );
+ if (!EFI_ERROR (Status)) {
+ InstallFlag = TRUE;
+ } else {
+ FreePool (FvDevice);
+ }
+
+ DEBUG ((EFI_D_INFO, "Install FV protocol as writable - %r\n", Status));
+ ASSERT_EFI_ERROR (Status);
+ }
+ }
+
+Done:
+ //
+ // As long as one Fv protocol install/reinstall successfully,
+ // success should return to ensure this image will be not unloaded.
+ // Otherwise, new Fv protocols are corrupted by other loaded driver.
+ //
+ if (InstallFlag) {
+ return EFI_SUCCESS;
+ }
+
+ //
+ // No FV protocol install/reinstall successfully.
+ // EFI_NOT_FOUND should return to ensure this image will be unloaded.
+ //
+ return EFI_NOT_FOUND;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c
new file mode 100644
index 0000000000..0e4ddf8bea
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolAttrib.c
@@ -0,0 +1,220 @@
+/** @file
+
+ Implements get/set firmware volume attributes.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the Firmware Volume Block Attributes
+ //
+ Status = Fvb->GetAttributes (Fvb, &FvbAttributes);
+ FvbAttributes &= 0xfffff0ff;
+
+ *Attributes = FvbAttributes;
+ *Attributes |= EFI_FV2_WRITE_POLICY_RELIABLE;
+ return Status;
+}
+
+/**
+ Sets current attributes for volume.
+
+ @param This Calling context
+ @param Attributes On input, FvAttributes is a pointer to
+ an EFI_FV_ATTRIBUTES containing the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. On
+ unsuccessful return, FvAttributes is not
+ modified and the firmware volume
+ settings are not changed.
+
+ @retval EFI_SUCCESS The requested firmware volume attributes
+ were set and the resulting
+ EFI_FV_ATTRIBUTES is returned in
+ FvAttributes.
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FVB_ATTRIBUTES_2 OldFvbAttributes;
+ EFI_FVB_ATTRIBUTES_2 NewFvbAttributes;
+ UINT64 NewStatus;
+ UINT32 Capabilities;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+ Fvb = FvDevice->Fvb;
+
+ //
+ // First get the current Volume Attributes
+ //
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &OldFvbAttributes
+ );
+
+ if ((OldFvbAttributes & EFI_FVB2_LOCK_STATUS) != 0) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Only status attributes can be updated.
+ //
+ Capabilities = OldFvbAttributes & EFI_FVB2_CAPABILITIES;
+ NewStatus = (*Attributes) & EFI_FVB2_STATUS;
+
+ //
+ // Test read disable
+ //
+ if ((Capabilities & EFI_FVB2_READ_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test read enable
+ //
+ if ((Capabilities & EFI_FVB2_READ_ENABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_READ_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write disable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_DISABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) == 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test write enable
+ //
+ if ((Capabilities & EFI_FVB2_WRITE_ENABLED_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_WRITE_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ //
+ // Test lock
+ //
+ if ((Capabilities & EFI_FVB2_LOCK_CAP) == 0) {
+ if ((NewStatus & EFI_FVB2_LOCK_STATUS) != 0) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ NewFvbAttributes = OldFvbAttributes & (0xFFFFFFFF & (~EFI_FVB2_STATUS));
+ NewFvbAttributes |= NewStatus;
+ Status = Fvb->SetAttributes (
+ Fvb,
+ &NewFvbAttributes
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ *Attributes = 0;
+
+ This->GetVolumeAttributes (
+ This,
+ Attributes
+ );
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of
+ data returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @return EFI_UNSUPPORTED Could not get.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
+
+/**
+ Set information with InformationType into the requested firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize Size of Buffer data.
+ @param Buffer A poniter to the data buffer to be set.
+
+ @retval EFI_UNSUPPORTED Could not set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ )
+{
+ return EFI_UNSUPPORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h
new file mode 100644
index 0000000000..b1646dd39e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDriver.h
@@ -0,0 +1,761 @@
+/** @file
+ Common defines and definitions for a FwVolDxe driver.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _FWVOL_DRIVER_H_
+#define _FWVOL_DRIVER_H_
+
+#include <PiDxe.h>
+
+#include <Guid/FirmwareFileSystem2.h>
+#include <Guid/FirmwareFileSystem3.h>
+#include <Protocol/SectionExtraction.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolume2.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+
+#include <Library/DebugLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiLib.h>
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+#define FV_DEVICE_SIGNATURE SIGNATURE_32 ('_', 'F', 'V', '_')
+
+//
+// Define two helper macro to extract the Capability field or Status field in FVB
+// bit fields
+//
+#define EFI_FVB2_CAPABILITIES (EFI_FVB2_READ_DISABLED_CAP | \
+ EFI_FVB2_READ_ENABLED_CAP | \
+ EFI_FVB2_WRITE_DISABLED_CAP | \
+ EFI_FVB2_WRITE_ENABLED_CAP | \
+ EFI_FVB2_LOCK_CAP \
+ )
+
+#define EFI_FVB2_STATUS (EFI_FVB2_READ_STATUS | EFI_FVB2_WRITE_STATUS | EFI_FVB2_LOCK_STATUS)
+
+#define MAX_FILES 32
+
+//
+// Used to calculate from address -> Lba
+//
+typedef struct {
+ LIST_ENTRY Link;
+ EFI_LBA LbaIndex;
+ UINT8 *StartingAddress;
+ UINTN BlockLength;
+} LBA_ENTRY;
+
+//
+// Used to track free space in the Fv
+//
+typedef struct {
+ LIST_ENTRY Link;
+ UINT8 *StartingAddress;
+ UINTN Length;
+} FREE_SPACE_ENTRY;
+
+//
+// Used to track all non-deleted files
+//
+typedef struct {
+ LIST_ENTRY Link;
+ UINT8 *FfsHeader;
+} FFS_FILE_LIST_ENTRY;
+
+typedef struct {
+ UINTN Signature;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL Fv;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ UINT8 *Key;
+ EFI_HANDLE Handle;
+
+ UINT8 ErasePolarity;
+ EFI_PHYSICAL_ADDRESS CachedFv;
+ LIST_ENTRY LbaHeader;
+ LIST_ENTRY FreeSpaceHeader;
+ LIST_ENTRY FfsFileListHeader;
+
+ FFS_FILE_LIST_ENTRY *CurrentFfsFile;
+ BOOLEAN IsFfs3Fv;
+ UINT32 AuthenticationStatus;
+} FV_DEVICE;
+
+#define FV_DEVICE_FROM_THIS(a) CR (a, FV_DEVICE, Fv, FV_DEVICE_SIGNATURE)
+
+/**
+ Retrieves attributes, insures positive polarity of attribute bits, returns
+ resulting attributes in output parameter.
+
+ @param This Calling context
+ @param Attributes output buffer which contains attributes
+
+ @retval EFI_SUCCESS Successfully got volume attributes
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Sets current attributes for volume.
+
+ @param This Calling context
+ @param Attributes On input, FvAttributes is a pointer to
+ an EFI_FV_ATTRIBUTES containing the
+ desired firmware volume settings. On
+ successful return, it contains the new
+ settings of the firmware volume. On
+ unsuccessful return, FvAttributes is not
+ modified and the firmware volume
+ settings are not changed.
+
+ @retval EFI_SUCCESS The requested firmware volume attributes
+ were set and the resulting
+ EFI_FV_ATTRIBUTES is returned in
+ FvAttributes.
+ @retval EFI_ACCESS_DENIED Atrribute is locked down.
+ @retval EFI_INVALID_PARAMETER Atrribute is not valid.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeAttributes (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT EFI_FV_ATTRIBUTES *Attributes
+ );
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ );
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ );
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ );
+
+/**
+ Return information of type InformationType for the requested firmware
+ volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize On input, size of Buffer.On output, the amount of
+ data returned in Buffer.
+ @param Buffer A poniter to the data buffer to return.
+
+ @return EFI_UNSUPPORTED Could not get.
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN OUT UINTN *BufferSize,
+ OUT VOID *Buffer
+ );
+
+
+/**
+ Set information with InformationType into the requested firmware volume.
+
+ @param This Pointer to EFI_FIRMWARE_VOLUME2_PROTOCOL.
+ @param InformationType InformationType for requested.
+ @param BufferSize Size of Buffer data.
+ @param Buffer A poniter to the data buffer to be set.
+
+ @retval EFI_UNSUPPORTED Could not set.
+
+**/
+EFI_STATUS
+EFIAPI
+FvSetVolumeInfo (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *InformationType,
+ IN UINTN BufferSize,
+ IN CONST VOID *Buffer
+ );
+
+/**
+ Writes data beginning at Lba:Offset from FV. The write terminates either
+ when *NumBytes of data have been written, or when the firmware end is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Offset in the block at which to begin write
+ @param NumBytes At input, indicates the requested write size.
+ At output, indicates the actual number of bytes written.
+ @param Buffer Buffer containing source data for the write.
+
+ @retval EFI_SUCCESS Data is successfully written into FV.
+ @return error Data is failed written.
+
+**/
+EFI_STATUS
+FvcWrite (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ );
+
+
+/**
+ Check if a block of buffer is erased.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param Buffer The buffer to be checked
+ @param BufferSize Size of the buffer in bytes
+
+ @retval TRUE The block of buffer is erased
+ @retval FALSE The block of buffer is not erased
+
+**/
+BOOLEAN
+IsBufferErased (
+ IN UINT8 ErasePolarity,
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize
+ );
+
+/**
+ Get the FFS file state by checking the highest bit set in the header's state field.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header
+
+ @return FFS File state
+
+**/
+EFI_FFS_FILE_STATE
+GetFileState (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Verify checksum of the firmware volume header.
+
+ @param FvHeader Points to the firmware volume header to be checked
+
+ @retval TRUE Checksum verification passed
+ @retval FALSE Checksum verification failed
+
+**/
+BOOLEAN
+VerifyFvHeaderChecksum (
+ IN EFI_FIRMWARE_VOLUME_HEADER *FvHeader
+ );
+
+/**
+ Check if it's a valid FFS file header.
+
+ @param ErasePolarity Erase polarity attribute of the firmware volume
+ @param FfsHeader Points to the FFS file header to be checked
+
+ @retval TRUE Valid FFS file header
+ @retval FALSE Invalid FFS file header
+
+**/
+BOOLEAN
+IsValidFFSHeader (
+ IN UINT8 ErasePolarity,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Check if it's a valid FFS file.
+ Here we are sure that it has a valid FFS file header since we must call IsValidFfsHeader() first.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file to be checked
+
+ @retval TRUE Valid FFS file
+ @retval FALSE Invalid FFS file
+
+**/
+BOOLEAN
+IsValidFFSFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Given the supplied FW_VOL_BLOCK_PROTOCOL, allocate a buffer for output and
+ copy the real length volume header into it.
+
+ @param Fvb The FW_VOL_BLOCK_PROTOCOL instance from which to
+ read the volume header
+ @param FwVolHeader Pointer to pointer to allocated buffer in which
+ the volume header is returned.
+
+ @retval EFI_OUT_OF_RESOURCES No enough buffer could be allocated.
+ @retval EFI_SUCCESS Successfully read volume header to the allocated
+ buffer.
+ @retval EFI_ACCESS_DENIED Read status of FV is not enabled.
+ @retval EFI_INVALID_PARAMETER The FV Header signature is not as expected or
+ the file system could not be understood.
+**/
+EFI_STATUS
+GetFwVolHeader (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb,
+ OUT EFI_FIRMWARE_VOLUME_HEADER **FwVolHeader
+ );
+
+/**
+ Convert the Buffer Address to LBA Entry Address.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param LbaListEntry Pointer to the got LBA entry that contains the address.
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA entry is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2LbaEntry (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT LBA_ENTRY **LbaListEntry
+ );
+
+/**
+ Convert the Buffer Address to LBA Address & Offset.
+
+ @param FvDevice Cached FvDevice
+ @param BufferAddress Address of Buffer
+ @param Lba Pointer to the gob Lba value
+ @param Offset Pointer to the got Offset
+
+ @retval EFI_NOT_FOUND Buffer address is out of FvDevice.
+ @retval EFI_SUCCESS LBA and Offset is found for Buffer address.
+
+**/
+EFI_STATUS
+Buffer2Lba (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS BufferAddress,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *Offset
+ );
+
+/**
+ Set File State in the FfsHeader.
+
+ @param State File state to be set into FFS header.
+ @param FfsHeader Points to the FFS file header
+
+**/
+VOID
+SetFileState (
+ IN UINT8 State,
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Create a PAD File in the Free Space.
+
+ @param FvDevice Firmware Volume Device.
+ @param FreeSpaceEntry Indicating in which Free Space(Cache) the Pad file will be inserted.
+ @param Size Pad file Size, not include the header.
+ @param PadFileEntry The Ffs File Entry that points to this Pad File.
+
+ @retval EFI_SUCCESS Successfully create a PAD file.
+ @retval EFI_OUT_OF_RESOURCES No enough free space to create a PAD file.
+ @retval EFI_INVALID_PARAMETER Size is not 8 byte alignment.
+ @retval EFI_DEVICE_ERROR Free space is not erased.
+**/
+EFI_STATUS
+FvCreatePadFileInFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN FREE_SPACE_ENTRY *FreeSpaceEntry,
+ IN UINTN Size,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ );
+
+/**
+ Create a new file within a PAD file area.
+
+ @param FvDevice Firmware Volume Device.
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains a File Header which is in init state).
+ @param BufferSize The size of FfsFileBuffer.
+ @param ActualFileSize The actual file length, it may not be multiples of 8.
+ @param FileName The FFS File Name.
+ @param FileType The FFS File Type.
+ @param FileAttributes The Attributes of the FFS File to be created.
+
+ @retval EFI_SUCCESS Successfully create a new file within the found PAD file area.
+ @retval EFI_OUT_OF_RESOURCES No suitable PAD file is found.
+ @retval other errors New file is created failed.
+
+**/
+EFI_STATUS
+FvCreateNewFileInsidePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ );
+
+/**
+ Write multiple files into FV in reliable method.
+
+ @param FvDevice Firmware Volume Device.
+ @param NumOfFiles Total File number to be written.
+ @param FileData The array of EFI_FV_WRITE_FILE_DATA structure,
+ used to get name, attributes, type, etc
+ @param FileOperation The array of operation for each file.
+
+ @retval EFI_SUCCESS Files are added into FV.
+ @retval EFI_OUT_OF_RESOURCES No enough free PAD files to add the input files.
+ @retval EFI_INVALID_PARAMETER File number is less than or equal to 1.
+ @retval EFI_UNSUPPORTED File number exceeds the supported max numbers of files.
+
+**/
+EFI_STATUS
+FvCreateMultipleFiles (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN EFI_FV_WRITE_FILE_DATA *FileData,
+ IN BOOLEAN *FileOperation
+ );
+
+/**
+ Calculate the checksum for the FFS header.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+
+**/
+VOID
+SetHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ );
+
+/**
+ Calculate the checksum for the FFS File.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+ @param ActualFileSize The whole Ffs File Length.
+
+**/
+VOID
+SetFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN UINTN ActualFileSize
+ );
+
+/**
+ Get the alignment value from File Attributes.
+
+ @param FfsAttributes FFS attribute
+
+ @return Alignment value.
+
+**/
+UINTN
+GetRequiredAlignment (
+ IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
+ );
+
+/**
+ Locate Pad File for writing, this is got from FV Cache.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The required FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvLocatePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ );
+
+/**
+ Locate a suitable pad file for multiple file writing.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The totalsize that can hold these files.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitablePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ );
+
+/**
+ Locate a Free Space entry which can hold these files, including
+ meeting the alignment requirements.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The got total size that can hold these files.
+ @param FreeSpaceEntry The Free Space Entry that can hold these files.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitableFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ );
+
+/**
+ Change FFS file header state and write to FV.
+
+ @param FvDevice Cached FV image.
+ @param FfsHeader Points to the FFS file header to be updated.
+ @param State FFS file state to be set.
+
+ @retval EFI_SUCCESS File state is writen into FV.
+ @retval others File state can't be writen into FV.
+
+**/
+EFI_STATUS
+UpdateHeaderBit (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN EFI_FFS_FILE_STATE State
+ );
+
+/**
+ Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
+
+ @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
+ @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
+
+**/
+VOID
+FvFileAttrib2FfsFileAttrib (
+ IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
+ OUT UINT8 *FfsFileAttrib
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
new file mode 100644
index 0000000000..057266bb2b
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.inf
@@ -0,0 +1,74 @@
+## @file
+# FwVolDxe Driver.
+#
+# This driver produces Firmware Volume2 protocol with full services
+# (read/write, get/set) based on Firmware Volume Block protocol.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are
+# licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = FwVolDxe
+ MODULE_UNI_FILE = FwVolDxe.uni
+ FILE_GUID = 233C2592-1CEC-494a-A097-15DC96379777
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+
+ ENTRY_POINT = FwVolDriverInit
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ FwVolDriver.h
+ FwPadFile.c
+ Ffs.c
+ FwVolWrite.c
+ FwVolRead.c
+ FwVolAttrib.c
+ FwVol.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ BaseMemoryLib
+ BaseLib
+ UefiLib
+ UefiDriverEntryPoint
+ DebugLib
+
+
+[Guids]
+ gEfiFirmwareVolumeTopFileGuid ## CONSUMES ## File # VTF file
+ gEfiFirmwareFileSystem2Guid ## CONSUMES ## GUID # File System Guid
+ gEfiFirmwareFileSystem3Guid ## CONSUMES ## GUID # File System Guid
+
+[Protocols]
+ gEfiSectionExtractionProtocolGuid ## CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## PRODUCES
+
+[Depex]
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiSectionExtractionProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ FwVolDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.uni b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.uni
new file mode 100644
index 0000000000..89e44a4471
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxeExtra.uni
new file mode 100644
index 0000000000..b008de7a93
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
new file mode 100644
index 0000000000..8e2706bb8a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolRead.c
@@ -0,0 +1,629 @@
+/** @file
+ Implements functions to read firmware file.
+
+ Copyright (c) 2006 - 2012, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+/**
+Required Alignment Alignment Value in FFS Alignment Value in
+(bytes) Attributes Field Firmware Volume Interfaces
+1 0 0
+16 1 4
+128 2 7
+512 3 9
+1 KB 4 10
+4 KB 5 12
+32 KB 6 15
+64 KB 7 16
+**/
+UINT8 mFvAttributes[] = {0, 4, 7, 9, 10, 12, 15, 16};
+
+/**
+ Convert the FFS File Attributes to FV File Attributes.
+
+ @param FfsAttributes The attributes of UINT8 type.
+
+ @return The attributes of EFI_FV_FILE_ATTRIBUTES
+
+**/
+EFI_FV_FILE_ATTRIBUTES
+FfsAttributes2FvFileAttributes (
+ IN EFI_FFS_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINT8 DataAlignment;
+ EFI_FV_FILE_ATTRIBUTES FileAttribute;
+
+ DataAlignment = (UINT8) ((FfsAttributes & FFS_ATTRIB_DATA_ALIGNMENT) >> 3);
+ ASSERT (DataAlignment < 8);
+
+ FileAttribute = (EFI_FV_FILE_ATTRIBUTES) mFvAttributes[DataAlignment];
+
+ if ((FfsAttributes & FFS_ATTRIB_FIXED) == FFS_ATTRIB_FIXED) {
+ FileAttribute |= EFI_FV_FILE_ATTRIB_FIXED;
+ }
+
+ return FileAttribute;
+}
+
+/**
+ Given the input key, search for the next matching file in the volume.
+
+ @param This Indicates the calling context.
+ @param Key Key is a pointer to a caller allocated
+ buffer that contains implementation specific
+ data that is used to track where to begin
+ the search for the next file. The size of
+ the buffer must be at least This->KeySize
+ bytes long. To reinitialize the search and
+ begin from the beginning of the firmware
+ volume, the entire buffer must be cleared to
+ zero. Other than clearing the buffer to
+ initiate a new search, the caller must not
+ modify the data in the buffer between calls
+ to GetNextFile().
+ @param FileType FileType is a pointer to a caller allocated
+ EFI_FV_FILETYPE. The GetNextFile() API can
+ filter it's search for files based on the
+ value of *FileType input. A *FileType input
+ of 0 causes GetNextFile() to search for
+ files of all types. If a file is found, the
+ file's type is returned in *FileType.
+ *FileType is not modified if no file is
+ found.
+ @param NameGuid NameGuid is a pointer to a caller allocated
+ EFI_GUID. If a file is found, the file's
+ name is returned in *NameGuid. *NameGuid is
+ not modified if no file is found.
+ @param Attributes Attributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. If a file
+ is found, the file's attributes are returned
+ in *Attributes. *Attributes is not modified
+ if no file is found.
+ @param Size Size is a pointer to a caller allocated
+ UINTN. If a file is found, the file's size
+ is returned in *Size. *Size is not modified
+ if no file is found.
+
+ @retval EFI_SUCCESS Successfully find the file.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Fv could not read.
+ @retval EFI_NOT_FOUND No matching file found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter
+
+**/
+EFI_STATUS
+EFIAPI
+FvGetNextFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN OUT VOID *Key,
+ IN OUT EFI_FV_FILETYPE *FileType,
+ OUT EFI_GUID *NameGuid,
+ OUT EFI_FV_FILE_ATTRIBUTES *Attributes,
+ OUT UINTN *Size
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FFS_FILE_HEADER *FfsFileHeader;
+ UINTN *KeyValue;
+ LIST_ENTRY *Link;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ KeyValue = (UINTN *) Key;
+ FfsFileHeader = NULL;
+
+ //
+ // Check if read operation is enabled
+ //
+ if ((FvAttributes & EFI_FV2_READ_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ if (*FileType > EFI_FV_FILETYPE_SMM_CORE) {
+ //
+ // File type needs to be in 0 - 0x0D
+ //
+ return EFI_NOT_FOUND;
+ }
+
+ do {
+ if (*KeyValue == 0) {
+ //
+ // Search for 1st matching file
+ //
+ Link = &FvDevice->FfsFileListHeader;
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN) FfsFileEntry;
+
+ //
+ // we ignore pad files
+ //
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ continue;
+ }
+
+ if (*FileType == 0) {
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ break;
+ }
+
+ } else {
+ //
+ // Getting link from last Ffs
+ //
+ Link = (LIST_ENTRY *) (*KeyValue);
+ if (Link->ForwardLink == &FvDevice->FfsFileListHeader) {
+ return EFI_NOT_FOUND;
+ }
+
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Link->ForwardLink;
+ FfsFileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ //
+ // remember the key
+ //
+ *KeyValue = (UINTN) FfsFileEntry;
+
+ //
+ // we ignore pad files
+ //
+ if (FfsFileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) {
+ continue;
+ }
+
+ if (*FileType == EFI_FV_FILETYPE_ALL) {
+ break;
+ }
+
+ if (*FileType == FfsFileHeader->Type) {
+ break;
+ }
+ }
+ } while (Link->ForwardLink != &FvDevice->FfsFileListHeader);
+
+ //
+ // Cache this file entry
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ *FileType = FfsFileHeader->Type;
+ CopyGuid (NameGuid, &FfsFileHeader->Name);
+ *Attributes = FfsAttributes2FvFileAttributes (FfsFileHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *Attributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+
+ //
+ // we need to substract the header size
+ //
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ *Size = FFS_FILE2_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ *Size = FFS_FILE_SIZE (FfsFileHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
+ //
+ // specially deal with VTF file
+ //
+ UINT8 *SrcPtr;
+ UINT32 Tmp;
+
+ if (IS_FFS_FILE2 (FfsFileHeader)) {
+ SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ SrcPtr = ((UINT8 *) FfsFileHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ while (*Size >= 4) {
+ Tmp = *(UINT32 *) SrcPtr;
+ if (Tmp == 0) {
+ SrcPtr += 4;
+ (*Size) -= 4;
+ } else {
+ break;
+ }
+ }
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locates a file in the firmware volume and
+ copies it to the supplied buffer.
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN. On input *BufferSize indicates the
+ size in bytes of the memory region pointed
+ to by Buffer. On output, *BufferSize
+ contains the number of bytes required to
+ read the file.
+ @param FoundType FoundType is a pointer to a caller allocated
+ EFI_FV_FILETYPE that on successful return
+ from Read() contains the type of file read.
+ This output reflects the file type
+ irrespective of the value of the SectionType
+ input.
+ @param FileAttributes FileAttributes is a pointer to a caller
+ allocated EFI_FV_FILE_ATTRIBUTES. On
+ successful return from Read(),
+ *FileAttributes contains the attributes of
+ the file read.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINTN in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read to memory buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT EFI_FV_FILETYPE *FoundType,
+ OUT EFI_FV_FILE_ATTRIBUTES *FileAttributes,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ UINTN Key;
+ EFI_GUID SearchNameGuid;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FV_FILETYPE LocalFoundType;
+ EFI_FV_FILE_ATTRIBUTES LocalAttributes;
+ UINTN FileSize;
+ UINT8 *SrcPtr;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_HEADER *FfsHeader;
+ UINT8 *FileBuffer;
+
+ if (NULL == This || NULL == NameGuid) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // First check to see that FV is enabled for reads...
+ //
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ FfsHeader = NULL;
+
+ //
+ // Check if the file was read last time.
+ //
+ FfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (FfsFileEntry != NULL) {
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ }
+
+ if ((FfsFileEntry == NULL) || (!CompareGuid (&FfsHeader->Name, NameGuid))) {
+ //
+ // If not match or no file cached, search this file
+ //
+ Key = 0;
+ do {
+ LocalFoundType = 0;
+ Status = This->GetNextFile (
+ This,
+ &Key,
+ &LocalFoundType,
+ &SearchNameGuid,
+ &LocalAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+ } while (!CompareGuid (&SearchNameGuid, NameGuid));
+
+ //
+ // Get file entry
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Update the cache
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ FfsHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+
+ } else {
+ //
+ // Get File Size of the cached file
+ //
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FileSize = FFS_FILE2_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ FileSize = FFS_FILE_SIZE (FfsHeader) - sizeof (EFI_FFS_FILE_HEADER);
+ }
+ }
+ //
+ // Get file info
+ //
+ *FoundType = FfsHeader->Type;
+ *FileAttributes = FfsAttributes2FvFileAttributes (FfsHeader->Attributes);
+ if ((FvDevice->FwVolHeader->Attributes & EFI_FVB2_MEMORY_MAPPED) == EFI_FVB2_MEMORY_MAPPED) {
+ *FileAttributes |= EFI_FV_FILE_ATTRIB_MEMORY_MAPPED;
+ }
+ *AuthenticationStatus = 0;
+
+ //
+ // If Buffer is NULL, we only want to get some information
+ //
+ if (Buffer == NULL) {
+ *BufferSize = FileSize;
+ return EFI_SUCCESS;
+ }
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ SrcPtr = ((UINT8 *) FfsHeader) + sizeof (EFI_FFS_FILE_HEADER);
+ }
+
+ if (CompareGuid (&gEfiFirmwareVolumeTopFileGuid, NameGuid)) {
+ //
+ // specially deal with VTF file
+ //
+ UINT32 Tmp;
+
+ while (FileSize >= 4) {
+ Tmp = *(UINT32 *) SrcPtr;
+ if (Tmp == 0) {
+ SrcPtr += 4;
+ FileSize -= 4;
+ } else {
+ break;
+ }
+ }
+ }
+ //
+ // If we drop out of the above loop, we've found the correct file header...
+ //
+ if (*Buffer == NULL) {
+ FileBuffer = AllocateCopyPool (FileSize, SrcPtr);
+ if (FileBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ *BufferSize = FileSize;
+ *Buffer = FileBuffer;
+
+ return EFI_SUCCESS;
+ }
+ //
+ // If the user's buffer is smaller than the file size, then copy as much
+ // as we can and return an appropriate status.
+ //
+ if (FileSize > *BufferSize) {
+ CopyMem (*Buffer, SrcPtr, *BufferSize);
+ *BufferSize = FileSize;
+ return EFI_WARN_BUFFER_TOO_SMALL;
+ }
+ //
+ // User's buffer size is ok, so copy the entire file to their buffer.
+ //
+ *BufferSize = FileSize;
+ CopyMem (*Buffer, SrcPtr, *BufferSize);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Locates a section in a given FFS File and
+ copies it to the supplied buffer (not including section header).
+
+ @param This Indicates the calling context.
+ @param NameGuid Pointer to an EFI_GUID, which is the
+ filename.
+ @param SectionType Indicates the section type to return.
+ @param SectionInstance Indicates which instance of sections with a
+ type of SectionType to return.
+ @param Buffer Buffer is a pointer to pointer to a buffer
+ in which the file or section contents or are
+ returned.
+ @param BufferSize BufferSize is a pointer to caller allocated
+ UINTN.
+ @param AuthenticationStatus AuthenticationStatus is a pointer to a
+ caller allocated UINT32 in which the
+ authentication status is returned.
+
+ @retval EFI_SUCCESS Successfully read the file section into
+ buffer.
+ @retval EFI_WARN_BUFFER_TOO_SMALL Buffer too small.
+ @retval EFI_NOT_FOUND Section not found.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_ACCESS_DENIED Could not read.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+
+**/
+EFI_STATUS
+EFIAPI
+FvReadFileSection (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN CONST EFI_GUID *NameGuid,
+ IN EFI_SECTION_TYPE SectionType,
+ IN UINTN SectionInstance,
+ IN OUT VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ EFI_STATUS Status;
+ FV_DEVICE *FvDevice;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ UINT8 *FileBuffer;
+ EFI_SECTION_EXTRACTION_PROTOCOL *Sep;
+ UINTN StreamHandle;
+
+ if (NULL == This || NULL == NameGuid || Buffer == NULL) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ Status = This->GetVolumeAttributes (This, &FvAttributes);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // First check to see that FV is enabled for reads...
+ //
+ if (0 == (FvAttributes & EFI_FV2_READ_STATUS)) {
+ return EFI_ACCESS_DENIED;
+ }
+ //
+ // Read the whole file into buffer
+ //
+ FileBuffer = NULL;
+ Status = This->ReadFile (
+ This,
+ NameGuid,
+ (VOID **) &FileBuffer,
+ &FileSize,
+ &FileType,
+ &FileAttributes,
+ AuthenticationStatus
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Check to see that the file actually HAS sections before we go any further.
+ //
+ if (FileType == EFI_FV_FILETYPE_RAW) {
+ FreePool (FileBuffer);
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Located the protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiSectionExtractionProtocolGuid,
+ NULL,
+ (VOID **) &Sep
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ Status = Sep->OpenSectionStream (
+ Sep,
+ FileSize,
+ FileBuffer,
+ &StreamHandle
+ );
+
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ if (SectionType == 0) {
+ //
+ // We need the whole section stream
+ //
+ Status = Sep->GetSection (
+ Sep,
+ StreamHandle,
+ NULL,
+ NULL,
+ 0,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus
+ );
+ } else {
+ Status = Sep->GetSection (
+ Sep,
+ StreamHandle,
+ &SectionType,
+ NULL,
+ SectionInstance,
+ Buffer,
+ BufferSize,
+ AuthenticationStatus
+ );
+ }
+
+ if (!EFI_ERROR (Status)) {
+ //
+ // Inherit the authentication status.
+ //
+ *AuthenticationStatus |= FvDevice->AuthenticationStatus;
+ }
+
+ //
+ // Handle AuthenticationStatus if necessary
+ //
+ Sep->CloseSectionStream (Sep, StreamHandle);
+
+ FreePool (FileBuffer);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
new file mode 100644
index 0000000000..7f23b51d83
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/FwVolDxe/FwVolWrite.c
@@ -0,0 +1,1586 @@
+/** @file
+ Implements write firmware file.
+
+ Copyright (c) 2006 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "FwVolDriver.h"
+
+/**
+ Calculate the checksum for the FFS header.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+
+**/
+VOID
+SetHeaderChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader
+ )
+{
+ EFI_FFS_FILE_STATE State;
+ UINT8 FileChecksum;
+
+ //
+ // The state and the File checksum are not included
+ //
+ State = FfsHeader->State;
+ FfsHeader->State = 0;
+
+ FileChecksum = FfsHeader->IntegrityCheck.Checksum.File;
+ FfsHeader->IntegrityCheck.Checksum.File = 0;
+
+ FfsHeader->IntegrityCheck.Checksum.Header = 0;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER2)
+ );
+ } else {
+ FfsHeader->IntegrityCheck.Checksum.Header = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader,
+ sizeof (EFI_FFS_FILE_HEADER)
+ );
+ }
+
+ FfsHeader->State = State;
+ FfsHeader->IntegrityCheck.Checksum.File = FileChecksum;
+
+ return ;
+}
+
+/**
+ Calculate the checksum for the FFS File.
+
+ @param FfsHeader FFS File Header which needs to calculate the checksum
+ @param ActualFileSize The whole Ffs File Length.
+
+**/
+VOID
+SetFileChecksum (
+ IN EFI_FFS_FILE_HEADER *FfsHeader,
+ IN UINTN ActualFileSize
+ )
+{
+ if ((FfsHeader->Attributes & FFS_ATTRIB_CHECKSUM) != 0) {
+
+ FfsHeader->IntegrityCheck.Checksum.File = 0;
+
+ if (IS_FFS_FILE2 (FfsHeader)) {
+ FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER2),
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER2)
+ );
+ } else {
+ FfsHeader->IntegrityCheck.Checksum.File = CalculateCheckSum8 (
+ (UINT8 *) FfsHeader + sizeof (EFI_FFS_FILE_HEADER),
+ ActualFileSize - sizeof (EFI_FFS_FILE_HEADER)
+ );
+ }
+
+ } else {
+
+ FfsHeader->IntegrityCheck.Checksum.File = FFS_FIXED_CHECKSUM;
+
+ }
+
+ return ;
+}
+
+/**
+ Get the alignment value from File Attributes.
+
+ @param FfsAttributes FFS attribute
+
+ @return Alignment value.
+
+**/
+UINTN
+GetRequiredAlignment (
+ IN EFI_FV_FILE_ATTRIBUTES FfsAttributes
+ )
+{
+ UINTN AlignmentValue;
+
+ AlignmentValue = FfsAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT;
+
+ if (AlignmentValue <= 3) {
+ return 0x08;
+ }
+
+ if (AlignmentValue > 16) {
+ //
+ // Anyway, we won't reach this code
+ //
+ return 0x08;
+ }
+
+ return (UINTN)1 << AlignmentValue;
+
+}
+
+/**
+ Calculate the leading Pad file size to meet the alignment requirement.
+
+ @param FvDevice Cached Firmware Volume.
+ @param StartAddress The starting address to write the FFS File.
+ @param BufferSize The FFS File Buffer Size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+
+ @return The required Pad File Size.
+
+**/
+UINTN
+CalculatePadFileSize (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_PHYSICAL_ADDRESS StartAddress,
+ IN UINTN BufferSize,
+ IN UINTN RequiredAlignment
+ )
+{
+ UINTN DataStartPos;
+ UINTN RelativePos;
+ UINTN PadSize;
+
+ if (BufferSize > 0x00FFFFFF) {
+ DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ DataStartPos = (UINTN) StartAddress + sizeof (EFI_FFS_FILE_HEADER);
+ }
+ RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv;
+
+ PadSize = 0;
+
+ while ((RelativePos & (RequiredAlignment - 1)) != 0) {
+ RelativePos++;
+ PadSize++;
+ }
+ //
+ // If padsize is 0, no pad file needed;
+ // If padsize is great than 24, then pad file can be created
+ //
+ if ((PadSize == 0) || (PadSize >= sizeof (EFI_FFS_FILE_HEADER))) {
+ return PadSize;
+ }
+
+ //
+ // Perhaps following method can save space
+ //
+ RelativePos = DataStartPos - (UINTN) FvDevice->CachedFv + sizeof (EFI_FFS_FILE_HEADER);
+ PadSize = sizeof (EFI_FFS_FILE_HEADER);
+
+ while ((RelativePos & (RequiredAlignment - 1)) != 0) {
+ RelativePos++;
+ PadSize++;
+ }
+
+ return PadSize;
+}
+
+/**
+ Convert EFI_FV_FILE_ATTRIBUTES to FFS_FILE_ATTRIBUTES.
+
+ @param FvFileAttrib The value of EFI_FV_FILE_ATTRIBUTES
+ @param FfsFileAttrib Pointer to the got FFS_FILE_ATTRIBUTES value.
+
+**/
+VOID
+FvFileAttrib2FfsFileAttrib (
+ IN EFI_FV_FILE_ATTRIBUTES FvFileAttrib,
+ OUT UINT8 *FfsFileAttrib
+ )
+{
+ UINT8 FvFileAlignment;
+ UINT8 FfsFileAlignment;
+
+ FvFileAlignment = (UINT8) (FvFileAttrib & EFI_FV_FILE_ATTRIB_ALIGNMENT);
+ FfsFileAlignment = 0;
+
+ switch (FvFileAlignment) {
+ case 0:
+ //
+ // fall through
+ //
+ case 1:
+ //
+ // fall through
+ //
+ case 2:
+ //
+ // fall through
+ //
+ case 3:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 0;
+ break;
+
+ case 4:
+ //
+ // fall through
+ //
+ case 5:
+ //
+ // fall through
+ //
+ case 6:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 1;
+ break;
+
+ case 7:
+ //
+ // fall through
+ //
+ case 8:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 2;
+ break;
+
+ case 9:
+ FfsFileAlignment = 3;
+ break;
+
+ case 10:
+ //
+ // fall through
+ //
+ case 11:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 4;
+ break;
+
+ case 12:
+ //
+ // fall through
+ //
+ case 13:
+ //
+ // fall through
+ //
+ case 14:
+ //
+ // fall through
+ //
+ FfsFileAlignment = 5;
+ break;
+
+ case 15:
+ FfsFileAlignment = 6;
+ break;
+
+ case 16:
+ FfsFileAlignment = 7;
+ break;
+ }
+
+ *FfsFileAttrib = (UINT8) (FfsFileAlignment << 3);
+
+ return ;
+}
+
+/**
+ Locate a free space entry that can hold this FFS file.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param FreeSpaceEntry Pointer to the Free Space Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvLocateFreeSpaceEntry (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ )
+{
+ FREE_SPACE_ENTRY *FreeSpaceListEntry;
+ LIST_ENTRY *Link;
+ UINTN PadFileSize;
+
+ Link = FvDevice->FreeSpaceHeader.ForwardLink;
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
+
+ //
+ // Loop the free space entry list to find one that can hold the
+ // required the file size
+ //
+ while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
+ PadFileSize = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceListEntry->StartingAddress,
+ Size,
+ RequiredAlignment
+ );
+ if (FreeSpaceListEntry->Length >= Size + PadFileSize) {
+ *FreeSpaceEntry = FreeSpaceListEntry;
+ *PadSize = PadFileSize;
+ return EFI_SUCCESS;
+ }
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+
+}
+
+/**
+ Locate Pad File for writing, this is got from FV Cache.
+
+ @param FvDevice Cached Firmware Volume.
+ @param Size The required FFS file size.
+ @param RequiredAlignment FFS File Data alignment requirement.
+ @param PadSize Pointer to the size of leading Pad File.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvLocatePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Size,
+ IN UINTN RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ )
+{
+ FFS_FILE_LIST_ENTRY *FileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINTN PadAreaLength;
+ UINTN PadFileSize;
+ UINTN HeaderSize;
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+
+ //
+ // travel through the whole file list to get the pad file entry
+ //
+ while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
+ //
+ // we find one valid pad file, check its free area length
+ //
+ if (IS_FFS_FILE2 (FileHeader)) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
+ }
+
+ PadFileSize = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize,
+ Size,
+ RequiredAlignment
+ );
+ if (PadAreaLength >= (Size + PadFileSize)) {
+ *PadSize = PadFileSize;
+ *PadFileEntry = FileEntry;
+ return EFI_SUCCESS;
+ }
+ }
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate a suitable pad file for multiple file writing.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The totalsize that can hold these files.
+ @param PadFileEntry Pointer to the Pad File Entry that meets the requirement.
+
+ @retval EFI_SUCCESS The required pad file is found.
+ @retval EFI_NOT_FOUND The required pad file can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitablePadFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FFS_FILE_LIST_ENTRY **PadFileEntry
+ )
+{
+ FFS_FILE_LIST_ENTRY *FileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ UINTN PadAreaLength;
+ UINTN TotalSize;
+ UINTN Index;
+ UINTN HeaderSize;
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) FvDevice->FfsFileListHeader.ForwardLink;
+
+ //
+ // travel through the whole file list to get the pad file entry
+ //
+ while (FileEntry != (FFS_FILE_LIST_ENTRY *) &FvDevice->FfsFileListHeader) {
+
+ FileHeader = (EFI_FFS_FILE_HEADER *) FileEntry->FfsHeader;
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if ((FileHeader->Type == EFI_FV_FILETYPE_FFS_PAD) && (FileState == EFI_FILE_DATA_VALID)) {
+ //
+ // we find one valid pad file, check its length
+ //
+ if (IS_FFS_FILE2 (FileHeader)) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ PadAreaLength = FFS_FILE2_SIZE (FileHeader) - HeaderSize;
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ PadAreaLength = FFS_FILE_SIZE (FileHeader) - HeaderSize;
+ }
+ TotalSize = 0;
+
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ PadSize[Index] = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader + HeaderSize + TotalSize,
+ BufferSize[Index],
+ RequiredAlignment[Index]
+ );
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+
+ if (TotalSize > PadAreaLength) {
+ break;
+ }
+ }
+
+ if (PadAreaLength >= TotalSize) {
+ *PadFileEntry = FileEntry;
+ *TotalSizeNeeded = TotalSize;
+ return EFI_SUCCESS;
+ }
+ }
+
+ FileEntry = (FFS_FILE_LIST_ENTRY *) (FileEntry->Link.ForwardLink);
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Locate a Free Space entry which can hold these files, including
+ meeting the alignment requirements.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NumOfFiles The number of Files that needed updating
+ @param BufferSize The array of each file size.
+ @param RequiredAlignment The array of of FFS File Data alignment requirement.
+ @param PadSize The array of size of each leading Pad File.
+ @param TotalSizeNeeded The got total size that can hold these files.
+ @param FreeSpaceEntry The Free Space Entry that can hold these files.
+
+ @retval EFI_SUCCESS The free space entry is found.
+ @retval EFI_NOT_FOUND The free space entry can't be found.
+
+**/
+EFI_STATUS
+FvSearchSuitableFreeSpace (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN NumOfFiles,
+ IN UINTN *BufferSize,
+ IN UINTN *RequiredAlignment,
+ OUT UINTN *PadSize,
+ OUT UINTN *TotalSizeNeeded,
+ OUT FREE_SPACE_ENTRY **FreeSpaceEntry
+ )
+{
+ FREE_SPACE_ENTRY *FreeSpaceListEntry;
+ LIST_ENTRY *Link;
+ UINTN TotalSize;
+ UINTN Index;
+ UINT8 *StartAddr;
+
+ Link = FvDevice->FreeSpaceHeader.ForwardLink;
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) Link;
+
+ while ((LIST_ENTRY *) FreeSpaceListEntry != &FvDevice->FreeSpaceHeader) {
+ TotalSize = 0;
+ StartAddr = FreeSpaceListEntry->StartingAddress;
+
+ //
+ // Calculate the totalsize we need
+ //
+ for (Index = 0; Index < NumOfFiles; Index++) {
+ //
+ // Perhaps we don't need an EFI_FFS_FILE_HEADER, the first file
+ // have had its leading pad file.
+ //
+ PadSize[Index] = CalculatePadFileSize (
+ FvDevice,
+ (EFI_PHYSICAL_ADDRESS) (UINTN) StartAddr + TotalSize,
+ BufferSize[Index],
+ RequiredAlignment[Index]
+ );
+
+ TotalSize += PadSize[Index];
+ TotalSize += BufferSize[Index];
+
+ if (TotalSize > FreeSpaceListEntry->Length) {
+ break;
+ }
+ }
+
+ if (FreeSpaceListEntry->Length >= TotalSize) {
+ *FreeSpaceEntry = FreeSpaceListEntry;
+ *TotalSizeNeeded = TotalSize;
+ return EFI_SUCCESS;
+ }
+
+ FreeSpaceListEntry = (FREE_SPACE_ENTRY *) FreeSpaceListEntry->Link.ForwardLink;
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ Calculate the length of the remaining space in FV.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Current offset to FV base address.
+ @param Lba LBA number for the current offset.
+ @param LOffset Offset in block for the current offset.
+
+ @return the length of remaining space.
+
+**/
+UINTN
+CalculateRemainingLength (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ OUT EFI_LBA *Lba,
+ OUT UINTN *LOffset
+ )
+{
+ LIST_ENTRY *Link;
+ LBA_ENTRY *LbaEntry;
+ UINTN Count;
+
+ Count = 0;
+ *Lba = 0;
+ Link = FvDevice->LbaHeader.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+ if (Count > Offset) {
+ break;
+ }
+
+ Count += LbaEntry->BlockLength;
+ (*Lba)++;
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ if (Count <= Offset) {
+ return 0;
+ }
+
+ Link = LbaEntry->Link.BackLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+
+ (*Lba)--;
+ *LOffset = (UINTN) (LbaEntry->BlockLength - (Count - Offset));
+
+ Count = 0;
+ while (&LbaEntry->Link != &FvDevice->LbaHeader) {
+
+ Count += LbaEntry->BlockLength;
+
+ Link = LbaEntry->Link.ForwardLink;
+ LbaEntry = (LBA_ENTRY *) Link;
+ }
+
+ Count -= *LOffset;
+
+ return Count;
+}
+
+/**
+ Writes data beginning at Lba:Offset from FV. The write terminates either
+ when *NumBytes of data have been written, or when the firmware end is
+ reached. *NumBytes is updated to reflect the actual number of bytes
+ written.
+
+ @param FvDevice Cached Firmware Volume
+ @param Offset Offset in the block at which to begin write
+ @param NumBytes At input, indicates the requested write size.
+ At output, indicates the actual number of bytes written.
+ @param Buffer Buffer containing source data for the write.
+
+ @retval EFI_SUCCESS Data is successfully written into FV.
+ @return error Data is failed written.
+
+**/
+EFI_STATUS
+FvcWrite (
+ IN FV_DEVICE *FvDevice,
+ IN UINTN Offset,
+ IN OUT UINTN *NumBytes,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *Fvb;
+ EFI_LBA Lba;
+ UINTN LOffset;
+ EFI_FVB_ATTRIBUTES_2 FvbAttributes;
+ UINTN RemainingLength;
+ UINTN WriteLength;
+ UINT8 *TmpBuffer;
+
+ LOffset = 0;
+ RemainingLength = CalculateRemainingLength (FvDevice, Offset, &Lba, &LOffset);
+ if ((UINTN) (*NumBytes) > RemainingLength) {
+ *NumBytes = (UINTN) RemainingLength;
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Fvb = FvDevice->Fvb;
+
+ Status = Fvb->GetAttributes (
+ Fvb,
+ &FvbAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ if ((FvbAttributes & EFI_FV2_WRITE_STATUS) == 0) {
+ return EFI_ACCESS_DENIED;
+ }
+
+ RemainingLength = *NumBytes;
+ WriteLength = RemainingLength;
+ TmpBuffer = Buffer;
+
+ do {
+ Status = Fvb->Write (
+ Fvb,
+ Lba,
+ LOffset,
+ &WriteLength,
+ TmpBuffer
+ );
+ if (!EFI_ERROR (Status)) {
+ goto Done;
+ }
+
+ if (Status == EFI_BAD_BUFFER_SIZE) {
+ Lba++;
+ LOffset = 0;
+ TmpBuffer += WriteLength;
+ RemainingLength -= WriteLength;
+ WriteLength = (UINTN) RemainingLength;
+
+ continue;
+ } else {
+ return Status;
+ }
+ } while (1);
+
+Done:
+ return EFI_SUCCESS;
+}
+
+/**
+ Create a new FFS file into Firmware Volume device.
+
+ @param FvDevice Cached Firmware Volume.
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains
+ a File Header which is in init state).
+ @param BufferSize The size of FfsFileBuffer.
+ @param ActualFileSize The actual file length, it may not be multiples of 8.
+ @param FileName The FFS File Name.
+ @param FileType The FFS File Type.
+ @param FileAttributes The Attributes of the FFS File to be created.
+
+ @retval EFI_SUCCESS FFS fle is added into FV.
+ @retval EFI_INVALID_PARAMETER File type is not valid.
+ @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
+ @retval EFI_NOT_FOUND FV has no enough space for the added file.
+
+**/
+EFI_STATUS
+FvCreateNewFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ EFI_PHYSICAL_ADDRESS BufferPtr;
+ UINTN Offset;
+ UINTN NumBytesWritten;
+ UINTN StateOffset;
+ FREE_SPACE_ENTRY *FreeSpaceEntry;
+ UINTN RequiredAlignment;
+ UINTN PadFileSize;
+ FFS_FILE_LIST_ENTRY *PadFileEntry;
+ EFI_FFS_FILE_ATTRIBUTES TmpFileAttribute;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ UINTN HeaderSize;
+
+ //
+ // File Type: 0x0E~0xE0 are reserved
+ //
+ if ((FileType > EFI_FV_FILETYPE_SMM_CORE) && (FileType < 0xE0)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // First find a free space that can hold this image.
+ // Check alignment, FFS at least must be aligned at 8-byte boundry
+ //
+ RequiredAlignment = GetRequiredAlignment (FileAttributes);
+
+ Status = FvLocateFreeSpaceEntry (
+ FvDevice,
+ BufferSize,
+ RequiredAlignment,
+ &PadFileSize,
+ &FreeSpaceEntry
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // Maybe we need to find a PAD file that can hold this image
+ //
+ Status = FvCreateNewFileInsidePadFile (
+ FvDevice,
+ FfsFileBuffer,
+ BufferSize,
+ ActualFileSize,
+ FileName,
+ FileType,
+ FileAttributes
+ );
+
+ return Status;
+ }
+
+ BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
+
+ //
+ // If we need a leading PAD File, create it first.
+ //
+ if (PadFileSize != 0) {
+ Status = FvCreatePadFileInFreeSpace (
+ FvDevice,
+ FreeSpaceEntry,
+ PadFileSize - sizeof (EFI_FFS_FILE_HEADER),
+ &PadFileEntry
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+ //
+ // Maybe we create a pad file, so re-get the free space starting address
+ // and length
+ //
+ BufferPtr = (EFI_PHYSICAL_ADDRESS) (UINTN) FreeSpaceEntry->StartingAddress;
+
+ //
+ // File creation step 1: Allocate File Header,
+ // Mark EFI_FILE_HEADER_CONSTRUCTION bit to TRUE,
+ // Write Name, IntegrityCheck.Header, Type, Attributes, and Size
+ //
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileBuffer;
+ if (ActualFileSize > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ } else {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ }
+ SetFileState (EFI_FILE_HEADER_CONSTRUCTION, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ HeaderSize
+ );
+
+ //
+ // update Free Space Entry, now need to substract the file header length
+ //
+ FreeSpaceEntry->StartingAddress += HeaderSize;
+ FreeSpaceEntry->Length -= HeaderSize;
+
+ CopyGuid (&FileHeader->Name, FileName);
+ FileHeader->Type = FileType;
+
+ //
+ // Convert FvFileAttribute to FfsFileAttributes
+ //
+ FvFileAttrib2FfsFileAttrib (FileAttributes, &TmpFileAttribute);
+
+ FileHeader->Attributes = TmpFileAttribute;
+
+ //
+ // File size is including the FFS File Header.
+ //
+ if (ActualFileSize > 0x00FFFFFF) {
+ ((EFI_FFS_FILE_HEADER2 *) FileHeader)->ExtendedSize = (UINT32) ActualFileSize;
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ FileHeader->Attributes |= FFS_ATTRIB_LARGE_FILE;
+ } else {
+ *(UINT32 *) FileHeader->Size &= 0xFF000000;
+ *(UINT32 *) FileHeader->Size |= ActualFileSize;
+ }
+
+ SetHeaderChecksum (FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+
+ NumBytesWritten = HeaderSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ (UINT8 *) FileHeader
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ HeaderSize
+ );
+
+ //
+ // end of step 1
+ //
+ // File creation step 2:
+ // MARK EFI_FILE_HEADER_VALID bit to TRUE,
+ // Write IntegrityCheck.File, File Data
+ //
+ SetFileState (EFI_FILE_HEADER_VALID, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ HeaderSize
+ );
+
+ //
+ // update Free Space Entry, now need to substract the file data length
+ //
+ FreeSpaceEntry->StartingAddress += (BufferSize - HeaderSize);
+ FreeSpaceEntry->Length -= (BufferSize - HeaderSize);
+
+ //
+ // Calculate File Checksum
+ //
+ SetFileChecksum (FileHeader, ActualFileSize);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+
+ NumBytesWritten = BufferSize;
+ Status = FvcWrite (
+ FvDevice,
+ Offset,
+ &NumBytesWritten,
+ FfsFileBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // each time write block successfully, write also to cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FfsFileBuffer,
+ NumBytesWritten
+ );
+
+ //
+ // Step 3: Mark EFI_FILE_DATA_VALID to TRUE
+ //
+ SetFileState (EFI_FILE_DATA_VALID, FileHeader);
+
+ Offset = (UINTN) (BufferPtr - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // update header 2 cache
+ //
+ CopyMem (
+ (UINT8 *) (UINTN) BufferPtr,
+ FileHeader,
+ HeaderSize
+ );
+
+ //
+ // If successfully, insert an FfsFileEntry at the end of ffs file list
+ //
+
+ FfsFileEntry = AllocateZeroPool (sizeof (FFS_FILE_LIST_ENTRY));
+ ASSERT (FfsFileEntry != NULL);
+ FfsFileEntry->FfsHeader = (UINT8 *) (UINTN) BufferPtr;
+ InsertTailList (&FvDevice->FfsFileListHeader, &FfsFileEntry->Link);
+
+ //
+ // Set cache file to this file
+ //
+ FvDevice->CurrentFfsFile = FfsFileEntry;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Update a File, so after successful update, there are 2 files existing
+ in FV, one is marked for deleted, and another one is valid.
+
+ @param FvDevice Cached Firmware Volume.
+ @param FfsFileBuffer A buffer that holds an FFS file,(it contains
+ a File Header which is in init state).
+ @param BufferSize The size of FfsFileBuffer.
+ @param ActualFileSize The actual file length, it may not be multiples of 8.
+ @param FileName The FFS File Name.
+ @param NewFileType The FFS File Type.
+ @param NewFileAttributes The Attributes of the FFS File to be created.
+
+ @retval EFI_SUCCESS FFS fle is updated into FV.
+ @retval EFI_INVALID_PARAMETER File type is not valid.
+ @retval EFI_DEVICE_ERROR FV doesn't set writable attribute.
+ @retval EFI_NOT_FOUND FV has no enough space for the added file.
+ FFS with same file name is not found in FV.
+
+**/
+EFI_STATUS
+FvUpdateFile (
+ IN FV_DEVICE *FvDevice,
+ IN UINT8 *FfsFileBuffer,
+ IN UINTN BufferSize,
+ IN UINTN ActualFileSize,
+ IN EFI_GUID *FileName,
+ IN EFI_FV_FILETYPE NewFileType,
+ IN EFI_FV_FILE_ATTRIBUTES NewFileAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN NumBytesWritten;
+ EFI_FV_FILETYPE OldFileType;
+ EFI_FV_FILE_ATTRIBUTES OldFileAttributes;
+ UINTN OldFileSize;
+ EFI_FFS_FILE_HEADER *OldFileHeader;
+ UINTN OldOffset;
+ UINTN OldStateOffset;
+ FFS_FILE_LIST_ENTRY *OldFfsFileEntry;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+
+ Fv = &FvDevice->Fv;
+
+ //
+ // Step 1, find old file,
+ // Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE in the older header
+ //
+
+ //
+ // Check if the file was read last time.
+ //
+ OldFileHeader = NULL;
+ OldFfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (OldFfsFileEntry != NULL) {
+ OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
+ }
+
+ if ((OldFfsFileEntry == NULL) || (!CompareGuid (&OldFileHeader->Name, FileName))) {
+ Key = 0;
+ do {
+ OldFileType = 0;
+ Status = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &OldFileType,
+ &FileNameGuid,
+ &OldFileAttributes,
+ &OldFileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while (!CompareGuid (&FileNameGuid, FileName));
+
+ //
+ // Get FfsFileEntry from the search key
+ //
+ OldFfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Double check file state before being ready to be removed
+ //
+ OldFileHeader = (EFI_FFS_FILE_HEADER *) OldFfsFileEntry->FfsHeader;
+ } else {
+ //
+ // Mark the cache file to invalid
+ //
+ FvDevice->CurrentFfsFile = NULL;
+ }
+ //
+ // Update File: Mark EFI_FILE_MARKED_FOR_UPDATE to TRUE
+ //
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
+
+ OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
+ OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ OldStateOffset,
+ &NumBytesWritten,
+ &OldFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_MARKED_FOR_UPDATE, OldFileHeader);
+
+ return Status;
+ }
+
+ //
+ // Step 2, Create New Files
+ //
+ Status = FvCreateNewFile (
+ FvDevice,
+ FfsFileBuffer,
+ BufferSize,
+ ActualFileSize,
+ FileName,
+ NewFileType,
+ NewFileAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If successfully, remove this file entry,
+ // although delete file may fail.
+ //
+ (OldFfsFileEntry->Link.BackLink)->ForwardLink = OldFfsFileEntry->Link.ForwardLink;
+ (OldFfsFileEntry->Link.ForwardLink)->BackLink = OldFfsFileEntry->Link.BackLink;
+ FreePool (OldFfsFileEntry);
+
+ //
+ // Step 3: Delete old files,
+ // by marking EFI_FILE_DELETED to TRUE
+ //
+ SetFileState (EFI_FILE_DELETED, OldFileHeader);
+
+ OldOffset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) OldFileHeader - FvDevice->CachedFv);
+ OldStateOffset = OldOffset + (UINT8 *) &OldFileHeader->State - (UINT8 *) OldFileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ OldStateOffset,
+ &NumBytesWritten,
+ &OldFileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_DELETED, OldFileHeader);
+
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Deleted a given file from FV device.
+
+ @param FvDevice Cached Firmware Volume.
+ @param NameGuid The FFS File Name.
+
+ @retval EFI_SUCCESS FFS file with the specified FFS name is removed.
+ @retval EFI_NOT_FOUND FFS file with the specified FFS name is not found.
+
+**/
+EFI_STATUS
+FvDeleteFile (
+ IN FV_DEVICE *FvDevice,
+ IN EFI_GUID *NameGuid
+ )
+{
+ EFI_STATUS Status;
+ UINTN Key;
+ EFI_GUID FileNameGuid;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN FileSize;
+ EFI_FFS_FILE_HEADER *FileHeader;
+ FFS_FILE_LIST_ENTRY *FfsFileEntry;
+ EFI_FFS_FILE_STATE FileState;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *Fv;
+ UINTN Offset;
+ UINTN StateOffset;
+ UINTN NumBytesWritten;
+
+ Fv = &FvDevice->Fv;
+
+ //
+ // Check if the file was read last time.
+ //
+ FileHeader = NULL;
+ FfsFileEntry = FvDevice->CurrentFfsFile;
+
+ if (FfsFileEntry != NULL) {
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ }
+
+ if ((FfsFileEntry == NULL) || (!CompareGuid (&FileHeader->Name, NameGuid))) {
+ //
+ // Next search for the file using GetNextFile
+ //
+ Key = 0;
+ do {
+ FileType = 0;
+ Status = Fv->GetNextFile (
+ Fv,
+ &Key,
+ &FileType,
+ &FileNameGuid,
+ &FileAttributes,
+ &FileSize
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } while (!CompareGuid (&FileNameGuid, NameGuid));
+
+ //
+ // Get FfsFileEntry from the search key
+ //
+ FfsFileEntry = (FFS_FILE_LIST_ENTRY *) Key;
+
+ //
+ // Double check file state before being ready to be removed
+ //
+ FileHeader = (EFI_FFS_FILE_HEADER *) FfsFileEntry->FfsHeader;
+ } else {
+ //
+ // Mark the cache file to NULL
+ //
+ FvDevice->CurrentFfsFile = NULL;
+ }
+
+ FileState = GetFileState (FvDevice->ErasePolarity, FileHeader);
+
+ if (FileState == EFI_FILE_HEADER_INVALID) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (FileState == EFI_FILE_DELETED) {
+ return EFI_NOT_FOUND;
+ }
+ //
+ // Delete File: Mark EFI_FILE_DELETED to TRUE
+ //
+ SetFileState (EFI_FILE_DELETED, FileHeader);
+
+ Offset = (UINTN) ((EFI_PHYSICAL_ADDRESS) (UINTN) FileHeader - FvDevice->CachedFv);
+ StateOffset = Offset + (UINT8 *) &FileHeader->State - (UINT8 *) FileHeader;
+
+ NumBytesWritten = sizeof (EFI_FFS_FILE_STATE);
+ Status = FvcWrite (
+ FvDevice,
+ StateOffset,
+ &NumBytesWritten,
+ &FileHeader->State
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // if failed, write the bit back in the cache, its XOR operation.
+ //
+ SetFileState (EFI_FILE_DELETED, FileHeader);
+
+ return Status;
+ }
+ //
+ // If successfully, remove this file entry
+ //
+ FvDevice->CurrentFfsFile = NULL;
+
+ (FfsFileEntry->Link.BackLink)->ForwardLink = FfsFileEntry->Link.ForwardLink;
+ (FfsFileEntry->Link.ForwardLink)->BackLink = FfsFileEntry->Link.BackLink;
+ FreePool (FfsFileEntry);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Writes one or more files to the firmware volume.
+
+ @param This Indicates the calling context.
+ @param NumberOfFiles Number of files.
+ @param WritePolicy WritePolicy indicates the level of reliability
+ for the write in the event of a power failure or
+ other system failure during the write operation.
+ @param FileData FileData is an pointer to an array of
+ EFI_FV_WRITE_DATA. Each element of array
+ FileData represents a file to be written.
+
+ @retval EFI_SUCCESS Files successfully written to firmware volume
+ @retval EFI_OUT_OF_RESOURCES Not enough buffer to be allocated.
+ @retval EFI_DEVICE_ERROR Device error.
+ @retval EFI_WRITE_PROTECTED Write protected.
+ @retval EFI_NOT_FOUND Not found.
+ @retval EFI_INVALID_PARAMETER Invalid parameter.
+ @retval EFI_UNSUPPORTED This function not supported.
+
+**/
+EFI_STATUS
+EFIAPI
+FvWriteFile (
+ IN CONST EFI_FIRMWARE_VOLUME2_PROTOCOL *This,
+ IN UINT32 NumberOfFiles,
+ IN EFI_FV_WRITE_POLICY WritePolicy,
+ IN EFI_FV_WRITE_FILE_DATA *FileData
+ )
+{
+ EFI_STATUS Status;
+ UINTN Index1;
+ UINTN Index2;
+ UINT8 *FileBuffer;
+ UINTN BufferSize;
+ UINTN ActualSize;
+ UINT8 ErasePolarity;
+ FV_DEVICE *FvDevice;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES FileAttributes;
+ UINTN Size;
+ BOOLEAN CreateNewFile[MAX_FILES];
+ UINTN NumDelete;
+ EFI_FV_ATTRIBUTES FvAttributes;
+ UINT32 AuthenticationStatus;
+ UINTN HeaderSize;
+
+ if (NumberOfFiles > MAX_FILES) {
+ return EFI_UNSUPPORTED;
+ }
+
+ Status = EFI_SUCCESS;
+
+ SetMem (CreateNewFile, NumberOfFiles, TRUE);
+
+ FvDevice = FV_DEVICE_FROM_THIS (This);
+
+ //
+ // First check the volume attributes.
+ //
+ Status = This->GetVolumeAttributes (
+ This,
+ &FvAttributes
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Can we have write right?
+ //
+ if ((FvAttributes & EFI_FV2_WRITE_STATUS) == 0) {
+ return EFI_WRITE_PROTECTED;
+ }
+
+ ErasePolarity = FvDevice->ErasePolarity;
+
+ //
+ // Loop for all files
+ //
+ NumDelete = 0;
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+
+ if ((FileData[Index1].BufferSize + sizeof (EFI_FFS_FILE_HEADER) > 0x00FFFFFF) && !FvDevice->IsFfs3Fv) {
+ //
+ // Found a file needs a FFS3 formatted file to store it, but it is in a non-FFS3 formatted FV.
+ //
+ DEBUG ((EFI_D_ERROR, "FFS3 formatted file can't be written in a non-FFS3 formatted FV.\n"));
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (FileData[Index1].BufferSize == 0) {
+ //
+ // Here we will delete this file
+ //
+ Status = This->ReadFile (
+ This,
+ FileData[Index1].NameGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ NumDelete++;
+ } else {
+ return Status;
+ }
+ }
+
+ if (FileData[Index1].Type == EFI_FV_FILETYPE_FFS_PAD) {
+ //
+ // According to PI spec, on EFI_FV_FILETYPE_FFS_PAD:
+ // "Standard firmware file system services will not return the handle of any pad files,
+ // nor will they permit explicit creation of such files."
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+
+ if ((NumDelete != NumberOfFiles) && (NumDelete != 0)) {
+ //
+ // A delete was request with a multiple file write
+ //
+ return EFI_INVALID_PARAMETER;
+ }
+
+ if (NumDelete == NumberOfFiles) {
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ //
+ // Delete Files
+ //
+ Status = FvDeleteFile (FvDevice, FileData[Index1].NameGuid);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+ }
+
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ Status = This->ReadFile (
+ This,
+ FileData[Index1].NameGuid,
+ NULL,
+ &Size,
+ &FileType,
+ &FileAttributes,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ CreateNewFile[Index1] = FALSE;
+ } else if (Status == EFI_NOT_FOUND) {
+ CreateNewFile[Index1] = TRUE;
+ } else {
+ return Status;
+ }
+ //
+ // Checking alignment
+ //
+ if ((FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT) != 0) {
+ UINT8 FFSAlignmentValue;
+ UINT8 FvAlignmentValue;
+
+ FFSAlignmentValue = (UINT8) (FileData[Index1].FileAttributes & EFI_FV_FILE_ATTRIB_ALIGNMENT);
+ FvAlignmentValue = (UINT8) (((UINT32) (FvAttributes & EFI_FV2_ALIGNMENT)) >> 16);
+
+ if (FFSAlignmentValue > FvAlignmentValue) {
+ return EFI_INVALID_PARAMETER;
+ }
+ }
+ }
+
+ if ((WritePolicy != EFI_FV_RELIABLE_WRITE) && (WritePolicy != EFI_FV_UNRELIABLE_WRITE)) {
+ return EFI_INVALID_PARAMETER;
+ }
+ //
+ // Checking the reliable write is supported by FV
+ //
+
+ if ((WritePolicy == EFI_FV_RELIABLE_WRITE) && (NumberOfFiles > 1)) {
+ //
+ // Only for multiple files, reliable write is meaningful
+ //
+ Status = FvCreateMultipleFiles (
+ FvDevice,
+ NumberOfFiles,
+ FileData,
+ CreateNewFile
+ );
+
+ return Status;
+ }
+
+ for (Index1 = 0; Index1 < NumberOfFiles; Index1++) {
+ //
+ // Making Buffersize QWORD boundry, and add file tail.
+ //
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER);
+ ActualSize = FileData[Index1].BufferSize + HeaderSize;
+ if (ActualSize > 0x00FFFFFF) {
+ HeaderSize = sizeof (EFI_FFS_FILE_HEADER2);
+ ActualSize = FileData[Index1].BufferSize + HeaderSize;
+ }
+ BufferSize = ActualSize;
+
+ while ((BufferSize & 0x07) != 0) {
+ BufferSize++;
+ }
+
+ FileBuffer = AllocateZeroPool (BufferSize);
+ if (FileBuffer == NULL) {
+ return Status;
+ }
+ //
+ // Copy File Data into FileBuffer
+ //
+ CopyMem (
+ FileBuffer + HeaderSize,
+ FileData[Index1].Buffer,
+ FileData[Index1].BufferSize
+ );
+
+ if (ErasePolarity == 1) {
+ //
+ // Fill the file header and padding byte with Erase Byte
+ //
+ for (Index2 = 0; Index2 < HeaderSize; Index2++) {
+ FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
+ }
+
+ for (Index2 = ActualSize; Index2 < BufferSize; Index2++) {
+ FileBuffer[Index2] = (UINT8)~FileBuffer[Index2];
+ }
+ }
+
+ if (CreateNewFile[Index1]) {
+ Status = FvCreateNewFile (
+ FvDevice,
+ FileBuffer,
+ BufferSize,
+ ActualSize,
+ FileData[Index1].NameGuid,
+ FileData[Index1].Type,
+ FileData[Index1].FileAttributes
+ );
+ } else {
+ Status = FvUpdateFile (
+ FvDevice,
+ FileBuffer,
+ BufferSize,
+ ActualSize,
+ FileData[Index1].NameGuid,
+ FileData[Index1].Type,
+ FileData[Index1].FileAttributes
+ );
+ }
+
+ FreePool (FileBuffer);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
new file mode 100644
index 0000000000..56514c9855
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/FlashUpdate.c
@@ -0,0 +1,1218 @@
+/** @file
+ Functions in this file will program the image into flash area.
+
+ Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UpdateDriver.h"
+
+/**
+ Write a block size data into flash.
+
+ @param FvbProtocol Pointer to FVB protocol.
+ @param Lba Logic block index to be updated.
+ @param BlockSize Block size
+ @param Buffer Buffer data to be written.
+
+ @retval EFI_SUCCESS Write data successfully.
+ @retval other errors Write data failed.
+
+**/
+EFI_STATUS
+UpdateOneBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_LBA Lba,
+ IN UINTN BlockSize,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+
+ //
+ // First erase the block
+ //
+ Status = FvbProtocol->EraseBlocks (
+ FvbProtocol,
+ Lba, // Lba
+ 1, // NumOfBlocks
+ EFI_LBA_LIST_TERMINATOR
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Write the block
+ //
+ Size = BlockSize;
+ Status = FvbProtocol->Write (
+ FvbProtocol,
+ Lba, // Lba
+ 0, // Offset
+ &Size, // Size
+ Buffer // Buffer
+ );
+ if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
+ return Status;
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Write buffer data in a flash block.
+
+ @param FvbProtocol Pointer to FVB protocol.
+ @param Lba Logic block index to be updated.
+ @param Offset The offset within the block.
+ @param Length Size of buffer to be updated.
+ @param BlockSize Block size.
+ @param Buffer Buffer data to be updated.
+
+ @retval EFI_SUCCESS Write data successfully.
+ @retval other errors Write data failed.
+
+**/
+EFI_STATUS
+UpdateBufferInOneBlock (
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_LBA Lba,
+ IN UINTN Offset,
+ IN UINTN Length,
+ IN UINTN BlockSize,
+ IN UINT8 *Buffer
+ )
+{
+ EFI_STATUS Status;
+ UINTN Size;
+ UINT8 *ReservedBuffer;
+
+ //
+ // If we are going to update a whole block
+ //
+ if ((Offset == 0) && (Length == BlockSize)) {
+ Status = UpdateOneBlock (
+ FvbProtocol,
+ Lba,
+ BlockSize,
+ Buffer
+ );
+ return Status;
+ }
+
+ //
+ // If it is not a full block update, we need to coalesce data in
+ // the block that is not going to be updated and new data together.
+ //
+
+ //
+ // Allocate a reserved buffer to make up the final buffer for update
+ //
+ ReservedBuffer = NULL;
+ ReservedBuffer = AllocatePool (BlockSize);
+ if (ReservedBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // First get the original content of the block
+ //
+ Size = BlockSize;
+ Status = FvbProtocol->Read (
+ FvbProtocol,
+ Lba,
+ 0,
+ &Size,
+ ReservedBuffer
+ );
+ if ((EFI_ERROR (Status)) || (Size != BlockSize)) {
+ FreePool (ReservedBuffer);
+ return Status;
+ }
+
+ //
+ // Overwrite the reserved buffer with new content
+ //
+ CopyMem (ReservedBuffer + Offset, Buffer, Length);
+
+ Status = UpdateOneBlock (
+ FvbProtocol,
+ Lba,
+ BlockSize,
+ ReservedBuffer
+ );
+
+ FreePool (ReservedBuffer);
+
+ return Status;
+}
+
+/**
+ Get the last write log, and check the status of last write.
+ If not complete, restart will be taken.
+
+ @param FvbHandle Handle of FVB protocol.
+ @param FtwProtocol FTW protocol instance.
+ @param ConfigData Config data on updating driver.
+ @param PrivateDataSize bytes from the private data
+ stored for this write.
+ @param PrivateData A pointer to a buffer. The function will copy.
+ @param Lba The logical block address of the last write.
+ @param Offset The offset within the block of the last write.
+ @param Length The length of the last write.
+ @param Pending A Boolean value with TRUE indicating
+ that the write was completed.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_ABORTED The FTW work space is damaged.
+ @retval EFI_NOT_FOUND The last write is not done by this driver.
+ @retval EFI_SUCCESS Last write log is got.
+
+**/
+EFI_STATUS
+RetrieveLastWrite (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINTN PrivateDataSize,
+ IN OUT UPDATE_PRIVATE_DATA *PrivateData,
+ IN OUT EFI_LBA *Lba,
+ IN OUT UINTN *Offset,
+ IN OUT UINTN *Length,
+ IN OUT BOOLEAN *Pending
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID CallerId;
+ UINTN PrivateBufferSize;
+ BOOLEAN Complete;
+ VOID *PrivateDataBuffer;
+
+ //
+ // Get the last write
+ //
+ *Pending = FALSE;
+ PrivateBufferSize = PrivateDataSize;
+ PrivateDataBuffer = NULL;
+ Status = FtwProtocol->GetLastWrite (
+ FtwProtocol,
+ &CallerId,
+ Lba,
+ Offset,
+ Length,
+ &PrivateBufferSize,
+ PrivateData,
+ &Complete
+ );
+ if (EFI_ERROR (Status)) {
+ //
+ // If there is no incompleted record, return success.
+ //
+ if ((Status == EFI_NOT_FOUND) && Complete) {
+ return EFI_SUCCESS;
+ } else if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // If buffer too small, reallocate buffer and call getlastwrite again
+ //
+ PrivateDataBuffer = AllocatePool (PrivateBufferSize);
+
+ if (PrivateDataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = FtwProtocol->GetLastWrite (
+ FtwProtocol,
+ &CallerId,
+ Lba,
+ Offset,
+ Length,
+ &PrivateBufferSize,
+ PrivateDataBuffer,
+ &Complete
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool ( PrivateDataBuffer);
+ return EFI_ABORTED;
+ } else {
+ CopyMem (PrivateData, PrivateDataBuffer, PrivateDataSize);
+ FreePool (PrivateDataBuffer);
+ PrivateDataBuffer = NULL;
+ }
+ } else {
+ return EFI_ABORTED;
+ }
+ }
+
+ *Pending = TRUE;
+
+ //
+ // If the caller is not the update driver, then return.
+ // The update driver cannot continue to perform the update
+ //
+ if (CompareMem (&CallerId, &gEfiCallerIdGuid, sizeof (EFI_GUID)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check the private data and see if it is the one I need.
+ //
+ if (CompareMem (&(PrivateData->FileGuid), &(ConfigData->FileGuid), sizeof(EFI_GUID)) != 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // If the caller is the update driver and complete is not true, then restart().
+ //
+ if (!Complete) {
+ //
+ // Re-start the update
+ //
+ Status = FtwProtocol->Restart (
+ FtwProtocol,
+ FvbHandle
+ );
+ //
+ // If restart() error, then abort().
+ //
+ if (EFI_ERROR (Status)) {
+ FtwProtocol->Abort (FtwProtocol);
+ //
+ // Now set Pending as FALSE as this record has been cleared
+ //
+ *Pending = FALSE;
+ return EFI_SUCCESS;
+ }
+
+ }
+
+ return Status;
+}
+
+/**
+ Update the whole FV image in fault tolerant write method.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param BlockMap Block array to specify flash area.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+
+ @retval EFI_SUCCESS FV image is writed into flash.
+ @retval EFI_INVALID_PARAMETER Config data is not valid.
+ @retval EFI_NOT_FOUND FTW protocol doesn't exist.
+ @retval EFI_OUT_OF_RESOURCES No enough backup space.
+ @retval EFI_ABORTED Error happen when update FV.
+
+**/
+EFI_STATUS
+FaultTolerantUpdateOnWholeFv (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ UINTN MaxBlockSize;
+ UINTN FtwMaxBlockSize;
+ BOOLEAN Pending;
+ UPDATE_PRIVATE_DATA PrivateData;
+ EFI_LBA PendingLba;
+ EFI_LBA Lba;
+ UINTN PendingOffset;
+ UINTN Offset;
+ UINTN PendingLength;
+ UINTN Length;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrMap;
+ UINTN NumOfBlocks;
+ UINTN Index;
+ UINT8 *UpdateBuffer;
+
+ if ((ConfigData->UpdateType != UpdateWholeFV)
+ || (!ConfigData->FaultTolerant)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the FTW protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ NULL,
+ (VOID **) &FtwProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Get the maximum block size of the FV, and number of blocks
+ // NumOfBlocks will be the NumOfUdpates.
+ //
+ MaxBlockSize = 0;
+ NumOfBlocks = 0;
+ PtrMap = BlockMap;
+ while (TRUE) {
+ if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
+ break;
+ }
+ if (MaxBlockSize < PtrMap->Length) {
+ MaxBlockSize = PtrMap->Length;
+ }
+ NumOfBlocks = NumOfBlocks + PtrMap->NumBlocks;
+ PtrMap++;
+ }
+
+ FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+ //
+ // Not enough backup space. return directly
+ //
+ if (FtwMaxBlockSize < MaxBlockSize) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PendingLba = 0;
+ PendingOffset = 0;
+ PendingLength = 0;
+ Pending = FALSE;
+
+ //
+ // Fault Tolerant Write can only support actual fault tolerance if the write
+ // is a reclaim operation, which means the data buffer (new and old) are
+ // acutally both stored in flash. But for component update write, the data
+ // are now in memory. So we cannot actually recover the data after power
+ // failure.
+ //
+ Status = RetrieveLastWrite (
+ FvbHandle,
+ FtwProtocol,
+ ConfigData,
+ sizeof (UPDATE_PRIVATE_DATA),
+ &PrivateData,
+ &PendingLba,
+ &PendingOffset,
+ &PendingLength,
+ &Pending
+ );
+
+ if (Pending && (Status == EFI_NOT_FOUND)) {
+ //
+ // Cannot continue with the write operation
+ //
+ return EFI_ABORTED;
+ }
+
+ if (EFI_ERROR(Status)) {
+ return EFI_ABORTED;
+ }
+
+ //
+ // Currently we start from the pending write if there is any. But as we
+ // are going to update a whole FV, we can just abort last write and start
+ // from the very begining.
+ //
+ if (!Pending) {
+ //
+ // Now allocte the update private data in FTW. If there is pending
+ // write, it has already been allocated and no need to allocate here.
+ //
+ Status = FtwProtocol->Allocate (
+ FtwProtocol,
+ &gEfiCallerIdGuid,
+ sizeof (UPDATE_PRIVATE_DATA),
+ NumOfBlocks
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // Perform the update now. If there are pending writes, we need to
+ // start from the pending write instead of the very beginning.
+ //
+ PtrMap = BlockMap;
+ Lba = 0;
+ Offset = 0;
+ UpdateBuffer = ImageBuffer;
+ CopyMem (
+ (VOID *) &PrivateData.FileGuid,
+ (VOID *) &ConfigData->FileGuid,
+ sizeof (EFI_GUID)
+ );
+
+ while (TRUE) {
+ if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
+ break;
+ }
+ Length = (UINTN)PtrMap->Length;
+ for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
+
+ //
+ // Add an extra check here to see if the pending record is correct
+ //
+ if (Pending && (Lba == PendingLba)) {
+ if ((PendingOffset != Offset) || (PendingLength != Length)) {
+ //
+ // Error.
+ //
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+
+ if ((!Pending) || (Lba >= PendingLba)) {
+ Status = FtwProtocol->Write (
+ FtwProtocol,
+ Lba, // Lba
+ Offset, // Offset
+ Length, // Size
+ &PrivateData, // Private Data
+ FvbHandle, // FVB handle
+ UpdateBuffer // Buffer
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ Lba++;
+ UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + Length);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ PtrMap++;
+ }
+
+ return Status;
+
+}
+
+/**
+ Directly update the whole FV image without fault tolerant write method.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param BlockMap Block array to specify flash area.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+
+ @retval EFI_SUCCESS FV image is writed into flash.
+ @retval EFI_INVALID_PARAMETER Config data is not valid.
+ @retval EFI_ABORTED Error happen when update FV.
+
+**/
+EFI_STATUS
+NonFaultTolerantUpdateOnWholeFv (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_FV_BLOCK_MAP_ENTRY *BlockMap,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ EFI_STATUS Status;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrMap;
+ UINTN Index;
+ EFI_LBA UpdateLba;
+ UINT8 *UpdateBuffer;
+ UINTN UpdateSize;
+
+ if ((ConfigData->UpdateType != UpdateWholeFV )
+ || (ConfigData->FaultTolerant)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ Status = EFI_SUCCESS;
+ PtrMap = BlockMap;
+ UpdateLba = 0;
+ UpdateBuffer = ImageBuffer;
+
+ //
+ // Perform the update now
+ //
+ while (TRUE) {
+ if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
+ break;
+ }
+ UpdateSize = (UINTN)PtrMap->Length;
+ for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
+ Status = UpdateOneBlock (
+ FvbProtocol,
+ UpdateLba,
+ UpdateSize,
+ UpdateBuffer
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ UpdateLba++;
+ UpdateBuffer = (UINT8 *) ((UINTN)UpdateBuffer + UpdateSize);
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ PtrMap++;
+ }
+
+ return Status;
+}
+
+/**
+ Update the whole FV image, and reinsall FVB protocol for the updated FV image.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+
+ @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV.
+ Or Image size is not same to the size of whole FV.
+ @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated.
+ @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled.
+
+**/
+EFI_STATUS
+PerformUpdateOnWholeFv (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize
+)
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ CHAR16 *TmpStr;
+
+ if (ConfigData->UpdateType != UpdateWholeFV) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Get the header of the firmware volume
+ //
+ FwVolHeader = NULL;
+ FwVolHeader = AllocatePool (((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength);
+ if (FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (
+ FwVolHeader,
+ (VOID *) ((UINTN) (ConfigData->BaseAddress)),
+ ((EFI_FIRMWARE_VOLUME_HEADER *) ((UINTN) (ConfigData->BaseAddress)))->HeaderLength
+ );
+
+ //
+ // Check if ImageSize is the same as the size of the whole FV
+ //
+ if ((UINT64)ImageSize != FwVolHeader->FvLength) {
+ FreePool (FwVolHeader);
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print on screen
+ //
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME), NULL);
+ if (TmpStr != NULL) {
+ Print (TmpStr, ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress));
+ FreePool (TmpStr);
+ }
+
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating whole FV from %08LX to %08LX\n",
+ ConfigData->BaseAddress, (FwVolHeader->FvLength + ConfigData->BaseAddress)));
+
+ //
+ // Get the block map of the firmware volume
+ //
+ BlockMap = &(FwVolHeader->BlockMap[0]);
+
+ //
+ // It is about the same if we are going to fault tolerantly update
+ // a certain FV in our current design. But we divide non-fault tolerant
+ // and fault tolerant udpate here for better maintenance as fault
+ // tolerance may change and may be done more wisely if we have space.
+ //
+ if (ConfigData->FaultTolerant) {
+ Status = FaultTolerantUpdateOnWholeFv (
+ FvbHandle,
+ FvbProtocol,
+ BlockMap,
+ ConfigData,
+ ImageBuffer,
+ ImageSize
+ );
+ } else {
+ Status = NonFaultTolerantUpdateOnWholeFv (
+ FvbHandle,
+ FvbProtocol,
+ BlockMap,
+ ConfigData,
+ ImageBuffer,
+ ImageSize
+ );
+ }
+
+ FreePool (FwVolHeader);
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // As the whole FV has been replaced, the FV driver shall re-parse the
+ // firmware volume. So re-install FVB protocol here
+ //
+ Status = gBS->ReinstallProtocolInterface (
+ FvbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ FvbProtocol,
+ FvbProtocol
+ );
+
+ return Status;
+}
+
+/**
+ Update certain file in the FV.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+ @param FileType FFS file type.
+ @param FileAttributes FFS file attribute
+
+ @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile.
+ Or Image size is not same to the size of whole FV.
+ @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated.
+ @retval EFI_SUCCESS The FFS file is added into FV.
+
+**/
+EFI_STATUS
+PerformUpdateOnFvFile (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol;
+ EFI_FV_WRITE_FILE_DATA FileData;
+ CHAR16 *TmpStr;
+
+ if (ConfigData->UpdateType != UpdateFvFile) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ //
+ // Print on screen
+ //
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FIRMWARE_VOLUME_FILE), NULL);
+ if (TmpStr != NULL) {
+ Print (TmpStr, &(ConfigData->FileGuid));
+ FreePool (TmpStr);
+ }
+
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: updating file: %g\n",
+ &(ConfigData->FileGuid)));
+
+ //
+ // Get Firmware volume protocol on this FVB protocol
+ //
+ Status = gBS->HandleProtocol (
+ FvbHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &FwVolProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // If it is a PEIM, we need first to rebase it before committing
+ // the write to target
+ //
+ if ((FileType == EFI_FV_FILETYPE_PEI_CORE) || (FileType == EFI_FV_FILETYPE_PEIM )
+ || (FileType == EFI_FV_FILETYPE_COMBINED_PEIM_DRIVER)) {
+ return EFI_UNSUPPORTED;
+ }
+
+ FileData.NameGuid = &(ConfigData->FileGuid);
+ FileData.Type = FileType;
+ FileData.FileAttributes = FileAttributes;
+ FileData.Buffer = ImageBuffer;
+ FileData.BufferSize = (UINT32) ImageSize;
+
+ Status = FwVolProtocol->WriteFile (
+ FwVolProtocol,
+ 1, // NumberOfFiles
+ (EFI_FV_WRITE_POLICY)ConfigData->FaultTolerant,
+ &FileData
+ );
+ return Status;
+}
+
+/**
+ Update the buffer into flash area in fault tolerant write method.
+
+ @param ImageBuffer Image buffer to be updated.
+ @param SizeLeft Size of the image buffer.
+ @param UpdatedSize Size of the updated buffer.
+ @param ConfigData Config data on updating driver.
+ @param FlashAddress Flash address to be updated as start address.
+ @param FvbProtocol FVB protocol.
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+
+ @retval EFI_SUCCESS Buffer data is updated into flash.
+ @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.
+ @retval EFI_NOT_FOUND FTW protocol doesn't exist.
+ @retval EFI_OUT_OF_RESOURCES No enough backup space.
+ @retval EFI_ABORTED Error happen when update flash area.
+
+**/
+EFI_STATUS
+FaultTolerantUpdateOnPartFv (
+ IN UINT8 *ImageBuffer,
+ IN UINTN SizeLeft,
+ IN OUT UINTN *UpdatedSize,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN EFI_PHYSICAL_ADDRESS FlashAddress,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_HANDLE FvbHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS FvBase;
+ EFI_PHYSICAL_ADDRESS NextBlock;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ EFI_FV_BLOCK_MAP_ENTRY *PtrMap;
+ UINTN NumOfUpdates;
+ UINTN TotalSize;
+ EFI_PHYSICAL_ADDRESS StartAddress;
+ EFI_FAULT_TOLERANT_WRITE_PROTOCOL *FtwProtocol;
+ UINTN MaxBlockSize;
+ UINTN FtwMaxBlockSize;
+ BOOLEAN Pending;
+ UPDATE_PRIVATE_DATA PrivateData;
+ EFI_LBA PendingLba;
+ EFI_LBA Lba;
+ UINTN BlockSize;
+ UINTN PendingOffset;
+ UINTN Offset;
+ UINTN PendingLength;
+ UINTN Length;
+ UINTN Index;
+ UINT8 *Image;
+
+ //
+ // Get the block map to update the block one by one
+ //
+ Status = FvbProtocol->GetPhysicalAddress (
+ FvbProtocol,
+ &FvBase
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)FvBase;
+ if ((FlashAddress < FvBase) || (FlashAddress > (FvBase + FwVolHeaderTmp->FvLength))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
+ FwVolHeaderTmp->HeaderLength,
+ FwVolHeaderTmp
+ );
+ if (FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // For fault tolerant write, we have to know how many blocks we need to
+ // update. So we will calculate number of updates and max block size first
+ //
+ NumOfUpdates = 0;
+ MaxBlockSize = 0;
+ TotalSize = SizeLeft;
+ StartAddress = FlashAddress;
+ BaseAddress = FvBase;
+ BlockMap = &(FwVolHeader->BlockMap[0]);
+ PtrMap = BlockMap;
+
+ while (TotalSize > 0) {
+ if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
+ break;
+ }
+
+ BlockSize = PtrMap->Length;
+ for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
+ NextBlock = BaseAddress + BlockSize;
+ //
+ // Check if this block need to be updated
+ //
+ if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
+ //
+ // Get the maximum block size
+ //
+ if (MaxBlockSize < BlockSize) {
+ MaxBlockSize = BlockSize;
+ }
+
+ //
+ // This block shall be udpated. So increment number of updates
+ //
+ NumOfUpdates++;
+ Offset = (UINTN) (StartAddress - BaseAddress);
+ Length = TotalSize;
+ if ((Length + Offset ) > BlockSize) {
+ Length = BlockSize - Offset;
+ }
+
+ StartAddress = StartAddress + Length;
+ TotalSize = TotalSize - Length;
+ if (TotalSize <= 0) {
+ break;
+ }
+ }
+ BaseAddress = NextBlock;
+ }
+ PtrMap++;
+ }
+
+ //
+ // Get the FTW protocol
+ //
+ Status = gBS->LocateProtocol (
+ &gEfiFaultTolerantWriteProtocolGuid,
+ NULL,
+ (VOID **) &FtwProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ return EFI_NOT_FOUND;
+ }
+
+ FtwProtocol->GetMaxBlockSize (FtwProtocol, &FtwMaxBlockSize);
+
+ //
+ // Not enough backup space. return directly
+ //
+ if (FtwMaxBlockSize < MaxBlockSize) {
+ FreePool (FwVolHeader);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ PendingLba = 0;
+ PendingOffset = 0;
+ PendingLength = 0;
+ Pending = FALSE;
+
+ //
+ // Fault Tolerant Write can only support actual fault tolerance if the write
+ // is a reclaim operation, which means the data buffer (new and old) are
+ // acutally both stored in flash. But for component update write, the data
+ // are now in memory. So we cannot actually recover the data after power
+ // failure.
+ //
+ Status = RetrieveLastWrite (
+ FvbHandle,
+ FtwProtocol,
+ ConfigData,
+ sizeof (UPDATE_PRIVATE_DATA),
+ &PrivateData,
+ &PendingLba,
+ &PendingOffset,
+ &PendingLength,
+ &Pending
+ );
+ if (Pending && (Status == EFI_NOT_FOUND)) {
+ //
+ // I'm not the owner of the pending fault tolerant write record
+ // Cannot continue with the write operation
+ //
+ FreePool (FwVolHeader);
+ return EFI_ABORTED;
+ }
+
+ if (EFI_ERROR(Status)) {
+ FreePool (FwVolHeader);
+ return EFI_ABORTED;
+ }
+
+ //
+ // Currently we start from the pending write if there is any. But if the
+ // caller is exactly the same, and the new data is already a in memory, (it
+ // cannot be stored in flash in last write,) we can just abort last write
+ // and start from the very begining.
+ //
+ if (!Pending) {
+ //
+ // Now allocte the update private data in FTW. If there is pending
+ // write, it has already been allocated and no need to allocate here.
+ //
+ Status = FtwProtocol->Allocate (
+ FtwProtocol,
+ &gEfiCallerIdGuid,
+ sizeof (UPDATE_PRIVATE_DATA),
+ NumOfUpdates
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ return Status;
+ }
+ }
+
+ //
+ // Perform the update now. If there are pending writes, we need to
+ // start from the pending write instead of the very beginning.
+ //
+ TotalSize = SizeLeft;
+ Lba = 0;
+ StartAddress = FlashAddress;
+ BaseAddress = FvBase;
+ PtrMap = BlockMap;
+ Image = ImageBuffer;
+ CopyMem (
+ (VOID *) &PrivateData.FileGuid,
+ (VOID *) &ConfigData->FileGuid,
+ sizeof (EFI_GUID)
+ );
+
+ while (TotalSize > 0) {
+ if ((PtrMap->NumBlocks == 0) || (PtrMap->Length == 0)) {
+ break;
+ }
+
+ BlockSize = (UINTN)PtrMap->Length;
+ for (Index = 0; Index < PtrMap->NumBlocks; Index++) {
+ NextBlock = BaseAddress + BlockSize;
+ if ((StartAddress >= BaseAddress) && (StartAddress < NextBlock)) {
+ //
+ // So we need to update this block
+ //
+ Offset = (UINTN) (StartAddress - BaseAddress);
+ Length = TotalSize;
+ if ((Length + Offset ) > BlockSize) {
+ Length = BlockSize - Offset;
+ }
+
+ //
+ // Add an extra check here to see if the pending record is correct
+ //
+ if (Pending && (Lba == PendingLba)) {
+ if ((PendingOffset != Offset) || (PendingLength != Length)) {
+ //
+ // Error.
+ //
+ Status = EFI_ABORTED;
+ break;
+ }
+ }
+
+ if ((!Pending) || (Lba >= PendingLba)) {
+ DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", StartAddress, (UINT64)StartAddress + Length));
+ Status = FtwProtocol->Write (
+ FtwProtocol,
+ Lba, // Lba
+ Offset, // Offset
+ Length, // Size
+ &PrivateData, // Private Data
+ FvbHandle, // FVB handle
+ Image // Buffer
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Now increment StartAddress, ImageBuffer and decrease the
+ // left size to prepare for the next block update.
+ //
+ StartAddress = StartAddress + Length;
+ Image = Image + Length;
+ TotalSize = TotalSize - Length;
+ if (TotalSize <= 0) {
+ break;
+ }
+ }
+ BaseAddress = NextBlock;
+ Lba++;
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ PtrMap++;
+ }
+
+ FreePool (FwVolHeader);
+
+ *UpdatedSize = SizeLeft - TotalSize;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Directly update the buffer into flash area without fault tolerant write method.
+
+ @param ImageBuffer Image buffer to be updated.
+ @param SizeLeft Size of the image buffer.
+ @param UpdatedSize Size of the updated buffer.
+ @param FlashAddress Flash address to be updated as start address.
+ @param FvbProtocol FVB protocol.
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+
+ @retval EFI_SUCCESS Buffer data is updated into flash.
+ @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.
+ @retval EFI_OUT_OF_RESOURCES No enough backup space.
+
+**/
+EFI_STATUS
+NonFaultTolerantUpdateOnPartFv (
+ IN UINT8 *ImageBuffer,
+ IN UINTN SizeLeft,
+ IN OUT UINTN *UpdatedSize,
+ IN EFI_PHYSICAL_ADDRESS FlashAddress,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_HANDLE FvbHandle
+ )
+{
+ EFI_STATUS Status;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeaderTmp;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_PHYSICAL_ADDRESS NextBlock;
+ EFI_FV_BLOCK_MAP_ENTRY *BlockMap;
+ UINTN Index;
+ UINTN TotalSize;
+ UINTN BlockSize;
+ EFI_LBA Lba;
+ UINTN Offset;
+ UINTN Length;
+ UINT8 *Image;
+
+ //
+ // Get the block map to update the block one by one
+ //
+ Status = FvbProtocol->GetPhysicalAddress (
+ FvbProtocol,
+ &BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ FwVolHeaderTmp = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
+ if ((FlashAddress < BaseAddress) || (FlashAddress > ( BaseAddress + FwVolHeaderTmp->FvLength ))) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)AllocateCopyPool (
+ FwVolHeaderTmp->HeaderLength,
+ FwVolHeaderTmp
+ );
+ if (FwVolHeader == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Image = ImageBuffer;
+ TotalSize = SizeLeft;
+ BlockMap = &(FwVolHeader->BlockMap[0]);
+ Lba = 0;
+
+ while (TotalSize > 0) {
+ if ((BlockMap->NumBlocks == 0) || (BlockMap->Length == 0)) {
+ break;
+ }
+
+ BlockSize = BlockMap->Length;
+ for (Index = 0 ; Index < BlockMap->NumBlocks ; Index++) {
+ NextBlock = BaseAddress + BlockSize;
+ if ((FlashAddress >= BaseAddress) && (FlashAddress < NextBlock)) {
+ //
+ // So we need to update this block
+ //
+ Offset = (UINTN) FlashAddress - (UINTN) BaseAddress;
+ Length = TotalSize;
+ if ((Length + Offset ) > BlockSize) {
+ Length = BlockSize - Offset;
+ }
+
+ DEBUG ((EFI_D_UPDATE, "Update Flash area from %08LX to %08LX\n", FlashAddress, (UINT64)FlashAddress + Length));
+ //
+ // Update the block
+ //
+ Status = UpdateBufferInOneBlock (
+ FvbProtocol,
+ Lba,
+ Offset,
+ Length,
+ BlockSize,
+ Image
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FwVolHeader);
+ return Status;
+ }
+
+ //
+ // Now increment FlashAddress, ImageBuffer and decrease the
+ // left size to prepare for the next block update.
+ //
+ FlashAddress = FlashAddress + Length;
+ Image = Image + Length;
+ TotalSize = TotalSize - Length;
+ if (TotalSize <= 0) {
+ break;
+ }
+ }
+ BaseAddress = NextBlock;
+ Lba++;
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ BlockMap++;
+ }
+
+ FreePool (FwVolHeader);
+
+ *UpdatedSize = SizeLeft - TotalSize;
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c
new file mode 100644
index 0000000000..023506e6ee
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/ParseUpdateProfile.c
@@ -0,0 +1,1133 @@
+/** @file
+ Source file for the component update driver. It parse the update
+ configuration file and pass the information to the update driver
+ so that the driver can perform updates accordingly.
+
+ Copyright (c) 2002 - 2015, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UpdateDriver.h"
+
+/**
+ Copy one line data from buffer data to the line buffer.
+
+ @param Buffer Buffer data.
+ @param BufferSize Buffer Size.
+ @param LineBuffer Line buffer to store the found line data.
+ @param LineSize On input, size of the input line buffer.
+ On output, size of the actual line buffer.
+
+ @retval EFI_BUFFER_TOO_SMALL The size of input line buffer is not enough.
+ @retval EFI_SUCCESS Copy line data into the line buffer.
+
+**/
+EFI_STATUS
+ProfileGetLine (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT UINT8 *LineBuffer,
+ IN OUT UINTN *LineSize
+ )
+{
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINTN PtrEnd;
+
+ PtrBuf = Buffer;
+ PtrEnd = (UINTN)Buffer + BufferSize;
+
+ //
+ // 0x0D indicates a line break. Otherwise there is no line break
+ //
+ while ((UINTN)PtrBuf < PtrEnd) {
+ if (*PtrBuf == 0x0D) {
+ break;
+ }
+ PtrBuf++;
+ }
+
+ if ((UINTN)PtrBuf >= (PtrEnd - 1)) {
+ //
+ // The buffer ends without any line break
+ // or it is the last character of the buffer
+ //
+ Length = BufferSize;
+ } else if (*(PtrBuf + 1) == 0x0A) {
+ //
+ // Further check if a 0x0A follows. If yes, count 0xA
+ //
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 2;
+ } else {
+ Length = (UINTN) PtrBuf - (UINTN) Buffer + 1;
+ }
+
+ if (Length > (*LineSize)) {
+ *LineSize = Length;
+ return EFI_BUFFER_TOO_SMALL;
+ }
+
+ SetMem (LineBuffer, *LineSize, 0x0);
+ *LineSize = Length;
+ CopyMem (LineBuffer, Buffer, Length);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Trim Buffer by removing all CR, LF, TAB, and SPACE chars in its head and tail.
+
+ @param Buffer On input, buffer data to be trimed.
+ On output, the trimmed buffer.
+ @param BufferSize On input, size of original buffer data.
+ On output, size of the trimmed buffer.
+
+**/
+VOID
+ProfileTrim (
+ IN OUT UINT8 *Buffer,
+ IN OUT UINTN *BufferSize
+ )
+{
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINT8 *PtrEnd;
+
+ if (*BufferSize == 0) {
+ return;
+ }
+
+ //
+ // Trim the tail first, include CR, LF, TAB, and SPACE.
+ //
+ Length = *BufferSize;
+ PtrBuf = (UINT8 *) ((UINTN) Buffer + Length - 1);
+ while (PtrBuf >= Buffer) {
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
+ break;
+ }
+ PtrBuf --;
+ }
+
+ //
+ // all spaces, a blank line, return directly;
+ //
+ if (PtrBuf < Buffer) {
+ *BufferSize = 0;
+ return;
+ }
+
+ Length = (UINTN)PtrBuf - (UINTN)Buffer + 1;
+ PtrEnd = PtrBuf;
+ PtrBuf = Buffer;
+
+ //
+ // Now skip the heading CR, LF, TAB and SPACE
+ //
+ while (PtrBuf <= PtrEnd) {
+ if ((*PtrBuf != 0x0D) && (*PtrBuf != 0x0A )
+ && (*PtrBuf != 0x20) && (*PtrBuf != 0x09)) {
+ break;
+ }
+ PtrBuf++;
+ }
+
+ //
+ // If no heading CR, LF, TAB or SPACE, directly return
+ //
+ if (PtrBuf == Buffer) {
+ *BufferSize = Length;
+ return;
+ }
+
+ *BufferSize = (UINTN)PtrEnd - (UINTN)PtrBuf + 1;
+
+ //
+ // The first Buffer..PtrBuf characters are CR, LF, TAB or SPACE.
+ // Now move out all these characters.
+ //
+ while (PtrBuf <= PtrEnd) {
+ *Buffer = *PtrBuf;
+ Buffer++;
+ PtrBuf++;
+ }
+
+ return;
+}
+
+/**
+ Insert new comment item into comment head.
+
+ @param Buffer Comment buffer to be added.
+ @param BufferSize Size of comment buffer.
+ @param CommentHead Comment Item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS New comment item is inserted.
+
+**/
+EFI_STATUS
+ProfileGetComments (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT COMMENT_LINE **CommentHead
+ )
+{
+ COMMENT_LINE *CommentItem;
+
+ CommentItem = NULL;
+ CommentItem = AllocatePool (sizeof (COMMENT_LINE));
+ if (CommentItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ CommentItem->ptrNext = *CommentHead;
+ *CommentHead = CommentItem;
+
+ //
+ // Add a trailing '\0'
+ //
+ CommentItem->ptrComment = AllocatePool (BufferSize + 1);
+ if (CommentItem->ptrComment == NULL) {
+ FreePool (CommentItem);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (CommentItem->ptrComment, Buffer, BufferSize);
+ *(CommentItem->ptrComment + BufferSize) = '\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add new section item into Section head.
+
+ @param Buffer Section item data buffer.
+ @param BufferSize Size of section item.
+ @param SectionHead Section item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Section item is NULL or Section item is added.
+
+**/
+EFI_STATUS
+ProfileGetSection (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead
+ )
+{
+ EFI_STATUS Status;
+ SECTION_ITEM *SectionItem;
+ UINTN Length;
+ UINT8 *PtrBuf;
+
+ Status = EFI_SUCCESS;
+ //
+ // The first character of Buffer is '[', now we want for ']'
+ //
+ PtrBuf = (UINT8 *)((UINTN)Buffer + BufferSize - 1);
+ while (PtrBuf > Buffer) {
+ if (*PtrBuf == ']') {
+ break;
+ }
+ PtrBuf --;
+ }
+ if (PtrBuf <= Buffer) {
+ //
+ // Not found. Omit this line
+ //
+ return Status;
+ }
+
+ //
+ // excluding the heading '[' and tailing ']'
+ //
+ Length = PtrBuf - Buffer - 1;
+ ProfileTrim (
+ Buffer + 1,
+ &Length
+ );
+
+ //
+ // omit this line if the section name is null
+ //
+ if (Length == 0) {
+ return Status;
+ }
+
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));
+ if (SectionItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SectionItem->ptrSection = NULL;
+ SectionItem->SecNameLen = Length;
+ SectionItem->ptrEntry = NULL;
+ SectionItem->ptrValue = NULL;
+ SectionItem->ptrNext = *SectionHead;
+ *SectionHead = SectionItem;
+
+ //
+ // Add a trailing '\0'
+ //
+ SectionItem->ptrSection = AllocatePool (Length + 1);
+ if (SectionItem->ptrSection == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // excluding the heading '['
+ //
+ CopyMem (SectionItem->ptrSection, Buffer + 1, Length);
+ *(SectionItem->ptrSection + Length) = '\0';
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Add new section entry and entry value into Section head.
+
+ @param Buffer Section entry data buffer.
+ @param BufferSize Size of section entry.
+ @param SectionHead Section item head entry.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Section entry is NULL or Section entry is added.
+
+**/
+EFI_STATUS
+ProfileGetEntry (
+ IN UINT8 *Buffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead
+ )
+{
+ EFI_STATUS Status;
+ SECTION_ITEM *SectionItem;
+ SECTION_ITEM *PtrSection;
+ UINTN Length;
+ UINT8 *PtrBuf;
+ UINT8 *PtrEnd;
+
+ Status = EFI_SUCCESS;
+ PtrBuf = Buffer;
+ PtrEnd = (UINT8 *) ((UINTN)Buffer + BufferSize - 1);
+
+ //
+ // First search for '='
+ //
+ while (PtrBuf <= PtrEnd) {
+ if (*PtrBuf == '=') {
+ break;
+ }
+ PtrBuf++;
+ }
+ if (PtrBuf > PtrEnd) {
+ //
+ // Not found. Omit this line
+ //
+ return Status;
+ }
+
+ //
+ // excluding the tailing '='
+ //
+ Length = PtrBuf - Buffer;
+ ProfileTrim (
+ Buffer,
+ &Length
+ );
+
+ //
+ // Omit this line if the entry name is null
+ //
+ if (Length == 0) {
+ return Status;
+ }
+
+ //
+ // Omit this line if no section header has been found before
+ //
+ if (*SectionHead == NULL) {
+ return Status;
+ }
+ PtrSection = *SectionHead;
+
+ SectionItem = AllocatePool (sizeof (SECTION_ITEM));
+ if (SectionItem == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ SectionItem->ptrSection = NULL;
+ SectionItem->ptrEntry = NULL;
+ SectionItem->ptrValue = NULL;
+ SectionItem->SecNameLen = PtrSection->SecNameLen;
+ SectionItem->ptrNext = *SectionHead;
+ *SectionHead = SectionItem;
+
+ //
+ // SectionName, add a trailing '\0'
+ //
+ SectionItem->ptrSection = AllocatePool (PtrSection->SecNameLen + 1);
+ if (SectionItem->ptrSection == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->ptrSection, PtrSection->ptrSection, PtrSection->SecNameLen + 1);
+
+ //
+ // EntryName, add a trailing '\0'
+ //
+ SectionItem->ptrEntry = AllocatePool (Length + 1);
+ if (SectionItem->ptrEntry == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->ptrEntry, Buffer, Length);
+ *(SectionItem->ptrEntry + Length) = '\0';
+
+ //
+ // Next search for '#'
+ //
+ PtrBuf = PtrBuf + 1;
+ Buffer = PtrBuf;
+ while (PtrBuf <= PtrEnd) {
+ if (*PtrBuf == '#') {
+ break;
+ }
+ PtrBuf++;
+ }
+ Length = PtrBuf - Buffer;
+ ProfileTrim (
+ Buffer,
+ &Length
+ );
+
+ if (Length > 0) {
+ //
+ // EntryValue, add a trailing '\0'
+ //
+ SectionItem->ptrValue = AllocatePool (Length + 1);
+ if (SectionItem->ptrValue == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (SectionItem->ptrValue, Buffer, Length);
+ *(SectionItem->ptrValue + Length) = '\0';
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Free all comment entry and section entry.
+
+ @param Section Section entry list.
+ @param Comment Comment entry list.
+
+**/
+VOID
+FreeAllList (
+ IN SECTION_ITEM *Section,
+ IN COMMENT_LINE *Comment
+ )
+{
+ SECTION_ITEM *PtrSection;
+ COMMENT_LINE *PtrComment;
+
+ while (Section != NULL) {
+ PtrSection = Section;
+ Section = Section->ptrNext;
+ if (PtrSection->ptrEntry != NULL) {
+ FreePool (PtrSection->ptrEntry);
+ }
+ if (PtrSection->ptrSection != NULL) {
+ FreePool (PtrSection->ptrSection);
+ }
+ if (PtrSection->ptrValue != NULL) {
+ FreePool (PtrSection->ptrValue);
+ }
+ FreePool (PtrSection);
+ }
+
+ while (Comment != NULL) {
+ PtrComment = Comment;
+ Comment = Comment->ptrNext;
+ if (PtrComment->ptrComment != NULL) {
+ FreePool (PtrComment->ptrComment);
+ }
+ FreePool (PtrComment);
+ }
+
+ return;
+}
+
+/**
+ Get section entry value.
+
+ @param Section Section entry list.
+ @param SectionName Section name.
+ @param EntryName Section entry name.
+ @param EntryValue Point to the got entry value.
+
+ @retval EFI_NOT_FOUND Section is not found.
+ @retval EFI_SUCCESS Section entry value is got.
+
+**/
+EFI_STATUS
+UpdateGetProfileString (
+ IN SECTION_ITEM *Section,
+ IN UINT8 *SectionName,
+ IN UINT8 *EntryName,
+ OUT UINT8 **EntryValue
+ )
+{
+ *EntryValue = NULL;
+
+ while (Section != NULL) {
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrSection, (CONST CHAR8 *) SectionName) == 0) {
+ if (Section->ptrEntry != NULL) {
+ if (AsciiStrCmp ((CONST CHAR8 *) Section->ptrEntry, (CONST CHAR8 *) EntryName) == 0) {
+ break;
+ }
+ }
+ }
+ Section = Section->ptrNext;
+ }
+
+ if (Section == NULL) {
+ return EFI_NOT_FOUND;
+ }
+
+ *EntryValue = (UINT8 *) Section->ptrValue;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Convert the dec or hex ascii string to value.
+
+ @param Str ascii string to be converted.
+
+ @return the converted value.
+
+**/
+UINTN
+UpdateAtoi (
+ IN UINT8 *Str
+ )
+{
+ UINTN Number;
+
+ Number = 0;
+
+ //
+ // Skip preceeding while spaces
+ //
+ while (*Str != '\0') {
+ if (*Str != 0x20) {
+ break;
+ }
+ Str++;
+ }
+
+ if (*Str == '\0') {
+ return Number;
+ }
+
+ //
+ // Find whether the string is prefixed by 0x.
+ // That is, it should be xtoi or atoi.
+ //
+ if (*Str == '0') {
+ if ((*(Str+1) == 'x' ) || ( *(Str+1) == 'X')) {
+ return AsciiStrHexToUintn ((CONST CHAR8 *) Str);
+ }
+ }
+
+ while (*Str != '\0') {
+ if ((*Str >= '0') && (*Str <= '9')) {
+ Number = Number * 10 + *Str - '0';
+ } else {
+ break;
+ }
+ Str++;
+ }
+
+ return Number;
+}
+
+/**
+ Converts a decimal value to a Null-terminated ascii string.
+
+ @param Buffer Pointer to the output buffer for the produced Null-terminated
+ ASCII string.
+ @param Value The 64-bit sgned value to convert to a string.
+
+ @return The number of ASCII characters in Buffer not including the Null-terminator.
+
+**/
+UINTN
+UpdateValueToString (
+ IN OUT UINT8 *Buffer,
+ IN INT64 Value
+ )
+{
+ UINT8 TempBuffer[30];
+ UINT8 *TempStr;
+ UINT8 *BufferPtr;
+ UINTN Count;
+ UINT32 Remainder;
+
+ TempStr = TempBuffer;
+ BufferPtr = Buffer;
+ Count = 0;
+
+ if (Value < 0) {
+ *BufferPtr = '-';
+ BufferPtr++;
+ Value = -Value;
+ Count++;
+ }
+
+ do {
+ Value = (INT64) DivU64x32Remainder ((UINT64)Value, 10, &Remainder);
+ //
+ // The first item of TempStr is not occupied. It's kind of flag
+ //
+ TempStr++;
+ Count++;
+ *TempStr = (UINT8) ((UINT8)Remainder + '0');
+ } while (Value != 0);
+
+ //
+ // Reverse temp string into Buffer.
+ //
+ while (TempStr != TempBuffer) {
+ *BufferPtr = *TempStr;
+ BufferPtr++;
+ TempStr --;
+ }
+
+ *BufferPtr = 0;
+
+ return Count;
+}
+
+/**
+ Convert the input value to a ascii string,
+ and concatenates this string to the input string.
+
+ @param Str Pointer to a Null-terminated ASCII string.
+ @param Number The unsgned value to convert to a string.
+
+**/
+VOID
+UpdateStrCatNumber (
+ IN OUT UINT8 *Str,
+ IN UINTN Number
+ )
+{
+ UINTN Count;
+
+ while (*Str != '\0') {
+ Str++;
+ }
+
+ Count = UpdateValueToString (Str, (INT64)Number);
+
+ *(Str + Count) = '\0';
+
+ return;
+}
+
+/**
+ Convert the input ascii string into GUID value.
+
+ @param Str Ascii GUID string to be converted.
+ @param Guid Pointer to the converted GUID value.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_NOT_FOUND The input ascii string is not a valid GUID format string.
+ @retval EFI_SUCCESS GUID value is got.
+
+**/
+EFI_STATUS
+UpdateStringToGuid (
+ IN UINT8 *Str,
+ IN OUT EFI_GUID *Guid
+ )
+{
+ UINT8 *PtrBuffer;
+ UINT8 *PtrPosition;
+ UINT8 *Buffer;
+ UINTN Data;
+ UINTN StrLen;
+ UINTN Index;
+ UINT8 Digits[3];
+
+ StrLen = AsciiStrLen ((CONST CHAR8 *) Str);
+ Buffer = AllocateCopyPool (StrLen + 1, Str);
+ if (Buffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Data1
+ //
+ PtrBuffer = Buffer;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != '\0') {
+ if (*PtrBuffer == '-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == '\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+
+ *PtrBuffer = '\0';
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
+ Guid->Data1 = (UINT32)Data;
+
+ //
+ // Data2
+ //
+ PtrBuffer++;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != '\0') {
+ if (*PtrBuffer == '-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == '\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ *PtrBuffer = '\0';
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
+ Guid->Data2 = (UINT16)Data;
+
+ //
+ // Data3
+ //
+ PtrBuffer++;
+ PtrPosition = PtrBuffer;
+ while (*PtrBuffer != '\0') {
+ if (*PtrBuffer == '-') {
+ break;
+ }
+ PtrBuffer++;
+ }
+ if (*PtrBuffer == '\0') {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ *PtrBuffer = '\0';
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) PtrPosition);
+ Guid->Data3 = (UINT16)Data;
+
+ //
+ // Data4[0..1]
+ //
+ for ( Index = 0 ; Index < 2 ; Index++) {
+ PtrBuffer++;
+ if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ Digits[0] = *PtrBuffer;
+ PtrBuffer++;
+ Digits[1] = *PtrBuffer;
+ Digits[2] = '\0';
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
+ Guid->Data4[Index] = (UINT8)Data;
+ }
+
+ //
+ // skip the '-'
+ //
+ PtrBuffer++;
+ if ((*PtrBuffer != '-' ) || ( *PtrBuffer == '\0')) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Data4[2..7]
+ //
+ for ( ; Index < 8; Index++) {
+ PtrBuffer++;
+ if ((*PtrBuffer == '\0') || ( *(PtrBuffer + 1) == '\0')) {
+ FreePool (Buffer);
+ return EFI_NOT_FOUND;
+ }
+ Digits[0] = *PtrBuffer;
+ PtrBuffer++;
+ Digits[1] = *PtrBuffer;
+ Digits[2] = '\0';
+ Data = AsciiStrHexToUintn ((CONST CHAR8 *) Digits);
+ Guid->Data4[Index] = (UINT8)Data;
+ }
+
+ FreePool (Buffer);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Pre process config data buffer into Section entry list and Comment entry list.
+
+ @param DataBuffer Config raw file buffer.
+ @param BufferSize Size of raw buffer.
+ @param SectionHead Pointer to the section entry list.
+ @param CommentHead Pointer to the comment entry list.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Config data buffer is preprocessed.
+
+**/
+EFI_STATUS
+PreProcessDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT SECTION_ITEM **SectionHead,
+ IN OUT COMMENT_LINE **CommentHead
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *Source;
+ CHAR8 *CurrentPtr;
+ CHAR8 *BufferEnd;
+ CHAR8 *PtrLine;
+ UINTN LineLength;
+ UINTN SourceLength;
+ UINTN MaxLineLength;
+
+ *SectionHead = NULL;
+ *CommentHead = NULL;
+ BufferEnd = (CHAR8 *) ( (UINTN) DataBuffer + BufferSize);
+ CurrentPtr = (CHAR8 *) DataBuffer;
+ MaxLineLength = MAX_LINE_LENGTH;
+ Status = EFI_SUCCESS;
+
+ PtrLine = AllocatePool (MaxLineLength);
+ if (PtrLine == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ while (CurrentPtr < BufferEnd) {
+ Source = CurrentPtr;
+ SourceLength = (UINTN)BufferEnd - (UINTN)CurrentPtr;
+ LineLength = MaxLineLength;
+ //
+ // With the assumption that line length is less than 512
+ // characters. Otherwise BUFFER_TOO_SMALL will be returned.
+ //
+ Status = ProfileGetLine (
+ (UINT8 *) Source,
+ SourceLength,
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+ if (EFI_ERROR (Status)) {
+ if (Status == EFI_BUFFER_TOO_SMALL) {
+ //
+ // If buffer too small, re-allocate the buffer according
+ // to the returned LineLength and try again.
+ //
+ FreePool (PtrLine);
+ PtrLine = NULL;
+ PtrLine = AllocatePool (LineLength);
+ if (PtrLine == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ break;
+ }
+ SourceLength = LineLength;
+ Status = ProfileGetLine (
+ (UINT8 *) Source,
+ SourceLength,
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ MaxLineLength = LineLength;
+ } else {
+ break;
+ }
+ }
+ CurrentPtr = (CHAR8 *) ( (UINTN) CurrentPtr + LineLength);
+
+ //
+ // Line got. Trim the line before processing it.
+ //
+ ProfileTrim (
+ (UINT8 *) PtrLine,
+ &LineLength
+ );
+
+ //
+ // Blank line
+ //
+ if (LineLength == 0) {
+ continue;
+ }
+
+ if (PtrLine[0] == '#') {
+ Status = ProfileGetComments (
+ (UINT8 *) PtrLine,
+ LineLength,
+ CommentHead
+ );
+ } else if (PtrLine[0] == '[') {
+ Status = ProfileGetSection (
+ (UINT8 *) PtrLine,
+ LineLength,
+ SectionHead
+ );
+ } else {
+ Status = ProfileGetEntry (
+ (UINT8 *) PtrLine,
+ LineLength,
+ SectionHead
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ }
+
+ //
+ // Free buffer
+ //
+ FreePool (PtrLine);
+
+ return Status;
+}
+
+/**
+ Parse Config data file to get the updated data array.
+
+ @param DataBuffer Config raw file buffer.
+ @param BufferSize Size of raw buffer.
+ @param NumOfUpdates Pointer to the number of update data.
+ @param UpdateArray Pointer to the config of update data.
+
+ @retval EFI_NOT_FOUND No config data is found.
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Parse the config file successfully.
+
+**/
+EFI_STATUS
+ParseUpdateDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT UINTN *NumOfUpdates,
+ IN OUT UPDATE_CONFIG_DATA **UpdateArray
+ )
+{
+ EFI_STATUS Status;
+ CHAR8 *Value;
+ CHAR8 *SectionName;
+ CHAR8 Entry[MAX_LINE_LENGTH];
+ SECTION_ITEM *SectionHead;
+ COMMENT_LINE *CommentHead;
+ UINTN Num;
+ UINTN Index;
+ EFI_GUID FileGuid;
+
+ SectionHead = NULL;
+ CommentHead = NULL;
+
+ //
+ // First process the data buffer and get all sections and entries
+ //
+ Status = PreProcessDataFile (
+ DataBuffer,
+ BufferSize,
+ &SectionHead,
+ &CommentHead
+ );
+ if (EFI_ERROR (Status)) {
+ FreeAllList (SectionHead, CommentHead);
+ return Status;
+ }
+
+ //
+ // Now get NumOfUpdate
+ //
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) "Head",
+ (UINT8 *) "NumOfUpdate",
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+ Num = UpdateAtoi((UINT8 *) Value);
+ if (Num <= 0) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ *NumOfUpdates = Num;
+ *UpdateArray = AllocatePool ((sizeof (UPDATE_CONFIG_DATA) * Num));
+ if (*UpdateArray == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ for ( Index = 0 ; Index < *NumOfUpdates ; Index++) {
+ //
+ // Get the section name of each update
+ //
+ AsciiStrCpyS (Entry, MAX_LINE_LENGTH, "Update");
+ UpdateStrCatNumber ((UINT8 *) Entry, Index);
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) "Head",
+ (UINT8 *) Entry,
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // The section name of this update has been found.
+ // Now looks for all the config data of this update
+ //
+ SectionName = Value;
+
+ //
+ // UpdateType
+ //
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) SectionName,
+ (UINT8 *) "UpdateType",
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ Num = UpdateAtoi((UINT8 *) Value);
+ if (( Num >= (UINTN) UpdateOperationMaximum)) {
+ FreeAllList (SectionHead, CommentHead);
+ return Status;
+ }
+ (*UpdateArray)[Index].Index = Index;
+ (*UpdateArray)[Index].UpdateType = (UPDATE_OPERATION_TYPE) Num;
+
+ //
+ // FvBaseAddress
+ //
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) SectionName,
+ (UINT8 *) "FvBaseAddress",
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
+ (*UpdateArray)[Index].BaseAddress = (EFI_PHYSICAL_ADDRESS) Num;
+
+ //
+ // FileBuid
+ //
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) SectionName,
+ (UINT8 *) "FileGuid",
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ Status = UpdateStringToGuid ((UINT8 *) Value, &FileGuid);
+ if (EFI_ERROR (Status)) {
+ FreeAllList (SectionHead, CommentHead);
+ return Status;
+ }
+ CopyMem (&((*UpdateArray)[Index].FileGuid), &FileGuid, sizeof(EFI_GUID));
+
+ //
+ // FaultTolerant
+ // Default value is FALSE
+ //
+ Value = NULL;
+ (*UpdateArray)[Index].FaultTolerant = FALSE;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) SectionName,
+ (UINT8 *) "FaultTolerant",
+ (UINT8 **) &Value
+ );
+ if (EFI_ERROR (Status) && (Status != EFI_NOT_FOUND)) {
+ FreeAllList (SectionHead, CommentHead);
+ return Status;
+ } else if (Value != NULL) {
+ if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "TRUE") == 0) {
+ (*UpdateArray)[Index].FaultTolerant = TRUE;
+ } else if (AsciiStriCmp ((CONST CHAR8 *) Value, (CONST CHAR8 *) "FALSE") == 0) {
+ (*UpdateArray)[Index].FaultTolerant = FALSE;
+ }
+ }
+
+ if ((*UpdateArray)[Index].UpdateType == UpdateFvRange) {
+ //
+ // Length
+ //
+ Value = NULL;
+ Status = UpdateGetProfileString (
+ SectionHead,
+ (UINT8 *) SectionName,
+ (UINT8 *) "Length",
+ (UINT8 **) &Value
+ );
+ if (Value == NULL) {
+ FreeAllList (SectionHead, CommentHead);
+ return EFI_NOT_FOUND;
+ }
+
+ Num = AsciiStrHexToUintn ((CONST CHAR8 *) Value);
+ (*UpdateArray)[Index].Length = (UINTN) Num;
+ }
+ }
+
+ //
+ // Now all configuration data got. Free those temporary buffers
+ //
+ FreeAllList (SectionHead, CommentHead);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c
new file mode 100644
index 0000000000..e1f1b023dc
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDispatcher.c
@@ -0,0 +1,846 @@
+/** @file
+ Functions in this file will mainly focus on looking through the capsule
+ for the image to be programmed, and the flash area that is going to be
+ programed.
+
+ Copyright (c) 2002 - 2014, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "UpdateDriver.h"
+
+EFI_HII_HANDLE gHiiHandle;
+
+/**
+ Update the whole FV, or certain files in the FV.
+
+ @param ConfigData Pointer to the config data on updating file.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+ @param FileType FFS file type.
+ @param FileAttributes FFS file attribute.
+
+ @retval EFI_NOT_FOUND The matched FVB protocol is not found.
+ @retval EFI_SUCCESS The image buffer is updated into FV.
+
+**/
+EFI_STATUS
+PerformUpdateOnFirmwareVolume (
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ )
+{
+ EFI_STATUS Status;
+ BOOLEAN Found;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ UINTN Index;
+ UINTN NumOfHandles;
+ EFI_HANDLE *HandleBuffer;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+
+ //
+ // Locate all Fvb protocol
+ //
+ HandleBuffer = NULL;
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &NumOfHandles,
+ &HandleBuffer
+ );
+ if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Check the FVB protocol one by one
+ //
+ Found = FALSE;
+ FvbProtocol = NULL;
+ for (Index = 0; Index < NumOfHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &FvbProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Ensure this FVB protocol supported Write operation.
+ //
+ Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
+ continue;
+ }
+
+ Status = FvbProtocol->GetPhysicalAddress (
+ FvbProtocol,
+ &BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ if (BaseAddress == ConfigData->BaseAddress) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Now we have got the corresponding FVB protocol. Use the FVB protocol
+ // to update the whole FV, or certain files in the FV.
+ //
+ if (ConfigData->UpdateType == UpdateWholeFV) {
+ if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ Status = PerformUpdateOnWholeFv (
+ HandleBuffer[Index],
+ FvbProtocol,
+ ConfigData,
+ ImageBuffer,
+ ImageSize
+ );
+ }
+ } else if (ConfigData->UpdateType == UpdateFvFile) {
+ Status = PerformUpdateOnFvFile (
+ HandleBuffer[Index],
+ FvbProtocol,
+ ConfigData,
+ ImageBuffer,
+ ImageSize,
+ FileType,
+ FileAttributes
+ );
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Update the file directly into flash area.
+
+ @param ConfigData Pointer to the config data on updating file.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+
+ @retval EFI_SUCCESS The file is updated into flash area.
+ @retval EFI_NOT_FOUND The FVB protocol for the updated flash area is not found.
+
+**/
+EFI_STATUS
+PerformUpdateOnFlashArea (
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize
+ )
+{
+ EFI_STATUS Status;
+ UINTN SizeLeft;
+ EFI_PHYSICAL_ADDRESS FlashAddress;
+ UINT8 *PtrImage;
+ BOOLEAN Found;
+ EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol;
+ UINTN Index;
+ UINTN NumOfHandles;
+ EFI_HANDLE *HandleBuffer;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_HANDLE FvbHandle;
+ UINTN SizeUpdated;
+ CHAR16 *TmpStr;
+ EFI_FVB_ATTRIBUTES_2 Attributes;
+
+ SizeLeft = ImageSize;
+ PtrImage = ImageBuffer;
+ FlashAddress = ConfigData->BaseAddress;
+ Status = EFI_SUCCESS;
+ HandleBuffer = NULL;
+
+ //
+ // Print on screen
+ //
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_FLASH_RANGE), NULL);
+ if (TmpStr != NULL) {
+ Print (TmpStr, FlashAddress, ((UINT64)SizeLeft + FlashAddress));
+ FreePool (TmpStr);
+ }
+
+ //
+ // Locate all Fvb protocol
+ //
+ Status = gBS->LocateHandleBuffer (
+ ByProtocol,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ NULL,
+ &NumOfHandles,
+ &HandleBuffer
+ );
+ if ((EFI_ERROR (Status)) || (NumOfHandles == 0) || (HandleBuffer == NULL)) {
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ while (SizeLeft > 0) {
+ //
+ // First get the FVB protocols. If the flash area is a FV, or sub FV,
+ // we can directly locate all the FVB protocol. Otherwise we should use
+ // implementation specific method to get the alternate FVB protocol
+ //
+ Found = FALSE;
+ FvbProtocol = NULL;
+
+ //
+ // Check the FVB protocol one by one
+ //
+ for (Index = 0; Index < NumOfHandles; Index++) {
+ Status = gBS->HandleProtocol (
+ HandleBuffer[Index],
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ (VOID **) &FvbProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ //
+ // Ensure this FVB protocol supported Write operation.
+ //
+ Status = FvbProtocol->GetAttributes (FvbProtocol, &Attributes);
+ if (EFI_ERROR (Status) || ((Attributes & EFI_FVB2_WRITE_STATUS) == 0)) {
+ continue;
+ }
+
+ Status = FvbProtocol->GetPhysicalAddress (
+ FvbProtocol,
+ &BaseAddress
+ );
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *)(UINTN)BaseAddress;
+
+ //
+ // This sub area entry falls in the range of the FV
+ //
+ if ((FlashAddress >= BaseAddress) && (FlashAddress < (BaseAddress + FwVolHeader->FvLength))) {
+ Found = TRUE;
+ break;
+ }
+ }
+
+ if (!Found) {
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+ return EFI_NOT_FOUND;
+ }
+
+ FvbHandle = HandleBuffer[Index];
+ SizeUpdated = 0;
+
+ //
+ // If the flash area is boot required, the update must be fault tolerant
+ //
+ if (ConfigData->FaultTolerant) {
+ //
+ // Finally we are here. We have got the corresponding FVB protocol. Now
+ // we need to convert the physical address to LBA and offset and call
+ // FTW write. Also check if the flash range is larger than the FV.
+ //
+ Status = FaultTolerantUpdateOnPartFv (
+ PtrImage,
+ SizeLeft,
+ &SizeUpdated,
+ ConfigData,
+ FlashAddress,
+ FvbProtocol,
+ FvbHandle
+ );
+ } else {
+ //
+ // Finally we are here. We have got the corresponding FVB protocol. Now
+ // we need to convert the physical address to LBA and offset and call
+ // FVB write. Also check if the flash range is larger than the FV.
+ //
+ Status = NonFaultTolerantUpdateOnPartFv (
+ PtrImage,
+ SizeLeft,
+ &SizeUpdated,
+ FlashAddress,
+ FvbProtocol,
+ FvbHandle
+ );
+ }
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // As part of the FV has been replaced, the FV driver shall re-parse
+ // the firmware volume. So re-install FVB protocol here
+ //
+ Status = gBS->ReinstallProtocolInterface (
+ FvbHandle,
+ &gEfiFirmwareVolumeBlockProtocolGuid,
+ FvbProtocol,
+ FvbProtocol
+ );
+
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ //
+ // Check if we are done with the update
+ //
+ SizeLeft = SizeLeft - SizeUpdated;
+ FlashAddress = FlashAddress + SizeUpdated;
+ PtrImage = PtrImage + SizeUpdated;
+ }
+
+ if (HandleBuffer != NULL) {
+ FreePool (HandleBuffer);
+ HandleBuffer = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Find the updated file, and program it into the flash area based on the config data.
+
+ @param FwVolProtocol Pointer to FV protocol that contains the updated file.
+ @param ConfigData Pointer to the Config Data on updating file.
+
+ @retval EFI_INVALID_PARAMETER The update operation is not valid.
+ @retval EFI_NOT_FOUND The updated file is not found.
+ @retval EFI_SUCCESS The file is updated into the flash area.
+
+**/
+EFI_STATUS
+PerformUpdate (
+ IN EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData
+ )
+{
+ EFI_STATUS Status;
+ UINT8 *FileBuffer;
+ UINTN FileBufferSize;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attrib;
+ EFI_SECTION_TYPE SectionType;
+ UINT32 AuthenticationStatus;
+ CHAR16 *TmpStr;
+ BOOLEAN StartToUpdate;
+
+ Status = EFI_SUCCESS;
+ FileBuffer = NULL;
+ FileBufferSize = 0;
+ Status = FwVolProtocol->ReadFile (
+ FwVolProtocol,
+ &(ConfigData->FileGuid),
+ (VOID **) &FileBuffer,
+ &FileBufferSize,
+ &FileType,
+ &Attrib,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+
+ StartToUpdate = FALSE;
+
+ //
+ // Check if the update image is the one we require
+ // and then perform the update
+ //
+ switch (ConfigData->UpdateType) {
+
+ case UpdateWholeFV:
+
+ //
+ // For UpdateWholeFv, the update file shall be a firmware volume
+ // image file.
+ //
+ if (FileType != EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE) {
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be of TYPE EFI_FV_FILETYPE_FIRMWARE_VOLUME_IMAGE\n"));
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ }
+ SectionType = EFI_SECTION_FIRMWARE_VOLUME_IMAGE;
+ FileBuffer = NULL;
+ FileBufferSize = 0;
+ Status = FwVolProtocol->ReadSection (
+ FwVolProtocol,
+ &(ConfigData->FileGuid),
+ SectionType,
+ 0,
+ (VOID **) &FileBuffer,
+ &FileBufferSize,
+ &AuthenticationStatus
+ );
+ if (!EFI_ERROR (Status)) {
+ //
+ // Execute the update. For UpdateWholeFv, the update
+ // will always execute on a whole FV
+ //
+ StartToUpdate = TRUE;
+ Status = PerformUpdateOnFirmwareVolume (
+ ConfigData,
+ FileBuffer,
+ FileBufferSize,
+ FileType,
+ Attrib
+ );
+
+ } else {
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should be sectioned with TYPE EFI_SECTION_FIRMWARE_VOLUME_IMAGE\n"));
+ }
+ }
+ break;
+
+ case UpdateFvRange:
+
+ //
+ // For UpdateFvRange, the update file shall be a raw file
+ // which does not contain any sections. The contents of the file
+ // will be directly programmed.
+ //
+ if (FileType != EFI_FV_FILETYPE_RAW) {
+ DEBUG ((EFI_D_UPDATE, "UpdateDriver: Data file should of TYPE EFI_FV_FILETYPE_RAW\n"));
+ Status = EFI_INVALID_PARAMETER;
+ } else {
+ //
+ // For UpdateFvRange, the update may be performed on a sub area
+ // of a certain FV, or a flash area that is not FV, or part of FV.
+ // The update may also go across more than one FVs.
+ //
+ StartToUpdate = TRUE;
+ Status = PerformUpdateOnFlashArea (
+ ConfigData,
+ FileBuffer,
+ FileBufferSize
+ );
+ }
+ break;
+
+ case UpdateFvFile:
+
+ //
+ // No check will be done the the file got. The contents of the file
+ // will be directly programmed.
+ // Though UpdateFvFile will only update a single file, but the update
+ // will always execute on a FV
+ //
+ StartToUpdate = TRUE;
+ Status = PerformUpdateOnFirmwareVolume (
+ ConfigData,
+ FileBuffer,
+ FileBufferSize,
+ FileType,
+ Attrib
+ );
+ break;
+
+ default:
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ if (StartToUpdate) {
+ if (EFI_ERROR (Status)) {
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_ABORTED), NULL);
+ } else {
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_DRIVER_DONE), NULL);
+ }
+ if (TmpStr != NULL) {
+ Print (TmpStr);
+ FreePool (TmpStr);
+ }
+ }
+
+ if (FileBuffer != NULL) {
+ FreePool(FileBuffer);
+ FileBuffer = NULL;
+ }
+
+ return Status;
+}
+
+/**
+ Process the input firmware volume by using DXE service ProcessFirmwareVolume.
+
+ @param DataBuffer Point to the FV image to be processed.
+ @param BufferSize Size of the FV image buffer.
+ @param FwVolProtocol Point to the installed FV protocol for the input FV image.
+
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_VOLUME_CORRUPTED FV image is corrupted.
+ @retval EFI_SUCCESS FV image is processed and FV protocol is installed.
+
+**/
+EFI_STATUS
+ProcessUpdateImage (
+ UINT8 *DataBuffer,
+ UINTN BufferSize,
+ EFI_FIRMWARE_VOLUME2_PROTOCOL **FwVolProtocol
+ )
+{
+ EFI_FIRMWARE_VOLUME_HEADER *FwVolHeader;
+ EFI_HANDLE FwVolHandle;
+ EFI_STATUS Status;
+ UINT8 *ProcessedDataBuffer;
+ UINT32 FvAlignment;
+
+ ProcessedDataBuffer = NULL;
+ FwVolHeader = (EFI_FIRMWARE_VOLUME_HEADER *) DataBuffer;
+ if (FwVolHeader->FvLength != BufferSize) {
+ return EFI_VOLUME_CORRUPTED;
+ }
+
+ FvAlignment = 1 << ((FwVolHeader->Attributes & EFI_FVB2_ALIGNMENT) >> 16);
+ //
+ // FvAlignment must be greater than or equal to 8 bytes of the minimum FFS alignment value.
+ //
+ if (FvAlignment < 8) {
+ FvAlignment = 8;
+ }
+ //
+ // Check FvImage Align is required.
+ //
+ if (((UINTN) FwVolHeader % FvAlignment) == 0) {
+ ProcessedDataBuffer = DataBuffer;
+ } else {
+ //
+ // Allocate new aligned buffer to store DataBuffer.
+ //
+ ProcessedDataBuffer = AllocateAlignedPages (EFI_SIZE_TO_PAGES (BufferSize), (UINTN) FvAlignment);
+ if (ProcessedDataBuffer == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+ CopyMem (ProcessedDataBuffer, DataBuffer, BufferSize);
+ }
+ //
+ // Process the firmware volume
+ //
+ gDS->ProcessFirmwareVolume (
+ ProcessedDataBuffer,
+ BufferSize,
+ &FwVolHandle
+ );
+
+ //
+ // Get the FwVol protocol
+ //
+ Status = gBS->HandleProtocol (
+ FwVolHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) FwVolProtocol
+ );
+
+ return Status;
+}
+
+/**
+ Find the image in the same FV and program it in a target Firmware Volume device.
+ After update image, it will reset system and no return.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_ABORTED System reset failed.
+ @retval EFI_NOT_FOUND The updated image is not found in the same FV.
+
+**/
+EFI_STATUS
+EFIAPI
+InitializeUpdateDriver (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+ EFI_LOADED_IMAGE_PROTOCOL *LoadedImageProtocol;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *FwVolProtocol;
+ EFI_FIRMWARE_VOLUME2_PROTOCOL *DataFwVolProtocol;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *FwVolFilePathNode;
+ MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *AlignedDevPathNode;
+ EFI_DEVICE_PATH_PROTOCOL *FilePathNode;
+ EFI_SECTION_TYPE SectionType;
+ UINT8 *FileBuffer;
+ UINTN FileBufferSize;
+ EFI_FV_FILETYPE FileType;
+ EFI_FV_FILE_ATTRIBUTES Attrib;
+ UINT32 AuthenticationStatus;
+ UPDATE_CONFIG_DATA *ConfigData;
+ UPDATE_CONFIG_DATA *UpdateConfigData;
+ UINTN NumOfUpdates;
+ UINTN Index;
+ CHAR16 *TmpStr;
+
+ //
+ // Clear screen
+ //
+ if (gST->ConOut != NULL) {
+ gST->ConOut->ClearScreen (gST->ConOut);
+ gST->ConOut->SetAttribute (gST->ConOut, EFI_YELLOW | EFI_BRIGHT);
+ gST->ConOut->EnableCursor (gST->ConOut, FALSE);
+ }
+
+ gHiiHandle = HiiAddPackages (
+ &gEfiCallerIdGuid,
+ NULL,
+ UpdateDriverDxeStrings,
+ NULL
+ );
+ ASSERT (gHiiHandle != NULL);
+
+ //
+ // In order to look for the update data file and programmed image file
+ // from the same volume which this driver is dispatched from, we need
+ // to get the device path of this driver image. It is done by first
+ // locate the LoadedImageProtocol and then get its device path
+ //
+ Status = gBS->OpenProtocol (
+ ImageHandle,
+ &gEfiLoadedImageProtocolGuid,
+ (VOID **)&LoadedImageProtocol,
+ ImageHandle,
+ NULL,
+ EFI_OPEN_PROTOCOL_GET_PROTOCOL
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ //
+ // Get the firmware volume protocol where this file resides
+ //
+ Status = gBS->HandleProtocol (
+ LoadedImageProtocol->DeviceHandle,
+ &gEfiFirmwareVolume2ProtocolGuid,
+ (VOID **) &FwVolProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Shall do some extra check to see if it is really contained in the FV?
+ // Should be able to find the section of this driver in the the FV.
+ //
+ FilePathNode = LoadedImageProtocol->FilePath;
+ FwVolFilePathNode = NULL;
+ while (!IsDevicePathEnd (FilePathNode)) {
+ if (EfiGetNameGuidFromFwVolDevicePathNode ((MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *)FilePathNode)!= NULL) {
+ FwVolFilePathNode = (MEDIA_FW_VOL_FILEPATH_DEVICE_PATH *) FilePathNode;
+ break;
+ }
+ FilePathNode = NextDevicePathNode (FilePathNode);
+ }
+
+ if (FwVolFilePathNode != NULL) {
+ AlignedDevPathNode = AllocateCopyPool (DevicePathNodeLength (FwVolFilePathNode), FwVolFilePathNode);
+
+ SectionType = EFI_SECTION_PE32;
+ FileBuffer = NULL;
+ FileBufferSize = 0;
+ Status = FwVolProtocol->ReadSection (
+ FwVolProtocol,
+ &(AlignedDevPathNode->FvFileName),
+ SectionType,
+ 0,
+ (VOID **) &FileBuffer,
+ &FileBufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (AlignedDevPathNode);
+ return Status;
+ }
+
+ if (FileBuffer != NULL) {
+ FreePool(FileBuffer);
+ FileBuffer = NULL;
+ }
+
+ //
+ // Check the NameGuid of the udpate driver so that it can be
+ // used as the CallerId in fault tolerant write protocol
+ //
+ if (!CompareGuid (&gEfiCallerIdGuid, &(AlignedDevPathNode->FvFileName))) {
+ FreePool (AlignedDevPathNode);
+ return EFI_NOT_FOUND;
+ }
+ FreePool (AlignedDevPathNode);
+ } else {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Now try to find the script file. The script file is usually
+ // a raw data file which does not contain any sections.
+ //
+ FileBuffer = NULL;
+ FileBufferSize = 0;
+ Status = FwVolProtocol->ReadFile (
+ FwVolProtocol,
+ &gEfiConfigFileNameGuid,
+ (VOID **) &FileBuffer,
+ &FileBufferSize,
+ &FileType,
+ &Attrib,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (FileType != EFI_FV_FILETYPE_RAW) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // Parse the configuration file.
+ //
+ ConfigData = NULL;
+ NumOfUpdates = 0;
+ Status = ParseUpdateDataFile (
+ FileBuffer,
+ FileBufferSize,
+ &NumOfUpdates,
+ &ConfigData
+ );
+ if (FileBuffer != NULL) {
+ FreePool (FileBuffer);
+ FileBuffer = NULL;
+ }
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ ASSERT (ConfigData != NULL);
+
+ //
+ // Now find the update image. The update image should be put in a FV, and then
+ // encapsulated as a raw FFS file. This is to prevent the update image from
+ // being dispatched. So the raw data we get here should be an FV. We need to
+ // process this FV and read the files that is going to be updated.
+ //
+ FileBuffer = NULL;
+ FileBufferSize = 0;
+ Status = FwVolProtocol->ReadFile (
+ FwVolProtocol,
+ &gEfiUpdateDataFileGuid,
+ (VOID **) &FileBuffer,
+ &FileBufferSize,
+ &FileType,
+ &Attrib,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ if (FileType != EFI_FV_FILETYPE_RAW) {
+ return EFI_NOT_FOUND;
+ }
+
+ //
+ // FileBuffer should be an FV. Process the FV
+ //
+ DataFwVolProtocol = NULL;
+ Status = ProcessUpdateImage (
+ FileBuffer,
+ FileBufferSize,
+ &DataFwVolProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (FileBuffer);
+ return Status;
+ }
+
+ //
+ // Print on screen
+ //
+ TmpStr = HiiGetString (gHiiHandle, STRING_TOKEN(UPDATE_PROCESS_DATA), NULL);
+ if (TmpStr != NULL) {
+ Print (TmpStr);
+ FreePool(TmpStr);
+ }
+
+ //
+ // Execute the update
+ //
+ Index = 0;
+ UpdateConfigData = ConfigData;
+ while (Index < NumOfUpdates) {
+ Status = PerformUpdate (
+ DataFwVolProtocol,
+ UpdateConfigData
+ );
+ //
+ // Shall updates be serialized so that if an update is not successfully completed,
+ // the remaining updates won't be performed.
+ //
+ if (EFI_ERROR (Status)) {
+ break;
+ }
+
+ Index++;
+ UpdateConfigData++;
+ }
+
+ if (EFI_ERROR (Status)) {
+ if (ConfigData != NULL) {
+ FreePool(ConfigData);
+ ConfigData = NULL;
+ }
+ return Status;
+ }
+
+ //
+ // Call system reset
+ //
+ gRT->ResetSystem (EfiResetCold, EFI_SUCCESS, 0, NULL);
+
+ //
+ // Hopefully it won't be reached
+ //
+ return EFI_ABORTED;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h
new file mode 100644
index 0000000000..e1f22a9d5a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriver.h
@@ -0,0 +1,213 @@
+/** @file
+ Common defines and definitions for a component update driver.
+
+ Copyright (c) 2002 - 2010, Intel Corporation. All rights reserved.<BR>
+
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions
+ of the BSD License which accompanies this distribution. The
+ full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef _EFI_UPDATE_DRIVER_H_
+#define _EFI_UPDATE_DRIVER_H_
+
+#include <PiDxe.h>
+
+#include <Protocol/LoadedImage.h>
+#include <Guid/Capsule.h>
+#include <Guid/CapsuleDataFile.h>
+#include <Protocol/FaultTolerantWrite.h>
+#include <Protocol/FirmwareVolumeBlock.h>
+#include <Protocol/FirmwareVolume2.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiRuntimeServicesTableLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/DxeServicesTableLib.h>
+#include <Library/HiiLib.h>
+#include <Library/PrintLib.h>
+#include <Library/DevicePathLib.h>
+
+extern EFI_HII_HANDLE gHiiHandle;
+
+typedef enum {
+ UpdateWholeFV = 0, // 0, update whole FV
+ UpdateFvFile, // 1, update a set of FV files asynchronously
+ UpdateFvRange, // 2, update part of FV or flash
+ UpdateOperationMaximum // 3
+} UPDATE_OPERATION_TYPE;
+
+typedef struct {
+ UINTN Index;
+ UPDATE_OPERATION_TYPE UpdateType;
+ EFI_DEVICE_PATH_PROTOCOL DevicePath;
+ EFI_PHYSICAL_ADDRESS BaseAddress;
+ EFI_GUID FileGuid;
+ UINTN Length;
+ BOOLEAN FaultTolerant;
+} UPDATE_CONFIG_DATA;
+
+typedef struct _SECTION_ITEM SECTION_ITEM;
+struct _SECTION_ITEM {
+ CHAR8 *ptrSection;
+ UINTN SecNameLen;
+ CHAR8 *ptrEntry;
+ CHAR8 *ptrValue;
+ SECTION_ITEM *ptrNext;
+};
+
+typedef struct _COMMENT_LINE COMMENT_LINE;
+struct _COMMENT_LINE {
+ CHAR8 *ptrComment;
+ COMMENT_LINE *ptrNext;
+};
+
+typedef struct {
+ EFI_GUID FileGuid;
+} UPDATE_PRIVATE_DATA;
+
+#define MAX_LINE_LENGTH 512
+#define EFI_D_UPDATE EFI_D_ERROR
+
+#define MIN_ALIGNMENT_SIZE 4
+#define ALIGN_SIZE(a) ((a % MIN_ALIGNMENT_SIZE) ? MIN_ALIGNMENT_SIZE - (a % MIN_ALIGNMENT_SIZE) : 0)
+
+/**
+ Parse Config data file to get the updated data array.
+
+ @param DataBuffer Config raw file buffer.
+ @param BufferSize Size of raw buffer.
+ @param NumOfUpdates Pointer to the number of update data.
+ @param UpdateArray Pointer to the config of update data.
+
+ @retval EFI_NOT_FOUND No config data is found.
+ @retval EFI_OUT_OF_RESOURCES No enough memory is allocated.
+ @retval EFI_SUCCESS Parse the config file successfully.
+
+**/
+EFI_STATUS
+ParseUpdateDataFile (
+ IN UINT8 *DataBuffer,
+ IN UINTN BufferSize,
+ IN OUT UINTN *NumOfUpdates,
+ IN OUT UPDATE_CONFIG_DATA **UpdateArray
+ );
+
+/**
+ Update the whole FV image, and reinsall FVB protocol for the updated FV image.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+
+ @retval EFI_INVALID_PARAMETER Update type is not UpdateWholeFV.
+ Or Image size is not same to the size of whole FV.
+ @retval EFI_OUT_OF_RESOURCES No enoug memory is allocated.
+ @retval EFI_SUCCESS FV image is updated, and its FVB protocol is reinstalled.
+
+**/
+EFI_STATUS
+PerformUpdateOnWholeFv (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize
+ );
+
+/**
+ Update certain file in the FV.
+
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+ @param FvbProtocol FVB protocol.
+ @param ConfigData Config data on updating driver.
+ @param ImageBuffer Image buffer to be updated.
+ @param ImageSize Image size.
+ @param FileType FFS file type.
+ @param FileAttributes FFS file attribute
+
+ @retval EFI_INVALID_PARAMETER Update type is not UpdateFvFile.
+ Or Image size is not same to the size of whole FV.
+ @retval EFI_UNSUPPORTED PEIM FFS is unsupported to be updated.
+ @retval EFI_SUCCESS The FFS file is added into FV.
+
+**/
+EFI_STATUS
+PerformUpdateOnFvFile (
+ IN EFI_HANDLE FvbHandle,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN UINT8 *ImageBuffer,
+ IN UINTN ImageSize,
+ IN EFI_FV_FILETYPE FileType,
+ IN EFI_FV_FILE_ATTRIBUTES FileAttributes
+ );
+
+/**
+ Update the buffer into flash area in fault tolerant write method.
+
+ @param ImageBuffer Image buffer to be updated.
+ @param SizeLeft Size of the image buffer.
+ @param UpdatedSize Size of the updated buffer.
+ @param ConfigData Config data on updating driver.
+ @param FlashAddress Flash address to be updated as start address.
+ @param FvbProtocol FVB protocol.
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+
+ @retval EFI_SUCCESS Buffer data is updated into flash.
+ @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.
+ @retval EFI_NOT_FOUND FTW protocol doesn't exist.
+ @retval EFI_OUT_OF_RESOURCES No enough backup space.
+ @retval EFI_ABORTED Error happen when update flash area.
+
+**/
+EFI_STATUS
+FaultTolerantUpdateOnPartFv (
+ IN UINT8 *ImageBuffer,
+ IN UINTN SizeLeft,
+ IN OUT UINTN *UpdatedSize,
+ IN UPDATE_CONFIG_DATA *ConfigData,
+ IN EFI_PHYSICAL_ADDRESS FlashAddress,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_HANDLE FvbHandle
+ );
+
+/**
+ Directly update the buffer into flash area without fault tolerant write method.
+
+ @param ImageBuffer Image buffer to be updated.
+ @param SizeLeft Size of the image buffer.
+ @param UpdatedSize Size of the updated buffer.
+ @param FlashAddress Flash address to be updated as start address.
+ @param FvbProtocol FVB protocol.
+ @param FvbHandle Handle of FVB protocol for the updated flash range.
+
+ @retval EFI_SUCCESS Buffer data is updated into flash.
+ @retval EFI_INVALID_PARAMETER Base flash address is not in FVB flash area.
+ @retval EFI_OUT_OF_RESOURCES No enough backup space.
+
+**/
+EFI_STATUS
+NonFaultTolerantUpdateOnPartFv (
+ IN UINT8 *ImageBuffer,
+ IN UINTN SizeLeft,
+ IN OUT UINTN *UpdatedSize,
+ IN EFI_PHYSICAL_ADDRESS FlashAddress,
+ IN EFI_FIRMWARE_VOLUME_BLOCK_PROTOCOL *FvbProtocol,
+ IN EFI_HANDLE FvbHandle
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf
new file mode 100644
index 0000000000..d83a1ecb57
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.inf
@@ -0,0 +1,76 @@
+## @file
+# Update Driver for Capulse update.
+#
+# This driver is intended to be put in a capsule (FV). If all goes well,
+# then it should be dispatched from the capsule FV, then find the image
+# in the same FV and program it in a target Firmware Volume device.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials are
+# licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = UpdateDriverDxe
+ MODULE_UNI_FILE = UpdateDriverDxe.uni
+ FILE_GUID = 0E84FC69-29CC-4C6D-92AC-6D476921850F
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = InitializeUpdateDriver
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ UpdateDriver.h
+ UpdateStrings.uni
+ UpdateDispatcher.c
+ ParseUpdateProfile.c
+ FlashUpdate.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ PrintLib
+ HiiLib
+ DxeServicesTableLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ UefiRuntimeServicesTableLib
+ BaseMemoryLib
+ DebugLib
+ DevicePathLib
+
+[Guids]
+ gEfiConfigFileNameGuid ## CONSUMES ## File # FileName to store ConfigFile
+ gEfiUpdateDataFileGuid ## CONSUMES ## File # FileName to store Capsule Data.
+
+[Protocols]
+ gEfiFaultTolerantWriteProtocolGuid ## CONSUMES
+ gEfiFirmwareVolume2ProtocolGuid ## CONSUMES
+ gEfiFirmwareVolumeBlockProtocolGuid ## CONSUMES
+ gEfiLoadedImageProtocolGuid ## CONSUMES
+
+[Depex]
+ gEfiFirmwareVolumeBlockProtocolGuid AND gEfiFaultTolerantWriteProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ UpdateDriverDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.uni b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.uni
new file mode 100644
index 0000000000..dd37abe216
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxeExtra.uni
new file mode 100644
index 0000000000..a01d23de84
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateDriverDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni
new file mode 100644
index 0000000000..16455937e5
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/FirmwareVolume/UpdateDriverDxe/UpdateStrings.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegion.c b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegion.c
new file mode 100644
index 0000000000..e432cf4403
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegion.c
@@ -0,0 +1,170 @@
+/** @file
+ Produces the Legacy Region Protocol.
+
+ This generic implementation of the Legacy Region Protocol does not actually
+ perform any lock/unlock operations. This module may be used on platforms
+ that do not provide HW locking of the legacy memory regions. It can also
+ be used as a template driver for implementing the Legacy Region Protocol on
+ a platform that does support HW locking of the legacy memory regions.
+
+Copyright (c) 2009, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <PiDxe.h>
+#include <Protocol/LegacyRegion.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+
+/**
+ Sets hardware to decode or not decode a region.
+
+ @param This Indicates the EFI_LEGACY_REGION_PROTOCOL instance
+ @param Start Start of region to decode.
+ @param Length Size in bytes of the region.
+ @param On Decode/nondecode flag.
+
+ @retval EFI_SUCCESS Decode range successfully changed.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionDecode (
+ IN EFI_LEGACY_REGION_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ IN BOOLEAN *On
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets a region to read only.
+
+ @param This Indicates the EFI_LEGACY_REGION_PROTOCOL instance
+ @param Start Start of region to lock.
+ @param Length Size in bytes of the region.
+ @param Granularity Lock attribute affects this granularity in bytes.
+
+ @retval EFI_SUCCESS The region was made read only.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionLock (
+ IN EFI_LEGACY_REGION_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets a region to read only and ensures that flash is locked from being
+ inadvertently modified.
+
+ @param This Indicates the EFI_LEGACY_REGION_PROTOCOL instance
+ @param Start Start of region to lock.
+ @param Length Size in bytes of the region.
+ @param Granularity Lock attribute affects this granularity in bytes.
+
+ @retval EFI_SUCCESS The region was made read only and flash is locked.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionBootLock (
+ IN EFI_LEGACY_REGION_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+/**
+ Sets a region to read-write.
+
+ @param This Indicates the EFI_LEGACY_REGION_PROTOCOL instance
+ @param Start Start of region to lock.
+ @param Length Size in bytes of the region.
+ @param Granularity Lock attribute affects this granularity in bytes.
+
+ @retval EFI_SUCCESS The region was successfully made read-write.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionUnlock (
+ IN EFI_LEGACY_REGION_PROTOCOL *This,
+ IN UINT32 Start,
+ IN UINT32 Length,
+ OUT UINT32 *Granularity OPTIONAL
+ )
+{
+ return EFI_SUCCESS;
+}
+
+//
+// Module global for the handle the Legacy Region Protocol is installed
+//
+EFI_HANDLE mLegacyRegionHandle = NULL;
+
+//
+// Module global for the Legacy Region Protocol instance that is installed onto
+// mLegacyRegionHandle
+//
+EFI_LEGACY_REGION_PROTOCOL mLegacyRegion = {
+ LegacyRegionDecode,
+ LegacyRegionLock,
+ LegacyRegionBootLock,
+ LegacyRegionUnlock
+};
+
+/**
+ The user Entry Point for module LegacyRegionDxe. The user code starts with this function.
+
+ @param[in] ImageHandle The firmware allocated handle for the EFI image.
+ @param[in] SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+ @retval other Some error occurs when executing this entry point.
+
+**/
+EFI_STATUS
+EFIAPI
+LegacyRegionInstall (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Make sure the Legacy Region Protocol is not already installed in the system
+ //
+ ASSERT_PROTOCOL_ALREADY_INSTALLED (NULL, &gEfiLegacyRegionProtocolGuid);
+
+ //
+ // Install the protocol on a new handle.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mLegacyRegionHandle,
+ &gEfiLegacyRegionProtocolGuid, &mLegacyRegion,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf
new file mode 100644
index 0000000000..f8e5639dec
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.inf
@@ -0,0 +1,55 @@
+## @file
+# Produces Framework Legacy Region Protocol.
+#
+# This generic implementation of the Legacy Region Protocol does not actually
+# perform any lock/unlock operations. This module may be used on platforms
+# that do not provide HW locking of the legacy memory regions. It can also
+# be used as a template driver for implementing the Legacy Region Protocol on
+# a platform that does support HW locking of the legacy memory regions.
+#
+# Copyright (c) 2009 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = LegacyRegionDxe
+ MODULE_UNI_FILE = LegacyRegionDxe.uni
+ FILE_GUID = 8C439043-85CA-467a-96F1-CB14F4D0DCDA
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = LegacyRegionInstall
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ LegacyRegion.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[LibraryClasses]
+ UefiDriverEntryPoint
+ DebugLib
+ UefiBootServicesTableLib
+
+[Protocols]
+ gEfiLegacyRegionProtocolGuid ## PRODUCES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ LegacyRegionDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.uni b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.uni
new file mode 100644
index 0000000000..a0746e961a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxeExtra.uni
new file mode 100644
index 0000000000..b04851c0d2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/LegacyRegionDxe/LegacyRegionDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtraction.c b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtraction.c
new file mode 100644
index 0000000000..76aec0ac2c
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtraction.c
@@ -0,0 +1,1456 @@
+/** @file
+ Section Extraction Protocol implementation.
+
+ Stream database is implemented as a linked list of section streams,
+ where each stream contains a linked list of children, which may be leaves or
+ encapsulations.
+
+ Children that are encapsulations generate new stream entries
+ when they are created. Streams can also be created by calls to
+ SEP->OpenSectionStream().
+
+ The database is only created far enough to return the requested data from
+ any given stream, or to determine that the requested data is not found.
+
+ If a GUIDed encapsulation is encountered, there are three possiblilites.
+
+ 1) A support protocol is found, in which the stream is simply processed with
+ the support protocol.
+
+ 2) A support protocol is not found, but the data is available to be read
+ without processing. In this case, the database is built up through the
+ recursions to return the data, and a RPN event is set that will enable
+ the stream in question to be refreshed if and when the required section
+ extraction protocol is published.This insures the AuthenticationStatus
+ does not become stale in the cache.
+
+ 3) A support protocol is not found, and the data is not available to be read
+ without it. This results in EFI_PROTOCOL_ERROR.
+
+Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+This program and the accompanying materials
+are licensed and made available under the terms and conditions of the BSD License
+which accompanies this distribution. The full text of the license may be found at
+http://opensource.org/licenses/bsd-license.php
+
+THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include <FrameworkDxe.h>
+
+#include <Library/BaseLib.h>
+#include <Library/DebugLib.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/UefiLib.h>
+#include <Protocol/Decompress.h>
+#include <Protocol/GuidedSectionExtraction.h>
+#include <Protocol/SectionExtraction.h>
+
+//
+// Local defines and typedefs
+//
+#define FRAMEWORK_SECTION_CHILD_SIGNATURE SIGNATURE_32('S','X','F','S')
+#define CHILD_SECTION_NODE_FROM_LINK(Node) \
+ CR (Node, FRAMEWORK_SECTION_CHILD_NODE, Link, FRAMEWORK_SECTION_CHILD_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINT32 Type;
+ UINT32 Size;
+ //
+ // StreamBase + OffsetInStream == pointer to section header in stream. The
+ // stream base is always known when walking the sections within.
+ //
+ UINT32 OffsetInStream;
+ //
+ // Then EncapsulatedStreamHandle below is always 0 if the section is NOT an
+ // encapsulating section. Otherwise, it contains the stream handle
+ // of the encapsulated stream. This handle is ALWAYS produced any time an
+ // encapsulating child is encountered, irrespective of whether the
+ // encapsulated stream is processed further.
+ //
+ UINTN EncapsulatedStreamHandle;
+ EFI_GUID *EncapsulationGuid;
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ EFI_EVENT Event;
+} FRAMEWORK_SECTION_CHILD_NODE;
+
+#define FRAMEWORK_SECTION_STREAM_SIGNATURE SIGNATURE_32('S','X','S','S')
+#define STREAM_NODE_FROM_LINK(Node) \
+ CR (Node, FRAMEWORK_SECTION_STREAM_NODE, Link, FRAMEWORK_SECTION_STREAM_SIGNATURE)
+
+typedef struct {
+ UINT32 Signature;
+ LIST_ENTRY Link;
+ UINTN StreamHandle;
+ UINT8 *StreamBuffer;
+ UINTN StreamLength;
+ LIST_ENTRY Children;
+ //
+ // Authentication status is from GUIDed encapsulations.
+ //
+ UINT32 AuthenticationStatus;
+} FRAMEWORK_SECTION_STREAM_NODE;
+
+#define NULL_STREAM_HANDLE 0
+
+typedef struct {
+ FRAMEWORK_SECTION_CHILD_NODE *ChildNode;
+ FRAMEWORK_SECTION_STREAM_NODE *ParentStream;
+ VOID *Registration;
+} RPN_EVENT_CONTEXT;
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param This Indicates the calling context.
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
+ contains the new section stream handle.
+
+ @retval EFI_SUCCESS Section wase opened successfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
+ last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ )
+;
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param This Pointer to SEP instance.
+ @param SectionStreamHandle The section stream from which to extract the requested
+ section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
+ SectionDefinitionGuid indicates which of these types
+ of sections to search for.
+ @param SectionInstance Indicates which instance of the requested section to
+ return.
+ @param Buffer Double indirection to buffer. If *Buffer is non-null on
+ input, then the buffer is caller allocated. If
+ *Buffer is NULL, then the buffer is callee allocated.
+ In either case, the requried buffer size is returned
+ in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if *Buffer is
+ non-null on input. On output, indicates the required
+ size (allocated size if callee allocated) of *Buffer.
+ @param AuthenticationStatus Indicates the authentication status of the retrieved
+ section.
+
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
+ stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
+ bit set, but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database. *Buffer is
+ unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
+ This indicates the SectionStream is not correctly
+ formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
+ request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section. The
+ input buffer is filled and contents are section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+;
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param This Indicates the calling context.
+ @param StreamHandleToClose Indicates the stream to close
+
+ @retval EFI_SUCCESS Section stream was closed successfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
+ last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN StreamHandleToClose
+ )
+;
+
+//
+// Module globals
+//
+LIST_ENTRY mStreamRoot = INITIALIZE_LIST_HEAD_VARIABLE (mStreamRoot);
+
+EFI_HANDLE mSectionExtractionHandle = NULL;
+
+EFI_SECTION_EXTRACTION_PROTOCOL mSectionExtraction = {
+ OpenSectionStream,
+ GetSection,
+ CloseSectionStream
+};
+
+/**
+ Entry point of the section extraction code. Initializes an instance of the
+ section extraction interface and installs it on a new handle.
+
+ @param ImageHandle A handle for the image that is initializing this driver
+ @param SystemTable A pointer to the EFI system table
+
+ @retval EFI_SUCCESS Driver initialized successfully
+ @retval EFI_OUT_OF_RESOURCES Could not allocate needed resources
+
+**/
+EFI_STATUS
+EFIAPI
+SectionExtractionEntryPoint (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Install SEP to a new handle
+ //
+ Status = gBS->InstallProtocolInterface (
+ &mSectionExtractionHandle,
+ &gEfiSectionExtractionProtocolGuid,
+ EFI_NATIVE_INTERFACE,
+ &mSectionExtraction
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return Status;
+}
+
+/**
+
+ Check if a stream is valid.
+
+ @param SectionStream The section stream to be checked
+ @param SectionStreamLength The length of section stream
+
+ @return A boolean value indicating the validness of the section stream.
+
+**/
+BOOLEAN
+IsValidSectionStream (
+ IN VOID *SectionStream,
+ IN UINTN SectionStreamLength
+ )
+{
+ UINTN TotalLength;
+ UINTN SectionLength;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMMON_SECTION_HEADER *NextSectionHeader;
+
+ TotalLength = 0;
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *)SectionStream;
+
+ while (TotalLength < SectionStreamLength) {
+ if (IS_SECTION2 (SectionHeader)) {
+ SectionLength = SECTION2_SIZE (SectionHeader);
+ } else {
+ SectionLength = SECTION_SIZE (SectionHeader);
+ }
+ TotalLength += SectionLength;
+
+ if (TotalLength == SectionStreamLength) {
+ return TRUE;
+ }
+
+ //
+ // Move to the next byte following the section...
+ //
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *) ((UINT8 *) SectionHeader + SectionLength);
+
+ //
+ // Figure out where the next section begins
+ //
+ NextSectionHeader = ALIGN_POINTER(SectionHeader, 4);
+ TotalLength += (UINTN) NextSectionHeader - (UINTN) SectionHeader;
+ SectionHeader = NextSectionHeader;
+ }
+
+ ASSERT (FALSE);
+ return FALSE;
+}
+
+/**
+ Worker function. Constructor for section streams.
+
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param AllocateBuffer Indicates whether the stream buffer is to be copied
+ or the input buffer is to be used in place.
+ @param AuthenticationStatus Indicates the default authentication status for the
+ new stream.
+ @param SectionStreamHandle A pointer to a caller allocated section stream handle.
+
+ @retval EFI_SUCCESS Stream was added to stream database.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+
+**/
+EFI_STATUS
+OpenSectionStreamEx (
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ IN BOOLEAN AllocateBuffer,
+ IN UINT32 AuthenticationStatus,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ FRAMEWORK_SECTION_STREAM_NODE *NewStream;
+ EFI_TPL OldTpl;
+
+ //
+ // Allocate a new stream
+ //
+ NewStream = AllocatePool (sizeof (FRAMEWORK_SECTION_STREAM_NODE));
+ if (NewStream == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (AllocateBuffer) {
+ //
+ // if we're here, we're double buffering, allocate the buffer and copy the
+ // data in
+ //
+ if (SectionStreamLength > 0) {
+ NewStream->StreamBuffer = AllocatePool (SectionStreamLength);
+ if (NewStream->StreamBuffer == NULL) {
+ FreePool (NewStream);
+ return EFI_OUT_OF_RESOURCES;
+ }
+ //
+ // Copy in stream data
+ //
+ CopyMem (NewStream->StreamBuffer, SectionStream, SectionStreamLength);
+ } else {
+ //
+ // It's possible to have a zero length section stream.
+ //
+ NewStream->StreamBuffer = NULL;
+ }
+ } else {
+ //
+ // If were here, the caller has supplied the buffer (it's an internal call)
+ // so just assign the buffer. This happens when we open section streams
+ // as a result of expanding an encapsulating section.
+ //
+ NewStream->StreamBuffer = SectionStream;
+ }
+
+ //
+ // Initialize the rest of the section stream
+ //
+ NewStream->Signature = FRAMEWORK_SECTION_STREAM_SIGNATURE;
+ NewStream->StreamHandle = (UINTN) NewStream;
+ NewStream->StreamLength = SectionStreamLength;
+ InitializeListHead (&NewStream->Children);
+ NewStream->AuthenticationStatus = AuthenticationStatus;
+
+ //
+ // Add new stream to stream list
+ //
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ InsertTailList (&mStreamRoot, &NewStream->Link);
+ gBS->RestoreTPL (OldTpl);
+
+ *SectionStreamHandle = NewStream->StreamHandle;
+
+ return EFI_SUCCESS;
+}
+
+/**
+ SEP member function. This function creates and returns a new section stream
+ handle to represent the new section stream.
+
+ @param This Indicates the calling context.
+ @param SectionStreamLength Size in bytes of the section stream.
+ @param SectionStream Buffer containing the new section stream.
+ @param SectionStreamHandle A pointer to a caller allocated UINTN that on output
+ contains the new section stream handle.
+
+ @retval EFI_SUCCESS Section wase opened successfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
+ last section.
+
+**/
+EFI_STATUS
+EFIAPI
+OpenSectionStream (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN SectionStreamLength,
+ IN VOID *SectionStream,
+ OUT UINTN *SectionStreamHandle
+ )
+{
+ //
+ // Check to see section stream looks good...
+ //
+ if (!IsValidSectionStream (SectionStream, SectionStreamLength)) {
+ return EFI_INVALID_PARAMETER;
+ }
+
+ return OpenSectionStreamEx (
+ SectionStreamLength,
+ SectionStream,
+ TRUE,
+ 0,
+ SectionStreamHandle
+ );
+}
+
+/**
+ Worker function. Determine if the input stream:child matches the input type.
+
+ @param Stream Indicates the section stream associated with the child
+ @param Child Indicates the child to check
+ @param SearchType Indicates the type of section to check against for
+ @param SectionDefinitionGuid Indicates the GUID to check against if the type is
+ EFI_SECTION_GUID_DEFINED
+
+ @retval TRUE The child matches
+ @retval FALSE The child doesn't match
+
+**/
+BOOLEAN
+ChildIsType (
+ IN FRAMEWORK_SECTION_STREAM_NODE *Stream,
+ IN FRAMEWORK_SECTION_CHILD_NODE *Child,
+ IN EFI_SECTION_TYPE SearchType,
+ IN EFI_GUID *SectionDefinitionGuid
+ )
+{
+ EFI_GUID_DEFINED_SECTION *GuidedSection;
+
+ if (SearchType == EFI_SECTION_ALL) {
+ return TRUE;
+ }
+ if (Child->Type != SearchType) {
+ return FALSE;
+ }
+ if ((SearchType != EFI_SECTION_GUID_DEFINED) || (SectionDefinitionGuid == NULL)) {
+ return TRUE;
+ }
+ GuidedSection = (EFI_GUID_DEFINED_SECTION * )(Stream->StreamBuffer + Child->OffsetInStream);
+ if (IS_SECTION2 (GuidedSection)) {
+ return CompareGuid (&(((EFI_GUID_DEFINED_SECTION2 *) GuidedSection)->SectionDefinitionGuid), SectionDefinitionGuid);
+ } else {
+ return CompareGuid (&GuidedSection->SectionDefinitionGuid, SectionDefinitionGuid);
+ }
+}
+
+/**
+ Create a protocol notification event and return it.
+
+ @param ProtocolGuid Protocol to register notification event on.
+ @param NotifyTpl Maximum TPL to signal the NotifyFunction.
+ @param NotifyFunction EFI notification routine.
+ @param NotifyContext Context passed into Event when it is created.
+ @param Registration Registration key returned from RegisterProtocolNotify().
+ @param SignalFlag Boolean value to decide whether kick the event after register or not.
+
+ @return The EFI_EVENT that has been registered to be signaled when a ProtocolGuid
+ is added to the system.
+
+**/
+EFI_EVENT
+CreateProtocolNotifyEvent (
+ IN EFI_GUID *ProtocolGuid,
+ IN EFI_TPL NotifyTpl,
+ IN EFI_EVENT_NOTIFY NotifyFunction,
+ IN VOID *NotifyContext,
+ OUT VOID **Registration,
+ IN BOOLEAN SignalFlag
+ )
+{
+ EFI_STATUS Status;
+ EFI_EVENT Event;
+
+ //
+ // Create the event
+ //
+
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ NotifyTpl,
+ NotifyFunction,
+ NotifyContext,
+ &Event
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Register for protocol notifactions on this event
+ //
+
+ Status = gBS->RegisterProtocolNotify (
+ ProtocolGuid,
+ Event,
+ Registration
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ if (SignalFlag) {
+ //
+ // Kick the event so we will perform an initial pass of
+ // current installed drivers
+ //
+ gBS->SignalEvent (Event);
+ }
+
+ return Event;
+}
+
+/**
+ Verify the Guided Section GUID by checking if there is the Guided Section GUID configuration table recorded the GUID itself.
+
+ @param GuidedSectionGuid The Guided Section GUID.
+ @param GuidedSectionExtraction A pointer to the pointer to the supported Guided Section Extraction Protocol
+ for the Guided Section.
+
+ @return TRUE The GuidedSectionGuid could be identified, and the pointer to
+ the Guided Section Extraction Protocol will be returned to *GuidedSectionExtraction.
+ @return FALSE The GuidedSectionGuid could not be identified, or
+ the Guided Section Extraction Protocol has not been installed yet.
+
+**/
+BOOLEAN
+VerifyGuidedSectionGuid (
+ IN EFI_GUID *GuidedSectionGuid,
+ OUT EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL **GuidedSectionExtraction
+ )
+{
+ EFI_GUID *GuidRecorded;
+ VOID *Interface;
+ EFI_STATUS Status;
+
+ //
+ // Check if there is the Guided Section GUID configuration table recorded the GUID itself.
+ //
+ Status = EfiGetSystemConfigurationTable (GuidedSectionGuid, (VOID **) &GuidRecorded);
+ if (Status == EFI_SUCCESS) {
+ if (CompareGuid (GuidRecorded, GuidedSectionGuid)) {
+ //
+ // Found the recorded GuidedSectionGuid.
+ //
+ Status = gBS->LocateProtocol (GuidedSectionGuid, NULL, (VOID **) &Interface);
+ if (!EFI_ERROR (Status) && Interface != NULL) {
+ //
+ // Found the supported Guided Section Extraction Porotocol for the Guided Section.
+ //
+ *GuidedSectionExtraction = (EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *) Interface;
+ return TRUE;
+ }
+ return FALSE;
+ }
+ }
+
+ return FALSE;
+}
+
+/**
+ RPN callback function.
+ 1. Initialize the section stream when the GUIDED_SECTION_EXTRACTION_PROTOCOL is installed.
+ 2. Removes a stale section stream and re-initializes it with an updated AuthenticationStatus.
+
+ @param Event The event that fired
+ @param RpnContext A pointer to the context that allows us to identify
+ the relevent encapsulation.
+
+**/
+VOID
+EFIAPI
+NotifyGuidedExtraction (
+ IN EFI_EVENT Event,
+ IN VOID *RpnContext
+ )
+{
+ EFI_STATUS Status;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ RPN_EVENT_CONTEXT *Context;
+
+ Context = RpnContext;
+ Status = EFI_SUCCESS;
+ if (Context->ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ Status = CloseSectionStream (&mSectionExtraction, Context->ChildNode->EncapsulatedStreamHandle);
+ }
+ if (!EFI_ERROR (Status)) {
+ //
+ // The stream is not initialized, open it.
+ // Or the stream closed successfully, so re-open the stream with correct AuthenticationStatus.
+ //
+
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *)
+ (Context->ParentStream->StreamBuffer + Context->ChildNode->OffsetInStream);
+ ASSERT (GuidedHeader->CommonHeader.Type == EFI_SECTION_GUID_DEFINED);
+
+ if (!VerifyGuidedSectionGuid (Context->ChildNode->EncapsulationGuid, &GuidedExtraction)) {
+ return;
+ }
+
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ ASSERT_EFI_ERROR (Status);
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Context->ParentStream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Context->ChildNode->EncapsulatedStreamHandle
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // If above, the stream did not close successfully, it indicates it's
+ // already been closed by someone, so just destroy the event and be done with
+ // it.
+ //
+
+ gBS->CloseEvent (Event);
+ Context->ChildNode->Event = NULL;
+ FreePool (Context);
+}
+
+/**
+ Worker function. Constructor for RPN event if needed to keep AuthenticationStatus
+ cache correct when a missing GUIDED_SECTION_EXTRACTION_PROTOCOL appears...
+
+ @param ParentStream Indicates the parent of the ecnapsulation section (child)
+ @param ChildNode Indicates the child node that is the encapsulation section.
+
+**/
+VOID
+CreateGuidedExtractionRpnEvent (
+ IN FRAMEWORK_SECTION_STREAM_NODE *ParentStream,
+ IN FRAMEWORK_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ RPN_EVENT_CONTEXT *Context;
+
+ //
+ // Allocate new event structure and context
+ //
+ Context = AllocatePool (sizeof (RPN_EVENT_CONTEXT));
+ ASSERT (Context != NULL);
+
+ Context->ChildNode = ChildNode;
+ Context->ParentStream = ParentStream;
+
+ Context->ChildNode->Event = CreateProtocolNotifyEvent (
+ Context->ChildNode->EncapsulationGuid,
+ TPL_NOTIFY,
+ NotifyGuidedExtraction,
+ Context,
+ &Context->Registration,
+ FALSE
+ );
+}
+
+/**
+ Worker function. Constructor for new child nodes.
+
+ @param Stream Indicates the section stream in which to add the child.
+ @param ChildOffset Indicates the offset in Stream that is the beginning
+ of the child section.
+ @param ChildNode Indicates the Callee allocated and initialized child.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_PROTOCOL_ERROR Encapsulation sections produce new stream handles when
+ the child node is created. If the section type is GUID
+ defined, and the extraction GUID does not exist, and
+ producing the stream requires the GUID, then a protocol
+ error is generated and no child is produced.
+ Values returned by OpenSectionStreamEx.
+
+**/
+EFI_STATUS
+CreateChildNode (
+ IN FRAMEWORK_SECTION_STREAM_NODE *Stream,
+ IN UINT32 ChildOffset,
+ OUT FRAMEWORK_SECTION_CHILD_NODE **ChildNode
+ )
+{
+ EFI_STATUS Status;
+ EFI_COMMON_SECTION_HEADER *SectionHeader;
+ EFI_COMPRESSION_SECTION *CompressionHeader;
+ EFI_GUID_DEFINED_SECTION *GuidedHeader;
+ EFI_DECOMPRESS_PROTOCOL *Decompress;
+ EFI_GUIDED_SECTION_EXTRACTION_PROTOCOL *GuidedExtraction;
+ VOID *NewStreamBuffer;
+ VOID *ScratchBuffer;
+ UINT32 ScratchSize;
+ UINTN NewStreamBufferSize;
+ UINT32 AuthenticationStatus;
+ VOID *CompressionSource;
+ UINT32 CompressionSourceSize;
+ UINT32 UncompressedLength;
+ UINT8 CompressionType;
+ UINT16 GuidedSectionAttributes;
+
+ FRAMEWORK_SECTION_CHILD_NODE *Node;
+
+ SectionHeader = (EFI_COMMON_SECTION_HEADER *) (Stream->StreamBuffer + ChildOffset);
+
+ //
+ // Allocate a new node
+ //
+ *ChildNode = AllocateZeroPool (sizeof (FRAMEWORK_SECTION_CHILD_NODE));
+ Node = *ChildNode;
+ if (Node == NULL) {
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Now initialize it
+ //
+ Node->Signature = FRAMEWORK_SECTION_CHILD_SIGNATURE;
+ Node->Type = SectionHeader->Type;
+ if (IS_SECTION2 (SectionHeader)) {
+ Node->Size = SECTION2_SIZE (SectionHeader);
+ } else {
+ Node->Size = SECTION_SIZE (SectionHeader);
+ }
+ Node->OffsetInStream = ChildOffset;
+ Node->EncapsulatedStreamHandle = NULL_STREAM_HANDLE;
+ Node->EncapsulationGuid = NULL;
+
+ //
+ // If it's an encapsulating section, then create the new section stream also
+ //
+ switch (Node->Type) {
+ case EFI_SECTION_COMPRESSION:
+ //
+ // Get the CompressionSectionHeader
+ //
+ if (Node->Size < sizeof (EFI_COMPRESSION_SECTION)) {
+ FreePool (Node);
+ return EFI_NOT_FOUND;
+ }
+
+ CompressionHeader = (EFI_COMPRESSION_SECTION *) SectionHeader;
+
+ if (IS_SECTION2 (CompressionHeader)) {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION2));
+ CompressionSourceSize = (UINT32) (SECTION2_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION2));
+ UncompressedLength = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->UncompressedLength;
+ CompressionType = ((EFI_COMPRESSION_SECTION2 *) CompressionHeader)->CompressionType;
+ } else {
+ CompressionSource = (VOID *) ((UINT8 *) CompressionHeader + sizeof (EFI_COMPRESSION_SECTION));
+ CompressionSourceSize = (UINT32) (SECTION_SIZE (CompressionHeader) - sizeof (EFI_COMPRESSION_SECTION));
+ UncompressedLength = CompressionHeader->UncompressedLength;
+ CompressionType = CompressionHeader->CompressionType;
+ }
+
+ //
+ // Allocate space for the new stream
+ //
+ if (UncompressedLength > 0) {
+ NewStreamBufferSize = UncompressedLength;
+ NewStreamBuffer = AllocatePool (NewStreamBufferSize);
+ if (NewStreamBuffer == NULL) {
+ FreePool (Node);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ if (CompressionType == EFI_NOT_COMPRESSED) {
+ //
+ // stream is not actually compressed, just encapsulated. So just copy it.
+ //
+ CopyMem (NewStreamBuffer, CompressionSource, NewStreamBufferSize);
+ } else if (CompressionType == EFI_STANDARD_COMPRESSION) {
+ //
+ // Only support the EFI_SATNDARD_COMPRESSION algorithm.
+ //
+
+ //
+ // Decompress the stream
+ //
+ Status = gBS->LocateProtocol (&gEfiDecompressProtocolGuid, NULL, (VOID **)&Decompress);
+
+ ASSERT_EFI_ERROR (Status);
+
+ Status = Decompress->GetInfo (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ (UINT32 *)&NewStreamBufferSize,
+ &ScratchSize
+ );
+ if (EFI_ERROR (Status) || (NewStreamBufferSize != UncompressedLength)) {
+ FreePool (Node);
+ FreePool (NewStreamBuffer);
+ if (!EFI_ERROR (Status)) {
+ Status = EFI_BAD_BUFFER_SIZE;
+ }
+ return Status;
+ }
+
+ ScratchBuffer = AllocatePool (ScratchSize);
+ if (ScratchBuffer == NULL) {
+ FreePool (Node);
+ FreePool (NewStreamBuffer);
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ Status = Decompress->Decompress (
+ Decompress,
+ CompressionSource,
+ CompressionSourceSize,
+ NewStreamBuffer,
+ (UINT32)NewStreamBufferSize,
+ ScratchBuffer,
+ ScratchSize
+ );
+ FreePool (ScratchBuffer);
+ if (EFI_ERROR (Status)) {
+ FreePool (Node);
+ FreePool (NewStreamBuffer);
+ return Status;
+ }
+ }
+ } else {
+ NewStreamBuffer = NULL;
+ NewStreamBufferSize = 0;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ Stream->AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (Node);
+ FreePool (NewStreamBuffer);
+ return Status;
+ }
+ break;
+
+ case EFI_SECTION_GUID_DEFINED:
+ GuidedHeader = (EFI_GUID_DEFINED_SECTION *) SectionHeader;
+ if (IS_SECTION2 (GuidedHeader)) {
+ Node->EncapsulationGuid = &(((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->SectionDefinitionGuid);
+ GuidedSectionAttributes = ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->Attributes;
+ } else {
+ Node->EncapsulationGuid = &GuidedHeader->SectionDefinitionGuid;
+ GuidedSectionAttributes = GuidedHeader->Attributes;
+ }
+ if (VerifyGuidedSectionGuid (Node->EncapsulationGuid, &GuidedExtraction)) {
+ //
+ // NewStreamBuffer is always allocated by ExtractSection... No caller
+ // allocation here.
+ //
+ Status = GuidedExtraction->ExtractSection (
+ GuidedExtraction,
+ GuidedHeader,
+ &NewStreamBuffer,
+ &NewStreamBufferSize,
+ &AuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (*ChildNode);
+ return EFI_PROTOCOL_ERROR;
+ }
+
+ //
+ // Make sure we initialize the new stream with the correct
+ // authentication status for both aggregate and local status fields.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ //
+ // OR in the parent stream's aggregate status.
+ //
+ AuthenticationStatus |= Stream->AuthenticationStatus & EFI_AGGREGATE_AUTH_STATUS_ALL;
+ } else {
+ //
+ // since there's no authentication data contributed by the section,
+ // just inherit the full value from our immediate parent.
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+ }
+
+ Status = OpenSectionStreamEx (
+ NewStreamBufferSize,
+ NewStreamBuffer,
+ FALSE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ if (EFI_ERROR (Status)) {
+ FreePool (*ChildNode);
+ FreePool (NewStreamBuffer);
+ return Status;
+ }
+ } else {
+ //
+ // There's no GUIDed section extraction protocol available.
+ //
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_PROCESSING_REQUIRED) == EFI_GUIDED_SECTION_PROCESSING_REQUIRED) {
+ //
+ // If the section REQUIRES an extraction protocol, register for RPN
+ // when the required GUIDed extraction protocol becomes available.
+ //
+ AuthenticationStatus = 0;
+ CreateGuidedExtractionRpnEvent (Stream, Node);
+ } else {
+ //
+ // Figure out the proper authentication status
+ //
+ AuthenticationStatus = Stream->AuthenticationStatus;
+ if ((GuidedSectionAttributes & EFI_GUIDED_SECTION_AUTH_STATUS_VALID) == EFI_GUIDED_SECTION_AUTH_STATUS_VALID) {
+ //
+ // The local status of the new stream is contained in
+ // AuthenticaionStatus. This value needs to be ORed into the
+ // Aggregate bits also...
+ //
+
+ //
+ // Clear out and initialize the local status
+ //
+ AuthenticationStatus &= ~EFI_LOCAL_AUTH_STATUS_ALL;
+ AuthenticationStatus |= EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED;
+ //
+ // OR local status into aggregate status
+ //
+ AuthenticationStatus |= AuthenticationStatus >> 16;
+ }
+
+ if (IS_SECTION2 (GuidedHeader)) {
+ Status = OpenSectionStreamEx (
+ SECTION2_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
+ (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION2 *) GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ } else {
+ Status = OpenSectionStreamEx (
+ SECTION_SIZE (GuidedHeader) - ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
+ (UINT8 *) GuidedHeader + ((EFI_GUID_DEFINED_SECTION *) GuidedHeader)->DataOffset,
+ TRUE,
+ AuthenticationStatus,
+ &Node->EncapsulatedStreamHandle
+ );
+ }
+ if (EFI_ERROR (Status)) {
+ FreePool (Node);
+ return Status;
+ }
+ }
+ }
+
+ if ((AuthenticationStatus & EFI_LOCAL_AUTH_STATUS_ALL) ==
+ (EFI_LOCAL_AUTH_STATUS_IMAGE_SIGNED | EFI_LOCAL_AUTH_STATUS_NOT_TESTED)) {
+ //
+ // Need to register for RPN for when the required GUIDed extraction
+ // protocol becomes available. This will enable us to refresh the
+ // AuthenticationStatus cached in the Stream if it's ever requested
+ // again.
+ //
+ CreateGuidedExtractionRpnEvent (Stream, Node);
+ }
+
+ break;
+
+ default:
+
+ //
+ // Nothing to do if it's a leaf
+ //
+ break;
+ }
+
+ //
+ // Last, add the new child node to the stream
+ //
+ InsertTailList (&Stream->Children, &Node->Link);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Worker function Recursively searches / builds section stream database
+ looking for requested section.
+
+
+ @param SourceStream Indicates the section stream in which to do the search.
+ @param SearchType Indicates the type of section to search for.
+ @param SectionInstance Indicates which instance of section to find. This is
+ an in/out parameter to deal with recursions.
+ @param SectionDefinitionGuid Guid of section definition
+ @param FoundChild Output indicating the child node that is found.
+ @param FoundStream Output indicating which section stream the child was
+ found in. If this stream was generated as a result of
+ an encapsulation section, the streamhandle is visible
+ within the SEP driver only.
+ @param AuthenticationStatus Indicates the authentication status of the found section.
+
+ @retval EFI_SUCCESS Child node was found and returned.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_NOT_FOUND Requested child node does not exist.
+ @retval EFI_PROTOCOL_ERROR A required GUIDED section extraction protocol does not
+ exist
+
+**/
+EFI_STATUS
+FindChildNode (
+ IN FRAMEWORK_SECTION_STREAM_NODE *SourceStream,
+ IN EFI_SECTION_TYPE SearchType,
+ IN OUT UINTN *SectionInstance,
+ IN EFI_GUID *SectionDefinitionGuid,
+ OUT FRAMEWORK_SECTION_CHILD_NODE **FoundChild,
+ OUT FRAMEWORK_SECTION_STREAM_NODE **FoundStream,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ FRAMEWORK_SECTION_CHILD_NODE *CurrentChildNode;
+ FRAMEWORK_SECTION_CHILD_NODE *RecursedChildNode;
+ FRAMEWORK_SECTION_STREAM_NODE *RecursedFoundStream;
+ UINT32 NextChildOffset;
+ EFI_STATUS ErrorStatus;
+ EFI_STATUS Status;
+
+ CurrentChildNode = NULL;
+ ErrorStatus = EFI_NOT_FOUND;
+
+ if (SourceStream->StreamLength == 0) {
+ return EFI_NOT_FOUND;
+ }
+
+ if (IsListEmpty (&SourceStream->Children) &&
+ SourceStream->StreamLength >= sizeof (EFI_COMMON_SECTION_HEADER)) {
+ //
+ // This occurs when a section stream exists, but no child sections
+ // have been parsed out yet. Therefore, extract the first child and add it
+ // to the list of children so we can get started.
+ // Section stream may contain an array of zero or more bytes.
+ // So, its size should be >= the size of commen section header.
+ //
+ Status = CreateChildNode (SourceStream, 0, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ //
+ // At least one child has been parsed out of the section stream. So, walk
+ // through the sections that have already been parsed out looking for the
+ // requested section, if necessary, continue parsing section stream and
+ // adding children until either the requested section is found, or we run
+ // out of data
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetFirstNode(&SourceStream->Children));
+
+ for (;;) {
+ ASSERT (CurrentChildNode != NULL);
+ if (ChildIsType (SourceStream, CurrentChildNode, SearchType, SectionDefinitionGuid)) {
+ //
+ // The type matches, so check the instance count to see if it's the one we want
+ //
+ (*SectionInstance)--;
+ if (*SectionInstance == 0) {
+ //
+ // Got it!
+ //
+ *FoundChild = CurrentChildNode;
+ *FoundStream = SourceStream;
+ *AuthenticationStatus = SourceStream->AuthenticationStatus;
+ return EFI_SUCCESS;
+ }
+ }
+
+ if (CurrentChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If the current node is an encapsulating node, recurse into it...
+ //
+ Status = FindChildNode (
+ (FRAMEWORK_SECTION_STREAM_NODE *)CurrentChildNode->EncapsulatedStreamHandle,
+ SearchType,
+ SectionInstance,
+ SectionDefinitionGuid,
+ &RecursedChildNode,
+ &RecursedFoundStream,
+ AuthenticationStatus
+ );
+ //
+ // If the status is not EFI_SUCCESS, just save the error code and continue
+ // to find the request child node in the rest stream.
+ //
+ if (*SectionInstance == 0) {
+ ASSERT_EFI_ERROR (Status);
+ *FoundChild = RecursedChildNode;
+ *FoundStream = RecursedFoundStream;
+ return EFI_SUCCESS;
+ } else {
+ ErrorStatus = Status;
+ }
+ } else if ((CurrentChildNode->Type == EFI_SECTION_GUID_DEFINED) && (SearchType != EFI_SECTION_GUID_DEFINED)) {
+ //
+ // When Node Type is GUIDED section, but Node has no encapsulated data, Node data should not be parsed
+ // because a required GUIDED section extraction protocol does not exist.
+ // If SearchType is not GUIDED section, EFI_PROTOCOL_ERROR should return.
+ //
+ ErrorStatus = EFI_PROTOCOL_ERROR;
+ }
+
+ if (!IsNodeAtEnd (&SourceStream->Children, &CurrentChildNode->Link)) {
+ //
+ // We haven't found the child node we're interested in yet, but there's
+ // still more nodes that have already been parsed so get the next one
+ // and continue searching..
+ //
+ CurrentChildNode = CHILD_SECTION_NODE_FROM_LINK (GetNextNode (&SourceStream->Children, &CurrentChildNode->Link));
+ } else {
+ //
+ // We've exhausted children that have already been parsed, so see if
+ // there's any more data and continue parsing out more children if there
+ // is.
+ //
+ NextChildOffset = CurrentChildNode->OffsetInStream + CurrentChildNode->Size;
+ //
+ // Round up to 4 byte boundary
+ //
+ NextChildOffset += 3;
+ NextChildOffset &= ~(UINTN)3;
+ if (NextChildOffset <= SourceStream->StreamLength - sizeof (EFI_COMMON_SECTION_HEADER)) {
+ //
+ // There's an unparsed child remaining in the stream, so create a new child node
+ //
+ Status = CreateChildNode (SourceStream, NextChildOffset, &CurrentChildNode);
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ } else {
+ ASSERT (EFI_ERROR (ErrorStatus));
+ return ErrorStatus;
+ }
+ }
+ }
+}
+
+/**
+ Worker function. Search stream database for requested stream handle.
+
+ @param SearchHandle Indicates which stream to look for.
+ @param FoundStream Output pointer to the found stream.
+
+ @retval EFI_SUCCESS StreamHandle was found and *FoundStream contains
+ the stream node.
+ @retval EFI_NOT_FOUND SearchHandle was not found in the stream database.
+
+**/
+EFI_STATUS
+FindStreamNode (
+ IN UINTN SearchHandle,
+ OUT FRAMEWORK_SECTION_STREAM_NODE **FoundStream
+ )
+{
+ FRAMEWORK_SECTION_STREAM_NODE *StreamNode;
+
+ if (!IsListEmpty (&mStreamRoot)) {
+ StreamNode = STREAM_NODE_FROM_LINK (GetFirstNode (&mStreamRoot));
+ for (;;) {
+ if (StreamNode->StreamHandle == SearchHandle) {
+ *FoundStream = StreamNode;
+ return EFI_SUCCESS;
+ } else if (IsNodeAtEnd (&mStreamRoot, &StreamNode->Link)) {
+ break;
+ } else {
+ StreamNode = STREAM_NODE_FROM_LINK (GetNextNode (&mStreamRoot, &StreamNode->Link));
+ }
+ }
+ }
+
+ return EFI_NOT_FOUND;
+}
+
+/**
+ SEP member function. Retrieves requested section from section stream.
+
+ @param This Pointer to SEP instance.
+ @param SectionStreamHandle The section stream from which to extract the requested
+ section.
+ @param SectionType A pointer to the type of section to search for.
+ @param SectionDefinitionGuid If the section type is EFI_SECTION_GUID_DEFINED, then
+ SectionDefinitionGuid indicates which of these types
+ of sections to search for.
+ @param SectionInstance Indicates which instance of the requested section to
+ return.
+ @param Buffer Double indirection to buffer. If *Buffer is non-null on
+ input, then the buffer is caller allocated. If
+ *Buffer is NULL, then the buffer is callee allocated.
+ In either case, the requried buffer size is returned
+ in *BufferSize.
+ @param BufferSize On input, indicates the size of *Buffer if *Buffer is
+ non-null on input. On output, indicates the required
+ size (allocated size if callee allocated) of *Buffer.
+ @param AuthenticationStatus Indicates the authentication status of the retrieved
+ section.
+
+
+ @retval EFI_SUCCESS Section was retrieved successfully
+ @retval EFI_PROTOCOL_ERROR A GUID defined section was encountered in the section
+ stream with its EFI_GUIDED_SECTION_PROCESSING_REQUIRED
+ bit set, but there was no corresponding GUIDed Section
+ Extraction Protocol in the handle database. *Buffer is
+ unmodified.
+ @retval EFI_NOT_FOUND An error was encountered when parsing the SectionStream.
+ This indicates the SectionStream is not correctly
+ formatted.
+ @retval EFI_NOT_FOUND The requested section does not exist.
+ @retval EFI_OUT_OF_RESOURCES The system has insufficient resources to process the
+ request.
+ @retval EFI_INVALID_PARAMETER The SectionStreamHandle does not exist.
+ @retval EFI_WARN_TOO_SMALL The size of the caller allocated input buffer is
+ insufficient to contain the requested section. The
+ input buffer is filled and contents are section contents
+ are truncated.
+
+**/
+EFI_STATUS
+EFIAPI
+GetSection (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN SectionStreamHandle,
+ IN EFI_SECTION_TYPE *SectionType,
+ IN EFI_GUID *SectionDefinitionGuid,
+ IN UINTN SectionInstance,
+ IN VOID **Buffer,
+ IN OUT UINTN *BufferSize,
+ OUT UINT32 *AuthenticationStatus
+ )
+{
+ FRAMEWORK_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ FRAMEWORK_SECTION_CHILD_NODE *ChildNode;
+ FRAMEWORK_SECTION_STREAM_NODE *ChildStreamNode;
+ UINTN CopySize;
+ UINT32 ExtractedAuthenticationStatus;
+ UINTN Instance;
+ UINT8 *CopyBuffer;
+ UINTN SectionSize;
+ EFI_COMMON_SECTION_HEADER *Section;
+
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+ Instance = SectionInstance + 1;
+ ChildStreamNode = NULL;
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (SectionStreamHandle, &StreamNode);
+ if (EFI_ERROR (Status)) {
+ Status = EFI_INVALID_PARAMETER;
+ goto GetSection_Done;
+ }
+
+ //
+ // Found the stream, now locate and return the appropriate section
+ //
+ if (SectionType == NULL) {
+ //
+ // SectionType == NULL means return the WHOLE section stream...
+ //
+ CopySize = StreamNode->StreamLength;
+ CopyBuffer = StreamNode->StreamBuffer;
+ *AuthenticationStatus = StreamNode->AuthenticationStatus;
+ } else {
+ //
+ // There's a requested section type, so go find it and return it...
+ //
+ Status = FindChildNode (
+ StreamNode,
+ *SectionType,
+ &Instance,
+ SectionDefinitionGuid,
+ &ChildNode,
+ &ChildStreamNode,
+ &ExtractedAuthenticationStatus
+ );
+ if (EFI_ERROR (Status)) {
+ goto GetSection_Done;
+ }
+ ASSERT (ChildNode != NULL);
+ ASSERT (ChildStreamNode != NULL);
+ Section = (EFI_COMMON_SECTION_HEADER *) (ChildStreamNode->StreamBuffer + ChildNode->OffsetInStream);
+
+ if (IS_SECTION2 (Section)) {
+ CopySize = SECTION2_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER2);
+ CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER2);
+ } else {
+ CopySize = SECTION_SIZE (Section) - sizeof (EFI_COMMON_SECTION_HEADER);
+ CopyBuffer = (UINT8 *) Section + sizeof (EFI_COMMON_SECTION_HEADER);
+ }
+ *AuthenticationStatus = ExtractedAuthenticationStatus;
+ }
+
+ SectionSize = CopySize;
+ if (*Buffer != NULL) {
+ //
+ // Caller allocated buffer. Fill to size and return required size...
+ //
+ if (*BufferSize < CopySize) {
+ Status = EFI_WARN_BUFFER_TOO_SMALL;
+ CopySize = *BufferSize;
+ }
+ } else {
+ //
+ // Callee allocated buffer. Allocate buffer and return size.
+ //
+ *Buffer = AllocatePool (CopySize);
+ if (*Buffer == NULL) {
+ Status = EFI_OUT_OF_RESOURCES;
+ goto GetSection_Done;
+ }
+ }
+ CopyMem (*Buffer, CopyBuffer, CopySize);
+ *BufferSize = SectionSize;
+
+GetSection_Done:
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
+
+/**
+ Worker function. Destructor for child nodes.
+
+ @param ChildNode Indicates the node to destroy
+
+**/
+VOID
+FreeChildNode (
+ IN FRAMEWORK_SECTION_CHILD_NODE *ChildNode
+ )
+{
+ ASSERT (ChildNode->Signature == FRAMEWORK_SECTION_CHILD_SIGNATURE);
+ //
+ // Remove the child from it's list
+ //
+ RemoveEntryList (&ChildNode->Link);
+
+ if (ChildNode->EncapsulatedStreamHandle != NULL_STREAM_HANDLE) {
+ //
+ // If it's an encapsulating section, we close the resulting section stream.
+ // CloseSectionStream will free all memory associated with the stream.
+ //
+ CloseSectionStream (&mSectionExtraction, ChildNode->EncapsulatedStreamHandle);
+ }
+
+ if (ChildNode->Event != NULL) {
+ gBS->CloseEvent (ChildNode->Event);
+ }
+
+ //
+ // Last, free the child node itself
+ //
+ FreePool (ChildNode);
+}
+
+/**
+ SEP member function. Deletes an existing section stream
+
+ @param This Indicates the calling context.
+ @param StreamHandleToClose Indicates the stream to close
+
+ @retval EFI_SUCCESS Section stream was closed successfully.
+ @retval EFI_OUT_OF_RESOURCES Memory allocation failed.
+ @retval EFI_INVALID_PARAMETER Section stream does not end concident with end of
+ last section.
+
+**/
+EFI_STATUS
+EFIAPI
+CloseSectionStream (
+ IN EFI_SECTION_EXTRACTION_PROTOCOL *This,
+ IN UINTN StreamHandleToClose
+ )
+{
+ FRAMEWORK_SECTION_STREAM_NODE *StreamNode;
+ EFI_TPL OldTpl;
+ EFI_STATUS Status;
+ LIST_ENTRY *Link;
+ FRAMEWORK_SECTION_CHILD_NODE *ChildNode;
+
+ OldTpl = gBS->RaiseTPL (TPL_NOTIFY);
+
+ //
+ // Locate target stream
+ //
+ Status = FindStreamNode (StreamHandleToClose, &StreamNode);
+ if (!EFI_ERROR (Status)) {
+ //
+ // Found the stream, so close it
+ //
+ RemoveEntryList (&StreamNode->Link);
+ while (!IsListEmpty (&StreamNode->Children)) {
+ Link = GetFirstNode (&StreamNode->Children);
+ ChildNode = CHILD_SECTION_NODE_FROM_LINK (Link);
+ FreeChildNode (ChildNode);
+ }
+ FreePool (StreamNode->StreamBuffer);
+ FreePool (StreamNode);
+ Status = EFI_SUCCESS;
+ } else {
+ Status = EFI_INVALID_PARAMETER;
+ }
+
+ gBS->RestoreTPL (OldTpl);
+ return Status;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
new file mode 100644
index 0000000000..ab0bd63076
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.inf
@@ -0,0 +1,57 @@
+## @file
+# Section Extraction Dxe Driver produces framework section extract protocol.
+#
+# The section is implemented as a linked list of section streams,
+# where each stream contains a linked list of children, which may be leaves or
+# encapsulations. Encapsulation section will further generate new section stream entries.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+#
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = SectionExtractionDxe
+ MODULE_UNI_FILE = SectionExtractionDxe.uni
+ FILE_GUID = 801ADCA0-815E-46a4-84F7-657F53621A57
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = SectionExtractionEntryPoint
+
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ SectionExtraction.c
+
+[LibraryClasses]
+ UefiBootServicesTableLib
+ MemoryAllocationLib
+ DebugLib
+ BaseLib
+ BaseMemoryLib
+ UefiDriverEntryPoint
+ UefiLib
+
+[Packages]
+ MdePkg/MdePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+
+[Protocols]
+ gEfiSectionExtractionProtocolGuid ## PRODUCES
+ gEfiDecompressProtocolGuid ## SOMETIMES_CONSUMES
+
+[Depex]
+ gEfiDecompressProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ SectionExtractionDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni
new file mode 100644
index 0000000000..98a01d2f90
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni
new file mode 100644
index 0000000000..84db1b982f
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/SectionExtractionDxe/SectionExtractionDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DataHubStatusCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DataHubStatusCodeWorker.c
new file mode 100644
index 0000000000..5b42395dbd
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DataHubStatusCodeWorker.c
@@ -0,0 +1,376 @@
+/** @file
+ Data Hub status code worker.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DatahubStatusCodeHandlerDxe.h"
+
+//
+// Initialize FIFO to cache records.
+//
+LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
+LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
+UINT32 mLogDataHubStatus = 0;
+EFI_EVENT mLogDataHubEvent;
+//
+// Cache data hub protocol.
+//
+EFI_DATA_HUB_PROTOCOL *mDataHubProtocol = NULL;
+
+
+/**
+ Retrieve one record of from free record buffer. This record is removed from
+ free record buffer.
+
+ This function retrieves one record from free record buffer.
+ If the pool has been exhausted, then new memory would be allocated for it.
+
+ @return Pointer to the free record.
+ NULL means failure to allocate new memeory for free record buffer.
+
+**/
+DATA_HUB_STATUS_CODE_DATA_RECORD *
+AcquireRecordBuffer (
+ VOID
+ )
+{
+ DATAHUB_STATUSCODE_RECORD *Record;
+ EFI_TPL CurrentTpl;
+ LIST_ENTRY *Node;
+ UINT32 Index;
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (!IsListEmpty (&mRecordsBuffer)) {
+ //
+ // Strip one entry from free record buffer.
+ //
+ Node = GetFirstNode (&mRecordsBuffer);
+ RemoveEntryList (Node);
+
+ Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
+ } else {
+ if (CurrentTpl > TPL_NOTIFY) {
+ //
+ // Memory management should work at <=TPL_NOTIFY
+ //
+ gBS->RestoreTPL (CurrentTpl);
+ return NULL;
+ }
+
+ //
+ // If free record buffer is exhausted, then allocate 16 new records for it.
+ //
+ gBS->RestoreTPL (CurrentTpl);
+ Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
+ if (Record == NULL) {
+ return NULL;
+ }
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ //
+ // Here we only insert 15 new records to the free record buffer, for the first record
+ // will be returned immediately.
+ //
+ for (Index = 1; Index < 16; Index++) {
+ InsertTailList (&mRecordsBuffer, &Record[Index].Node);
+ }
+ }
+
+ Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;
+ InsertTailList (&mRecordsFifo, &Record->Node);
+
+ gBS->RestoreTPL (CurrentTpl);
+
+ return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
+}
+
+
+/**
+ Retrieve one record from Records FIFO. The record would be removed from FIFO.
+
+ @return Point to record, which is ready to be logged.
+ NULL means the FIFO of record is empty.
+
+**/
+DATA_HUB_STATUS_CODE_DATA_RECORD *
+RetrieveRecord (
+ VOID
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData;
+ DATAHUB_STATUSCODE_RECORD *Record;
+ LIST_ENTRY *Node;
+ EFI_TPL CurrentTpl;
+
+ RecordData = NULL;
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (!IsListEmpty (&mRecordsFifo)) {
+ Node = GetFirstNode (&mRecordsFifo);
+ Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);
+ ASSERT (Record != NULL);
+
+ RemoveEntryList (&Record->Node);
+ RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
+ }
+
+ gBS->RestoreTPL (CurrentTpl);
+
+ return RecordData;
+}
+
+/**
+ Release given record and return it to free record buffer.
+
+ @param RecordData Pointer to the record to release.
+
+**/
+VOID
+ReleaseRecord (
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData
+ )
+{
+ DATAHUB_STATUSCODE_RECORD *Record;
+ EFI_TPL CurrentTpl;
+
+ Record = CR (RecordData, DATAHUB_STATUSCODE_RECORD, Data[0], DATAHUB_STATUS_CODE_SIGNATURE);
+ ASSERT (Record != NULL);
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ InsertTailList (&mRecordsBuffer, &Record->Node);
+ Record->Signature = 0;
+
+ gBS->RestoreTPL (CurrentTpl);
+}
+
+/**
+ Report status code into DataHub.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_DEVICE_ERROR Function is reentered.
+ @retval EFI_DEVICE_ERROR Function is called at runtime.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+DataHubStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
+ UINT32 ErrorLevel;
+ BASE_LIST Marker;
+ CHAR8 *Format;
+ UINTN CharCount;
+
+ //
+ // Use atom operation to avoid the reentant of report.
+ // If current status is not zero, then the function is reentrancy.
+ //
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 0) == 1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ Record = AcquireRecordBuffer ();
+ if (Record == NULL) {
+ //
+ // There are no empty record buffer in private buffers
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Construct Data Hub Extended Data
+ //
+ Record->CodeType = CodeType;
+ Record->Value = Value;
+ Record->Instance = Instance;
+
+ if (CallerId != NULL) {
+ CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
+ }
+
+ if (Data != NULL) {
+ if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ CharCount = UnicodeBSPrintAsciiFormat (
+ (CHAR16 *) (Record + 1),
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ Format,
+ Marker
+ );
+ //
+ // Change record data type to DebugType.
+ //
+ CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid);
+ Record->Data.HeaderSize = Data->HeaderSize;
+ Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));
+ } else {
+ //
+ // Copy status code data header
+ //
+ CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
+
+ if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {
+ Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;
+ }
+ CopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
+ }
+ }
+
+ gBS->SignalEvent (mLogDataHubEvent);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The Event handler which will be notified to log data in Data Hub.
+
+ @param Event Instance of the EFI_EVENT to signal whenever data is
+ available to be logged in the system.
+ @param Context Context of the event.
+
+**/
+VOID
+EFIAPI
+LogDataHubEventCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
+ UINT32 Size;
+ UINT64 DataRecordClass;
+
+ //
+ // Use atom operation to avoid the reentant of report.
+ // If current status is not zero, then the function is reentrancy.
+ //
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 1) == 1) {
+ return;
+ }
+
+ //
+ // Log DataRecord in Data Hub.
+ // Journal records fifo to find all record entry.
+ //
+ while (TRUE) {
+ //
+ // Retrieve record from record FIFO until no more record can be retrieved.
+ //
+ Record = RetrieveRecord ();
+ if (Record == NULL) {
+ break;
+ }
+ //
+ // Add in the size of the header we added.
+ //
+ Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
+
+ if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
+ } else {
+ //
+ // Should never get here.
+ //
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
+ EFI_DATA_RECORD_CLASS_ERROR |
+ EFI_DATA_RECORD_CLASS_DATA |
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ }
+
+ //
+ // Log DataRecord in Data Hub
+ //
+ mDataHubProtocol->LogData (
+ mDataHubProtocol,
+ &gEfiDataHubStatusCodeRecordGuid,
+ &gEfiStatusCodeRuntimeProtocolGuid,
+ DataRecordClass,
+ Record,
+ Size
+ );
+
+ ReleaseRecord (Record);
+ }
+
+ //
+ // Restore the nest status of report
+ //
+ InterlockedCompareExchange32 (&mLogDataHubStatus, 1, 0);
+}
+
+
+/**
+ Locate Data Hub Protocol and create event for logging data
+ as initialization for data hub status code worker.
+
+ @retval EFI_SUCCESS Initialization is successful.
+
+**/
+EFI_STATUS
+DataHubStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ (VOID **) &mDataHubProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mDataHubProtocol = NULL;
+ return Status;
+ }
+
+ //
+ // Create a Notify Event to log data in Data Hub
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ LogDataHubEventCallBack,
+ NULL,
+ &mLogDataHubEvent
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.c
new file mode 100644
index 0000000000..ee7bdd36af
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.c
@@ -0,0 +1,88 @@
+/** @file
+ Status Code Handler Driver which produces datahub handler and hook it
+ onto the DXE status code router.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "DatahubStatusCodeHandlerDxe.h"
+
+EFI_EVENT mExitBootServicesEvent = NULL;
+EFI_RSC_HANDLER_PROTOCOL *mRscHandlerProtocol = NULL;
+
+/**
+ Unregister status code callback functions only available at boot time from
+ report status code router when exiting boot services.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context, which is
+ always zero in current implementation.
+
+**/
+VOID
+EFIAPI
+UnregisterBootTimeHandlers (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ mRscHandlerProtocol->Unregister (DataHubStatusCodeReportWorker);
+}
+
+/**
+ Entry point of DXE Status Code Driver.
+
+ This function is the entry point of this DXE Status Code Driver.
+ It initializes registers status code handlers, and registers event for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+DatahubStatusCodeHandlerDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
+ Status = gBS->LocateProtocol (
+ &gEfiRscHandlerProtocolGuid,
+ NULL,
+ (VOID **) &mRscHandlerProtocol
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ //
+ // Dispatch initialization request to supported devices
+ //
+ DataHubStatusCodeInitializeWorker ();
+
+ mRscHandlerProtocol->Register (DataHubStatusCodeReportWorker, TPL_HIGH_LEVEL);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ UnregisterBootTimeHandlers,
+ NULL,
+ &gEfiEventExitBootServicesGuid,
+ &mExitBootServicesEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ return EFI_SUCCESS;
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.h b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.h
new file mode 100644
index 0000000000..8ee0b55fa8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.h
@@ -0,0 +1,91 @@
+/** @file
+ Internal include file for Datahub Status Code Handler Driver.
+
+ Copyright (c) 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __DATAHUB_STATUS_CODE_HANDLER_DXE_H__
+#define __DATAHUB_STATUS_CODE_HANDLER_DXE_H__
+
+#include <Protocol/ReportStatusCodeHandler.h>
+#include <Protocol/DataHub.h>
+#include <Protocol/StatusCode.h>
+
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/DataHubStatusCodeRecord.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/MemoryAllocationLib.h>
+
+//
+// Data hub worker definition
+//
+#define DATAHUB_STATUS_CODE_SIGNATURE SIGNATURE_32 ('B', 'D', 'H', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Node;
+ UINT8 Data[sizeof(DATA_HUB_STATUS_CODE_DATA_RECORD) + EFI_STATUS_CODE_DATA_MAX_SIZE];
+} DATAHUB_STATUSCODE_RECORD;
+
+/**
+ Report status code into DataHub.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_DEVICE_ERROR Function is reentered.
+ @retval EFI_DEVICE_ERROR Function is called at runtime.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.
+
+**/
+EFI_STATUS
+EFIAPI
+DataHubStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+/**
+ Locate Data Hub Protocol and create event for logging data
+ as initialization for data hub status code worker.
+
+ @retval EFI_SUCCESS Initialization is successful.
+
+**/
+EFI_STATUS
+DataHubStatusCodeInitializeWorker (
+ VOID
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf
new file mode 100644
index 0000000000..1a576772a3
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.inf
@@ -0,0 +1,72 @@
+## @file
+# Status Code Handler Driver which produces datahub handler.
+#
+# Copyright (c) 2011 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = DatahubStatusCodeHandlerDxe
+ MODULE_UNI_FILE = DatahubStatusCodeHandlerDxe.uni
+ FILE_GUID = 863D214F-0920-437B-8CAD-88EA83A24E97
+ MODULE_TYPE = DXE_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = DatahubStatusCodeHandlerDxeEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ DatahubStatusCodeHandlerDxe.h
+ DatahubStatusCodeHandlerDxe.c
+ DataHubStatusCodeWorker.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ BaseLib
+ MemoryAllocationLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ PcdLib
+ PrintLib
+ ReportStatusCodeLib
+ DebugLib
+ SynchronizationLib
+ BaseMemoryLib
+
+[Guids]
+ gEfiEventExitBootServicesGuid ## CONSUMES ## Event
+ gEfiDataHubStatusCodeRecordGuid ## PRODUCES ## UNDEFINED # DataRecord Guid
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Record data type
+
+[Protocols]
+ gEfiRscHandlerProtocolGuid ## CONSUMES
+ gEfiDataHubProtocolGuid ## CONSUMES
+ gEfiStatusCodeRuntimeProtocolGuid ## UNDEFINED
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseDataHub ## CONSUMES
+
+[Depex]
+ gEfiRscHandlerProtocolGuid AND
+ gEfiDataHubProtocolGuid
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ DatahubStatusCodeHandlerDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.uni
new file mode 100644
index 0000000000..57f0640fa4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxeExtra.uni
new file mode 100644
index 0000000000..0e648005ec
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/DatahubStatusCodeHandlerDxe/DatahubStatusCodeHandlerDxeExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/MemoryStausCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/MemoryStausCodeWorker.c
new file mode 100644
index 0000000000..f0b36f23a2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/MemoryStausCodeWorker.c
@@ -0,0 +1,118 @@
+/** @file
+ PEI memory status code worker.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodePei.h"
+
+/**
+ Create the first memory status code GUID'ed HOB as initialization for memory status code worker.
+
+ @retval EFI_SUCCESS The GUID'ed HOB is created successfully.
+
+**/
+EFI_STATUS
+MemoryStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ //
+ // Create memory status code GUID'ed HOB.
+ //
+ MEMORY_STATUSCODE_PACKET_HEADER *PacketHeader;
+
+ //
+ // Build GUID'ed HOB with PCD defined size.
+ //
+ PacketHeader = BuildGuidHob (
+ &gMemoryStatusCodeRecordGuid,
+ PcdGet16 (PcdStatusCodeMemorySize) * 1024 + sizeof (MEMORY_STATUSCODE_PACKET_HEADER)
+ );
+ ASSERT (PacketHeader != NULL);
+
+ PacketHeader->MaxRecordsNumber = (PcdGet16 (PcdStatusCodeMemorySize) * 1024) / sizeof (MEMORY_STATUSCODE_RECORD);
+ PacketHeader->PacketIndex = 0;
+ PacketHeader->RecordIndex = 0;
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Report status code into GUID'ed HOB.
+
+ This function reports status code into GUID'ed HOB. If not all packets are full, then
+ write status code into available entry. Otherwise, create a new packet for it.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+
+ @retval EFI_SUCCESS The function always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+MemoryStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance
+ )
+{
+
+ EFI_PEI_HOB_POINTERS Hob;
+ MEMORY_STATUSCODE_PACKET_HEADER *PacketHeader;
+ MEMORY_STATUSCODE_RECORD *Record;
+
+ //
+ // Find GUID'ed HOBs to locate current record buffer.
+ //
+ Hob.Raw = GetFirstGuidHob (&gMemoryStatusCodeRecordGuid);
+ ASSERT (Hob.Raw != NULL);
+
+ PacketHeader = (MEMORY_STATUSCODE_PACKET_HEADER *) GET_GUID_HOB_DATA (Hob.Guid);
+ Record = (MEMORY_STATUSCODE_RECORD *) (PacketHeader + 1);
+ Record = &Record[PacketHeader->RecordIndex++];
+
+ //
+ // Save status code.
+ //
+ Record->CodeType = CodeType;
+ Record->Instance = Instance;
+ Record->Value = Value;
+
+ //
+ // If record index equals to max record number, then wrap around record index to zero.
+ //
+ // The reader of status code should compare the number of records with max records number,
+ // If it is equal to or larger than the max number, then the wrap-around had happened,
+ // so the first record is pointed by record index.
+ // If it is less then max number, index of the first record is zero.
+ //
+ if (PacketHeader->RecordIndex == PacketHeader->MaxRecordsNumber) {
+ //
+ // Wrap around record index.
+ //
+ PacketHeader->RecordIndex = 0;
+ PacketHeader->PacketIndex ++;
+ }
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/SerialStatusCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/SerialStatusCodeWorker.c
new file mode 100644
index 0000000000..d62cb8f8c8
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/SerialStatusCodeWorker.c
@@ -0,0 +1,162 @@
+/** @file
+ Serial I/O status code reporting worker.
+
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+**/
+
+#include "StatusCodePei.h"
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code reported to serial I/O successfully.
+
+**/
+EFI_STATUS
+SerialStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ CHAR8 *Filename;
+ CHAR8 *Description;
+ CHAR8 *Format;
+ CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
+ UINT32 ErrorLevel;
+ UINT32 LineNumber;
+ UINTN CharCount;
+ BASE_LIST Marker;
+
+ Buffer[0] = '\0';
+
+ if (Data != NULL &&
+ ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
+ //
+ // Print ASSERT() information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "\n\rPEI_ASSERT!: %a (%d): %a\n\r",
+ Filename,
+ LineNumber,
+ Description
+ );
+ } else if (Data != NULL &&
+ ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ //
+ // Print DEBUG() information into output buffer.
+ //
+ CharCount = AsciiBSPrint (
+ Buffer,
+ sizeof (Buffer),
+ Format,
+ Marker
+ );
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ //
+ // Print ERROR information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "ERROR: C%08x:V%08x I%x",
+ CodeType,
+ Value,
+ Instance
+ );
+
+ if (CallerId != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ " %g",
+ CallerId
+ );
+ }
+
+ if (Data != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ " %x",
+ Data
+ );
+ }
+
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ "\n\r"
+ );
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ //
+ // Print PROGRESS information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "PROGRESS CODE: V%08x I%x\n\r",
+ Value,
+ Instance
+ );
+ } else if (Data != NULL &&
+ CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeStringGuid) &&
+ ((EFI_STATUS_CODE_STRING_DATA *) Data)->StringType == EfiStringAscii) {
+ //
+ // EFI_STATUS_CODE_STRING_DATA
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "%a\n\r",
+ ((EFI_STATUS_CODE_STRING_DATA *) Data)->String.Ascii
+ );
+ } else {
+ //
+ // Code type is not defined.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "Undefined: C%08x:V%08x I%x\n\r",
+ CodeType,
+ Value,
+ Instance
+ );
+ }
+
+ //
+ // Call SerialPort Lib function to do print.
+ //
+ SerialPortWrite ((UINT8 *) Buffer, CharCount);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.c
new file mode 100644
index 0000000000..5b17df3862
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.c
@@ -0,0 +1,146 @@
+/** @file
+ Status code PEIM which produces Status Code PPI.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodePei.h"
+
+EFI_PEI_PROGRESS_CODE_PPI mStatusCodePpi = {
+ ReportDispatcher
+ };
+
+EFI_PEI_PPI_DESCRIPTOR mStatusCodePpiDescriptor = {
+ EFI_PEI_PPI_DESCRIPTOR_PPI | EFI_PEI_PPI_DESCRIPTOR_TERMINATE_LIST,
+ &gEfiPeiStatusCodePpiGuid,
+ &mStatusCodePpi
+ };
+
+/**
+ Publishes an interface that allows PEIMs to report status codes.
+
+ This function implements EFI_PEI_PROGRESS_CODE_PPI.ReportStatusCode().
+ It publishes an interface that allows PEIMs to report status codes.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportDispatcher (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ SerialStatusCodeReportWorker (
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ MemoryStatusCodeReportWorker (
+ CodeType,
+ Value,
+ Instance
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
+ //
+ // Call OEM hook status code library API to report status code to OEM device
+ //
+ OemHookStatusCodeReport (
+ CodeType,
+ Value,
+ Instance,
+ (EFI_GUID *)CallerId,
+ (EFI_STATUS_CODE_DATA *)Data
+ );
+ }
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Entry point of Status Code PEIM.
+
+ This function is the entry point of this Status Code PEIM.
+ It initializes supported status code devices according to PCD settings,
+ and installs Status Code PPI.
+
+ @param FileHandle Handle of the file being invoked.
+ @param PeiServices Describes the list of possible PEI Services.
+
+ @retval EFI_SUCESS The entry point of DXE IPL PEIM executes successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+PeiStatusCodeDriverEntry (
+ IN EFI_PEI_FILE_HANDLE FileHandle,
+ IN CONST EFI_PEI_SERVICES **PeiServices
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Dispatch initialization request to sub-statuscode-devices.
+ // If enable UseSerial, then initialize serial port.
+ // if enable UseMemory, then initialize memory status code worker.
+ // if enable UseOEM, then initialize Oem status code.
+ //
+ if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ Status = SerialPortInitialize();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ Status = MemoryStatusCodeInitializeWorker ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
+ Status = OemHookStatusCodeInitialize ();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Install Status Code PPI.
+ // It serves the PEI Service ReportStatusCode.
+ //
+ Status = PeiServicesInstallPpi (&mStatusCodePpiDescriptor);
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.h b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.h
new file mode 100644
index 0000000000..75078d0ef4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.h
@@ -0,0 +1,147 @@
+/** @file
+ Internal include file for Status Code PEIM.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __PEI_STATUS_CODE_H__
+#define __PEI_STATUS_CODE_H__
+
+#include <FrameworkPei.h>
+
+#include <Guid/MemoryStatusCodeRecord.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Ppi/StatusCode.h>
+
+#include <Library/BaseLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/PrintLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/HobLib.h>
+#include <Library/PcdLib.h>
+#include <Library/PeiServicesLib.h>
+#include <Library/OemHookStatusCodeLib.h>
+#include <Library/PeimEntryPoint.h>
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code reported to serial I/O successfully.
+
+**/
+EFI_STATUS
+SerialStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+
+/**
+ Create the first memory status code GUID'ed HOB as initialization for memory status code worker.
+
+ @retval EFI_SUCCESS The GUID'ed HOB is created successfully.
+
+**/
+EFI_STATUS
+MemoryStatusCodeInitializeWorker (
+ VOID
+ );
+
+/**
+ Report status code into GUID'ed HOB.
+
+ This function reports status code into GUID'ed HOB. If not all packets are full, then
+ write status code into available entry. Otherwise, create a new packet for it.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+
+ @retval EFI_SUCCESS The function always return EFI_SUCCESS.
+
+**/
+EFI_STATUS
+MemoryStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance
+ );
+
+/**
+ Publishes an interface that allows PEIMs to report status codes.
+
+ This function implements EFI_PEI_PROGRESS_CODE_PPI.ReportStatusCode().
+ It publishes an interface that allows PEIMs to report status codes.
+
+ @param PeiServices An indirect pointer to the EFI_PEI_SERVICES table published by the PEI Foundation.
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or
+ software entity. This includes information about the class and
+ subclass that is used to classify the entity as well as an operation.
+ For progress codes, the operation is the current activity.
+ For error codes, it is the exception.For debug codes,it is not defined at this time.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. A system may contain multiple entities that match a class/subclass
+ pairing. The instance differentiates between them. An instance of 0 indicates
+ that instance information is unavailable, not meaningful, or not relevant.
+ Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportDispatcher (
+ IN CONST EFI_PEI_SERVICES **PeiServices,
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN CONST EFI_GUID *CallerId OPTIONAL,
+ IN CONST EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+#endif
+
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.inf b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.inf
new file mode 100644
index 0000000000..04cef4a2f4
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.inf
@@ -0,0 +1,78 @@
+## @file
+# Status code PEIM which produces Status Code PPI.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StatusCodePei
+ MODULE_UNI_FILE = StatusCodePei.uni
+ FILE_GUID = 1EC0F53A-FDE0-4576-8F25-7A1A410F58EB
+ MODULE_TYPE = PEIM
+ VERSION_STRING = 1.0
+ ENTRY_POINT = PeiStatusCodeDriverEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 IPF EBC
+#
+
+[Sources]
+ StatusCodePei.c
+ StatusCodePei.h
+ MemoryStausCodeWorker.c
+ SerialStatusCodeWorker.c
+
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ PeimEntryPoint
+ OemHookStatusCodeLib
+ PeiServicesLib
+ PcdLib
+ HobLib
+ SerialPortLib
+ ReportStatusCodeLib
+ PrintLib
+ DebugLib
+ BaseLib
+
+
+[Guids]
+ gMemoryStatusCodeRecordGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiStatusCodeDataTypeStringGuid ## SOMETIMES_CONSUMES ## UNDEFINED # String Data Type
+
+[Ppis]
+ gEfiPeiStatusCodePpiGuid ## PRODUCES
+
+
+[FeaturePcd]
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseOEM ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize|1|gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+
+[UserExtensions.TianoCore."ExtraFiles"]
+ StatusCodePeiExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.uni
new file mode 100644
index 0000000000..1e0b9edd0d
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePei.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePeiExtra.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePeiExtra.uni
new file mode 100644
index 0000000000..6385b4190e
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/Pei/StatusCodePeiExtra.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/DataHubStatusCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/DataHubStatusCodeWorker.c
new file mode 100644
index 0000000000..ffee2f9c2a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/DataHubStatusCodeWorker.c
@@ -0,0 +1,390 @@
+/** @file
+ Data Hub status code worker.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodeRuntimeDxe.h"
+
+//
+// Initialize FIFO to cache records.
+//
+LIST_ENTRY mRecordsFifo = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsFifo);
+LIST_ENTRY mRecordsBuffer = INITIALIZE_LIST_HEAD_VARIABLE (mRecordsBuffer);
+UINT32 mLogDataHubStatus = 0;
+EFI_EVENT mLogDataHubEvent;
+//
+// Cache data hub protocol.
+//
+EFI_DATA_HUB_PROTOCOL *mDataHubProtocol = NULL;
+
+
+/**
+ Retrieve one record of from free record buffer. This record is removed from
+ free record buffer.
+
+ This function retrieves one record from free record buffer.
+ If the pool has been exhausted, then new memory would be allocated for it.
+
+ @return Pointer to the free record.
+ NULL means failure to allocate new memeory for free record buffer.
+
+**/
+DATA_HUB_STATUS_CODE_DATA_RECORD *
+AcquireRecordBuffer (
+ VOID
+ )
+{
+ DATAHUB_STATUSCODE_RECORD *Record;
+ EFI_TPL CurrentTpl;
+ LIST_ENTRY *Node;
+ UINT32 Index;
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (!IsListEmpty (&mRecordsBuffer)) {
+ //
+ // Strip one entry from free record buffer.
+ //
+ Node = GetFirstNode (&mRecordsBuffer);
+ RemoveEntryList (Node);
+
+ Record = BASE_CR (Node, DATAHUB_STATUSCODE_RECORD, Node);
+ } else {
+ if (CurrentTpl > TPL_NOTIFY) {
+ //
+ // Memory management should work at <=TPL_NOTIFY
+ //
+ gBS->RestoreTPL (CurrentTpl);
+ return NULL;
+ }
+
+ //
+ // If free record buffer is exhausted, then allocate 16 new records for it.
+ //
+ gBS->RestoreTPL (CurrentTpl);
+ Record = (DATAHUB_STATUSCODE_RECORD *) AllocateZeroPool (sizeof (DATAHUB_STATUSCODE_RECORD) * 16);
+ if (Record == NULL) {
+ return NULL;
+ }
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+ //
+ // Here we only insert 15 new records to the free record buffer, for the first record
+ // will be returned immediately.
+ //
+ for (Index = 1; Index < 16; Index++) {
+ InsertTailList (&mRecordsBuffer, &Record[Index].Node);
+ }
+ }
+
+ Record->Signature = DATAHUB_STATUS_CODE_SIGNATURE;
+ InsertTailList (&mRecordsFifo, &Record->Node);
+
+ gBS->RestoreTPL (CurrentTpl);
+
+ return (DATA_HUB_STATUS_CODE_DATA_RECORD *) (Record->Data);
+}
+
+
+/**
+ Retrieve one record from Records FIFO. The record would be removed from FIFO.
+
+ @return Point to record, which is ready to be logged.
+ NULL means the FIFO of record is empty.
+
+**/
+DATA_HUB_STATUS_CODE_DATA_RECORD *
+RetrieveRecord (
+ VOID
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData;
+ DATAHUB_STATUSCODE_RECORD *Record;
+ LIST_ENTRY *Node;
+ EFI_TPL CurrentTpl;
+
+ RecordData = NULL;
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ if (!IsListEmpty (&mRecordsFifo)) {
+ Node = GetFirstNode (&mRecordsFifo);
+ Record = CR (Node, DATAHUB_STATUSCODE_RECORD, Node, DATAHUB_STATUS_CODE_SIGNATURE);
+ ASSERT (Record != NULL);
+
+ RemoveEntryList (&Record->Node);
+ RecordData = (DATA_HUB_STATUS_CODE_DATA_RECORD *) Record->Data;
+ }
+
+ gBS->RestoreTPL (CurrentTpl);
+
+ return RecordData;
+}
+
+/**
+ Release given record and return it to free record buffer.
+
+ @param RecordData Pointer to the record to release.
+
+**/
+VOID
+ReleaseRecord (
+ DATA_HUB_STATUS_CODE_DATA_RECORD *RecordData
+ )
+{
+ DATAHUB_STATUSCODE_RECORD *Record;
+ EFI_TPL CurrentTpl;
+
+ Record = CR (RecordData, DATAHUB_STATUSCODE_RECORD, Data[0], DATAHUB_STATUS_CODE_SIGNATURE);
+ ASSERT (Record != NULL);
+
+ CurrentTpl = gBS->RaiseTPL (TPL_HIGH_LEVEL);
+
+ InsertTailList (&mRecordsBuffer, &Record->Node);
+ Record->Signature = 0;
+
+ gBS->RestoreTPL (CurrentTpl);
+}
+
+/**
+ Report status code into DataHub.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_DEVICE_ERROR Function is reentered.
+ @retval EFI_DEVICE_ERROR Function is called at runtime.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.
+
+**/
+EFI_STATUS
+DataHubStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
+ UINT32 ErrorLevel;
+ BASE_LIST Marker;
+ CHAR8 *Format;
+ UINTN CharCount;
+ EFI_STATUS Status;
+
+ //
+ // Use atom operation to avoid the reentant of report.
+ // If current status is not zero, then the function is reentrancy.
+ //
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 0) == 1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ //
+ // See whether in runtime phase or not.
+ //
+ if (EfiAtRuntime ()) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (mDataHubProtocol == NULL) {
+ Status = DataHubStatusCodeInitializeWorker ();
+ if (EFI_ERROR (Status)) {
+ return Status;
+ }
+ }
+
+ Record = AcquireRecordBuffer ();
+ if (Record == NULL) {
+ //
+ // There are no empty record buffer in private buffers
+ //
+ return EFI_OUT_OF_RESOURCES;
+ }
+
+ //
+ // Construct Data Hub Extended Data
+ //
+ Record->CodeType = CodeType;
+ Record->Value = Value;
+ Record->Instance = Instance;
+
+ if (CallerId != NULL) {
+ CopyMem (&Record->CallerId, CallerId, sizeof (EFI_GUID));
+ }
+
+ if (Data != NULL) {
+ if (ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ CharCount = UnicodeBSPrintAsciiFormat (
+ (CHAR16 *) (Record + 1),
+ EFI_STATUS_CODE_DATA_MAX_SIZE,
+ Format,
+ Marker
+ );
+ //
+ // Change record data type to DebugType.
+ //
+ CopyGuid (&Record->Data.Type, &gEfiStatusCodeDataTypeDebugGuid);
+ Record->Data.HeaderSize = Data->HeaderSize;
+ Record->Data.Size = (UINT16) ((CharCount + 1) * sizeof (CHAR16));
+ } else {
+ //
+ // Copy status code data header
+ //
+ CopyMem (&Record->Data, Data, sizeof (EFI_STATUS_CODE_DATA));
+
+ if (Data->Size > EFI_STATUS_CODE_DATA_MAX_SIZE) {
+ Record->Data.Size = EFI_STATUS_CODE_DATA_MAX_SIZE;
+ }
+ CopyMem ((VOID *) (Record + 1), Data + 1, Record->Data.Size);
+ }
+ }
+
+ gBS->SignalEvent (mLogDataHubEvent);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ The Event handler which will be notified to log data in Data Hub.
+
+ @param Event Instance of the EFI_EVENT to signal whenever data is
+ available to be logged in the system.
+ @param Context Context of the event.
+
+**/
+VOID
+EFIAPI
+LogDataHubEventCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ DATA_HUB_STATUS_CODE_DATA_RECORD *Record;
+ UINT32 Size;
+ UINT64 DataRecordClass;
+
+ //
+ // Use atom operation to avoid the reentant of report.
+ // If current status is not zero, then the function is reentrancy.
+ //
+ if (InterlockedCompareExchange32 (&mLogDataHubStatus, 0, 1) == 1) {
+ return;
+ }
+
+ //
+ // Log DataRecord in Data Hub.
+ // Journal records fifo to find all record entry.
+ //
+ while (TRUE) {
+ //
+ // Retrieve record from record FIFO until no more record can be retrieved.
+ //
+ Record = RetrieveRecord ();
+ if (Record == NULL) {
+ break;
+ }
+ //
+ // Add in the size of the header we added.
+ //
+ Size = sizeof (DATA_HUB_STATUS_CODE_DATA_RECORD) + (UINT32) Record->Data.Size;
+
+ if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_ERROR;
+ } else if ((Record->CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_DEBUG_CODE) {
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG;
+ } else {
+ //
+ // Should never get here.
+ //
+ DataRecordClass = EFI_DATA_RECORD_CLASS_DEBUG |
+ EFI_DATA_RECORD_CLASS_ERROR |
+ EFI_DATA_RECORD_CLASS_DATA |
+ EFI_DATA_RECORD_CLASS_PROGRESS_CODE;
+ }
+
+ //
+ // Log DataRecord in Data Hub
+ //
+ mDataHubProtocol->LogData (
+ mDataHubProtocol,
+ &gEfiDataHubStatusCodeRecordGuid,
+ &gEfiStatusCodeRuntimeProtocolGuid,
+ DataRecordClass,
+ Record,
+ Size
+ );
+
+ ReleaseRecord (Record);
+ }
+
+ //
+ // Restore the nest status of report
+ //
+ InterlockedCompareExchange32 (&mLogDataHubStatus, 1, 0);
+}
+
+
+/**
+ Locate Data Hub Protocol and create event for logging data
+ as initialization for data hub status code worker.
+
+ @retval EFI_SUCCESS Initialization is successful.
+
+**/
+EFI_STATUS
+DataHubStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ EFI_STATUS Status;
+
+ Status = gBS->LocateProtocol (
+ &gEfiDataHubProtocolGuid,
+ NULL,
+ (VOID **) &mDataHubProtocol
+ );
+ if (EFI_ERROR (Status)) {
+ mDataHubProtocol = NULL;
+ return Status;
+ }
+
+ //
+ // Create a Notify Event to log data in Data Hub
+ //
+ Status = gBS->CreateEvent (
+ EVT_NOTIFY_SIGNAL,
+ TPL_CALLBACK,
+ LogDataHubEventCallBack,
+ NULL,
+ &mLogDataHubEvent
+ );
+
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/RtMemoryStatusCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/RtMemoryStatusCodeWorker.c
new file mode 100644
index 0000000000..2a26e19e65
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/RtMemoryStatusCodeWorker.c
@@ -0,0 +1,104 @@
+/** @file
+ Runtime memory status code worker.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodeRuntimeDxe.h"
+
+RUNTIME_MEMORY_STATUSCODE_HEADER *mRtMemoryStatusCodeTable;
+
+/**
+ Initialize runtime memory status code table as initialization for runtime memory status code worker
+
+ @retval EFI_SUCCESS Runtime memory status code table successfully initialized.
+
+**/
+EFI_STATUS
+RtMemoryStatusCodeInitializeWorker (
+ VOID
+ )
+{
+ //
+ // Allocate runtime memory status code pool.
+ //
+ mRtMemoryStatusCodeTable = AllocateRuntimePool (
+ sizeof (RUNTIME_MEMORY_STATUSCODE_HEADER) +
+ PcdGet16 (PcdStatusCodeMemorySize) * 1024
+ );
+ ASSERT (mRtMemoryStatusCodeTable != NULL);
+
+ mRtMemoryStatusCodeTable->RecordIndex = 0;
+ mRtMemoryStatusCodeTable->NumberOfRecords = 0;
+ mRtMemoryStatusCodeTable->MaxRecordsNumber =
+ (PcdGet16 (PcdStatusCodeMemorySize) * 1024) / sizeof (MEMORY_STATUSCODE_RECORD);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Report status code into runtime memory. If the runtime pool is full, roll back to the
+ first record and overwrite it.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+
+ @retval EFI_SUCCESS Status code successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+RtMemoryStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance
+ )
+{
+ MEMORY_STATUSCODE_RECORD *Record;
+
+ //
+ // Locate current record buffer.
+ //
+ Record = (MEMORY_STATUSCODE_RECORD *) (mRtMemoryStatusCodeTable + 1);
+ Record = &Record[mRtMemoryStatusCodeTable->RecordIndex++];
+
+ //
+ // Save status code.
+ //
+ Record->CodeType = CodeType;
+ Record->Value = Value;
+ Record->Instance = Instance;
+
+ //
+ // If record index equals to max record number, then wrap around record index to zero.
+ //
+ // The reader of status code should compare the number of records with max records number,
+ // If it is equal to or larger than the max number, then the wrap-around had happened,
+ // so the first record is pointed by record index.
+ // If it is less then max number, index of the first record is zero.
+ //
+ mRtMemoryStatusCodeTable->NumberOfRecords++;
+ if (mRtMemoryStatusCodeTable->RecordIndex == mRtMemoryStatusCodeTable->MaxRecordsNumber) {
+ //
+ // Wrap around record index.
+ //
+ mRtMemoryStatusCodeTable->RecordIndex = 0;
+ }
+
+ return EFI_SUCCESS;
+}
+
+
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/SerialStatusCodeWorker.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/SerialStatusCodeWorker.c
new file mode 100644
index 0000000000..e1d02630e7
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/SerialStatusCodeWorker.c
@@ -0,0 +1,160 @@
+/** @file
+ Serial I/O status code reporting worker.
+
+ Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodeRuntimeDxe.h"
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code reported to serial I/O successfully.
+ @retval EFI_DEVICE_ERROR EFI serial device cannot work after ExitBootService() is called.
+ @retval EFI_DEVICE_ERROR EFI serial device cannot work with TPL higher than TPL_CALLBACK.
+
+**/
+EFI_STATUS
+SerialStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ CHAR8 *Filename;
+ CHAR8 *Description;
+ CHAR8 *Format;
+ CHAR8 Buffer[EFI_STATUS_CODE_DATA_MAX_SIZE];
+ UINT32 ErrorLevel;
+ UINT32 LineNumber;
+ UINTN CharCount;
+ BASE_LIST Marker;
+
+ Buffer[0] = '\0';
+
+ if (Data != NULL &&
+ ReportStatusCodeExtractAssertInfo (CodeType, Value, Data, &Filename, &Description, &LineNumber)) {
+ //
+ // Print ASSERT() information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "\n\rDXE_ASSERT!: %a (%d): %a\n\r",
+ Filename,
+ LineNumber,
+ Description
+ );
+ } else if (Data != NULL &&
+ ReportStatusCodeExtractDebugInfo (Data, &ErrorLevel, &Marker, &Format)) {
+ //
+ // Print DEBUG() information into output buffer.
+ //
+ CharCount = AsciiBSPrint (
+ Buffer,
+ sizeof (Buffer),
+ Format,
+ Marker
+ );
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_ERROR_CODE) {
+ //
+ // Print ERROR information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "ERROR: C%08x:V%08x I%x",
+ CodeType,
+ Value,
+ Instance
+ );
+
+ if (CallerId != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ " %g",
+ CallerId
+ );
+ }
+
+ if (Data != NULL) {
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ " %x",
+ Data
+ );
+ }
+
+ CharCount += AsciiSPrint (
+ &Buffer[CharCount],
+ (sizeof (Buffer) - (sizeof (Buffer[0]) * CharCount)),
+ "\n\r"
+ );
+ } else if ((CodeType & EFI_STATUS_CODE_TYPE_MASK) == EFI_PROGRESS_CODE) {
+ //
+ // Print PROGRESS information into output buffer.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "PROGRESS CODE: V%08x I%x\n\r",
+ Value,
+ Instance
+ );
+ } else if (Data != NULL &&
+ CompareGuid (&Data->Type, &gEfiStatusCodeDataTypeStringGuid) &&
+ ((EFI_STATUS_CODE_STRING_DATA *) Data)->StringType == EfiStringAscii) {
+ //
+ // EFI_STATUS_CODE_STRING_DATA
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "%a\n\r",
+ ((EFI_STATUS_CODE_STRING_DATA *) Data)->String.Ascii
+ );
+ } else {
+ //
+ // Code type is not defined.
+ //
+ CharCount = AsciiSPrint (
+ Buffer,
+ sizeof (Buffer),
+ "Undefined: C%08x:V%08x I%x\n\r",
+ CodeType,
+ Value,
+ Instance
+ );
+ }
+
+ //
+ // Call SerialPort Lib function to do print.
+ //
+ SerialPortWrite ((UINT8 *) Buffer, CharCount);
+
+ return EFI_SUCCESS;
+}
+
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.c b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.c
new file mode 100644
index 0000000000..6435e1f727
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.c
@@ -0,0 +1,301 @@
+/** @file
+ Status code driver for IA32/X64/EBC architecture.
+
+ Copyright (c) 2006 - 2010, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#include "StatusCodeRuntimeDxe.h"
+
+EFI_EVENT mVirtualAddressChangeEvent = NULL;
+EFI_HANDLE mHandle = NULL;
+
+//
+// Declaration of status code protocol.
+//
+EFI_STATUS_CODE_PROTOCOL mEfiStatusCodeProtocol = {
+ ReportDispatcher
+};
+
+//
+// Report operation nest status.
+// If it is set, then the report operation has nested.
+//
+UINT32 mStatusCodeNestStatus = 0;
+
+/**
+ Entry point of DXE Status Code Driver.
+
+ This function is the entry point of this DXE Status Code Driver.
+ It installs Status Code Runtime Protocol, and registers event for EVT_SIGNAL_VIRTUAL_ADDRESS_CHANGE.
+
+ @param ImageHandle The firmware allocated handle for the EFI image.
+ @param SystemTable A pointer to the EFI System Table.
+
+ @retval EFI_SUCCESS The entry point is executed successfully.
+
+**/
+EFI_STATUS
+EFIAPI
+StatusCodeRuntimeDxeEntry (
+ IN EFI_HANDLE ImageHandle,
+ IN EFI_SYSTEM_TABLE *SystemTable
+ )
+{
+ EFI_STATUS Status;
+
+ //
+ // Dispatch initialization request to supported devices
+ //
+ InitializationDispatcherWorker ();
+
+ //
+ // Install Status Code Runtime Protocol implementation as defined in PI Specification.
+ //
+ Status = gBS->InstallMultipleProtocolInterfaces (
+ &mHandle,
+ &gEfiStatusCodeRuntimeProtocolGuid,
+ &mEfiStatusCodeProtocol,
+ NULL
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ Status = gBS->CreateEventEx (
+ EVT_NOTIFY_SIGNAL,
+ TPL_NOTIFY,
+ VirtualAddressChangeCallBack,
+ NULL,
+ &gEfiEventVirtualAddressChangeGuid,
+ &mVirtualAddressChangeEvent
+ );
+ ASSERT_EFI_ERROR (Status);
+
+ return EFI_SUCCESS;
+}
+
+/**
+ Report status code to all supported device.
+
+ This function implements EFI_STATUS_CODE_PROTOCOL.ReportStatusCode().
+ It calls into the workers which dispatches the platform specific listeners.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_DEVICE_ERROR The function should not be completed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportDispatcher (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ )
+{
+ //
+ // Use atom operation to avoid the reentant of report.
+ // If current status is not zero, then the function is reentrancy.
+ //
+ if (InterlockedCompareExchange32 (&mStatusCodeNestStatus, 0, 1) == 1) {
+ return EFI_DEVICE_ERROR;
+ }
+
+ if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ SerialStatusCodeReportWorker (
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ RtMemoryStatusCodeReportWorker (
+ CodeType,
+ Value,
+ Instance
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
+ DataHubStatusCodeReportWorker (
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
+ //
+ // Call OEM hook status code library API to report status code to OEM device
+ //
+ OemHookStatusCodeReport (
+ CodeType,
+ Value,
+ Instance,
+ CallerId,
+ Data
+ );
+ }
+
+ //
+ // Restore the nest status of report
+ //
+ InterlockedCompareExchange32 (&mStatusCodeNestStatus, 1, 0);
+
+ return EFI_SUCCESS;
+}
+
+
+/**
+ Virtual address change notification call back. It converts global pointer
+ to virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context, which is
+ always zero in current implementation.
+
+**/
+VOID
+EFIAPI
+VirtualAddressChangeCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ )
+{
+ //
+ // Convert memory status code table to virtual address;
+ //
+ EfiConvertPointer (
+ 0,
+ (VOID **) &mRtMemoryStatusCodeTable
+ );
+}
+
+/**
+ Dispatch initialization request to sub status code devices based on
+ customized feature flags.
+
+**/
+VOID
+InitializationDispatcherWorker (
+ VOID
+ )
+{
+ EFI_PEI_HOB_POINTERS Hob;
+ EFI_STATUS Status;
+ MEMORY_STATUSCODE_PACKET_HEADER *PacketHeader;
+ MEMORY_STATUSCODE_RECORD *Record;
+ UINTN Index;
+ UINTN MaxRecordNumber;
+
+ //
+ // If enable UseSerial, then initialize serial port.
+ // if enable UseRuntimeMemory, then initialize runtime memory status code worker.
+ // if enable UseDataHub, then initialize data hub status code worker.
+ //
+ if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ //
+ // Call Serial Port Lib API to initialize serial port.
+ //
+ Status = SerialPortInitialize ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ Status = RtMemoryStatusCodeInitializeWorker ();
+ ASSERT_EFI_ERROR (Status);
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
+ DataHubStatusCodeInitializeWorker ();
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
+ //
+ // Call OEM hook status code library API to initialize OEM device for status code.
+ //
+ Status = OemHookStatusCodeInitialize ();
+ ASSERT_EFI_ERROR (Status);
+ }
+
+ //
+ // Replay Status code which saved in GUID'ed HOB to all supported devices.
+ //
+ if (FeaturePcdGet (PcdStatusCodeReplayIn)) {
+ //
+ // Journal GUID'ed HOBs to find all record entry, if found,
+ // then output record to support replay device.
+ //
+ Hob.Raw = GetFirstGuidHob (&gMemoryStatusCodeRecordGuid);
+ if (Hob.Raw != NULL) {
+ PacketHeader = (MEMORY_STATUSCODE_PACKET_HEADER *) GET_GUID_HOB_DATA (Hob.Guid);
+ Record = (MEMORY_STATUSCODE_RECORD *) (PacketHeader + 1);
+ MaxRecordNumber = (UINTN) PacketHeader->RecordIndex;
+ if (PacketHeader->PacketIndex > 0) {
+ //
+ // Record has been wrapped around. So, record number has arrived at max number.
+ //
+ MaxRecordNumber = (UINTN) PacketHeader->MaxRecordsNumber;
+ }
+ for (Index = 0; Index < MaxRecordNumber; Index++) {
+ //
+ // Dispatch records to devices based on feature flag.
+ //
+ if (FeaturePcdGet (PcdStatusCodeUseSerial)) {
+ SerialStatusCodeReportWorker (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance,
+ NULL,
+ NULL
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseMemory)) {
+ RtMemoryStatusCodeReportWorker (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseDataHub)) {
+ DataHubStatusCodeReportWorker (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance,
+ NULL,
+ NULL
+ );
+ }
+ if (FeaturePcdGet (PcdStatusCodeUseOEM)) {
+ //
+ // Call OEM hook status code library API to report status code to OEM device
+ //
+ OemHookStatusCodeReport (
+ Record[Index].CodeType,
+ Record[Index].Value,
+ Record[Index].Instance,
+ NULL,
+ NULL
+ );
+ }
+ }
+ }
+ }
+}
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.h b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.h
new file mode 100644
index 0000000000..9d0ed19c4a
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.h
@@ -0,0 +1,240 @@
+/** @file
+ Internal include file of Status Code Runtime DXE Driver.
+
+ Copyright (c) 2006 - 2009, Intel Corporation. All rights reserved.<BR>
+ This program and the accompanying materials
+ are licensed and made available under the terms and conditions of the BSD License
+ which accompanies this distribution. The full text of the license may be found at
+ http://opensource.org/licenses/bsd-license.php
+
+ THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+ WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+
+**/
+
+#ifndef __STATUS_CODE_RUNTIME_DXE_H__
+#define __STATUS_CODE_RUNTIME_DXE_H__
+
+
+#include <FrameworkDxe.h>
+#include <Guid/DataHubStatusCodeRecord.h>
+#include <Protocol/DataHub.h>
+#include <Guid/MemoryStatusCodeRecord.h>
+#include <Protocol/StatusCode.h>
+#include <Guid/StatusCodeDataTypeId.h>
+#include <Guid/StatusCodeDataTypeDebug.h>
+#include <Guid/EventGroup.h>
+
+#include <Library/BaseLib.h>
+#include <Library/SynchronizationLib.h>
+#include <Library/BaseMemoryLib.h>
+#include <Library/DebugLib.h>
+#include <Library/ReportStatusCodeLib.h>
+#include <Library/PrintLib.h>
+#include <Library/PcdLib.h>
+#include <Library/HobLib.h>
+#include <Library/UefiDriverEntryPoint.h>
+#include <Library/UefiBootServicesTableLib.h>
+#include <Library/UefiLib.h>
+#include <Library/MemoryAllocationLib.h>
+#include <Library/UefiRuntimeLib.h>
+#include <Library/SerialPortLib.h>
+#include <Library/OemHookStatusCodeLib.h>
+
+//
+// Data hub worker definition
+//
+#define DATAHUB_STATUS_CODE_SIGNATURE SIGNATURE_32 ('B', 'D', 'H', 'S')
+
+typedef struct {
+ UINTN Signature;
+ LIST_ENTRY Node;
+ UINT8 Data[sizeof(DATA_HUB_STATUS_CODE_DATA_RECORD) + EFI_STATUS_CODE_DATA_MAX_SIZE];
+} DATAHUB_STATUSCODE_RECORD;
+
+
+//
+// Runtime memory status code worker definition
+//
+typedef struct {
+ UINT32 RecordIndex;
+ UINT32 NumberOfRecords;
+ UINT32 MaxRecordsNumber;
+} RUNTIME_MEMORY_STATUSCODE_HEADER;
+
+extern RUNTIME_MEMORY_STATUSCODE_HEADER *mRtMemoryStatusCodeTable;
+
+/**
+ Report status code to all supported device.
+
+ This function implements EFI_STATUS_CODE_PROTOCOL.ReportStatusCode().
+ It calls into the workers which dispatches the platform specific listeners.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully
+ @retval EFI_DEVICE_ERROR The function should not be completed due to a device error.
+
+**/
+EFI_STATUS
+EFIAPI
+ReportDispatcher (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId OPTIONAL,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+/**
+ Dispatch initialization request to sub status code devices based on
+ customized feature flags.
+
+**/
+VOID
+InitializationDispatcherWorker (
+ VOID
+ );
+
+
+/**
+ Locates Serial I/O Protocol as initialization for serial status code worker.
+
+ @retval EFI_SUCCESS Serial I/O Protocol is successfully located.
+
+**/
+EFI_STATUS
+EfiSerialStatusCodeInitializeWorker (
+ VOID
+ );
+
+
+/**
+ Convert status code value and extended data to readable ASCII string, send string to serial I/O device.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS Status code reported to serial I/O successfully.
+ @retval EFI_DEVICE_ERROR EFI serial device cannot work after ExitBootService() is called.
+ @retval EFI_DEVICE_ERROR EFI serial device cannot work with TPL higher than TPL_CALLBACK.
+
+**/
+EFI_STATUS
+SerialStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+/**
+ Initialize runtime memory status code table as initialization for runtime memory status code worker
+
+ @retval EFI_SUCCESS Runtime memory status code table successfully initialized.
+
+**/
+EFI_STATUS
+RtMemoryStatusCodeInitializeWorker (
+ VOID
+ );
+
+/**
+ Report status code into runtime memory. If the runtime pool is full, roll back to the
+ first record and overwrite it.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+
+ @retval EFI_SUCCESS Status code successfully recorded in runtime memory status code table.
+
+**/
+EFI_STATUS
+RtMemoryStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance
+ );
+
+/**
+ Locate Data Hub Protocol and create event for logging data
+ as initialization for data hub status code worker.
+
+ @retval EFI_SUCCESS Initialization is successful.
+
+**/
+EFI_STATUS
+DataHubStatusCodeInitializeWorker (
+ VOID
+ );
+
+
+/**
+ Report status code into DataHub.
+
+ @param CodeType Indicates the type of status code being reported.
+ @param Value Describes the current status of a hardware or software entity.
+ This included information about the class and subclass that is used to
+ classify the entity as well as an operation.
+ @param Instance The enumeration of a hardware or software entity within
+ the system. Valid instance numbers start with 1.
+ @param CallerId This optional parameter may be used to identify the caller.
+ This parameter allows the status code driver to apply different rules to
+ different callers.
+ @param Data This optional parameter may be used to pass additional data.
+
+ @retval EFI_SUCCESS The function completed successfully.
+ @retval EFI_DEVICE_ERROR Function is reentered.
+ @retval EFI_DEVICE_ERROR Function is called at runtime.
+ @retval EFI_OUT_OF_RESOURCES Fail to allocate memory for free record buffer.
+
+**/
+EFI_STATUS
+DataHubStatusCodeReportWorker (
+ IN EFI_STATUS_CODE_TYPE CodeType,
+ IN EFI_STATUS_CODE_VALUE Value,
+ IN UINT32 Instance,
+ IN EFI_GUID *CallerId,
+ IN EFI_STATUS_CODE_DATA *Data OPTIONAL
+ );
+
+
+/**
+ Virtual address change notification call back. It converts global pointer
+ to virtual address.
+
+ @param Event Event whose notification function is being invoked.
+ @param Context Pointer to the notification function's context, which is
+ always zero in current implementation.
+
+**/
+VOID
+EFIAPI
+VirtualAddressChangeCallBack (
+ IN EFI_EVENT Event,
+ IN VOID *Context
+ );
+
+#endif
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf
new file mode 100644
index 0000000000..d7c35021a2
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.inf
@@ -0,0 +1,88 @@
+## @file
+# Status Code Runtime Dxe driver produces Status Code Runtime Protocol.
+#
+# Copyright (c) 2006 - 2014, Intel Corporation. All rights reserved.<BR>
+#
+# This program and the accompanying materials
+# are licensed and made available under the terms and conditions of the BSD License
+# which accompanies this distribution. The full text of the license may be found at
+# http://opensource.org/licenses/bsd-license.php
+# THE PROGRAM IS DISTRIBUTED UNDER THE BSD LICENSE ON AN "AS IS" BASIS,
+# WITHOUT WARRANTIES OR REPRESENTATIONS OF ANY KIND, EITHER EXPRESS OR IMPLIED.
+#
+#
+##
+
+[Defines]
+ INF_VERSION = 0x00010005
+ BASE_NAME = StatusCodeRuntimeDxe
+ MODULE_UNI_FILE = StatusCodeRuntimeDxe.uni
+ FILE_GUID = FEDE0A1B-BCA2-4A9F-BB2B-D9FD7DEC2E9F
+ MODULE_TYPE = DXE_RUNTIME_DRIVER
+ VERSION_STRING = 1.0
+ ENTRY_POINT = StatusCodeRuntimeDxeEntry
+
+#
+# The following information is for reference only and not required by the build tools.
+#
+# VALID_ARCHITECTURES = IA32 X64 EBC
+#
+# VIRTUAL_ADDRESS_MAP_CALLBACK = VirtualAddressChangeCallBack
+#
+
+[Sources]
+ SerialStatusCodeWorker.c
+ RtMemoryStatusCodeWorker.c
+ DataHubStatusCodeWorker.c
+ StatusCodeRuntimeDxe.h
+ StatusCodeRuntimeDxe.c
+
+[Packages]
+ MdePkg/MdePkg.dec
+ MdeModulePkg/MdeModulePkg.dec
+ IntelFrameworkPkg/IntelFrameworkPkg.dec
+ IntelFrameworkModulePkg/IntelFrameworkModulePkg.dec
+
+[LibraryClasses]
+ OemHookStatusCodeLib
+ SerialPortLib
+ UefiRuntimeLib
+ MemoryAllocationLib
+ UefiLib
+ UefiBootServicesTableLib
+ UefiDriverEntryPoint
+ HobLib
+ PcdLib
+ PrintLib
+ ReportStatusCodeLib
+ DebugLib
+ BaseMemoryLib
+ BaseLib
+ SynchronizationLib
+
+
+[Guids]
+ gEfiDataHubStatusCodeRecordGuid ## SOMETIMES_PRODUCES ## UNDEFINED # DataRecord Guid
+ gEfiStatusCodeDataTypeDebugGuid ## SOMETIMES_PRODUCES ## UNDEFINED # Record data type
+ gMemoryStatusCodeRecordGuid ## SOMETIMES_CONSUMES ## HOB
+ gEfiEventVirtualAddressChangeGuid ## CONSUMES ## Event
+ gEfiStatusCodeDataTypeStringGuid ## SOMETIMES_CONSUMES ## UNDEFINED
+
+[Protocols]
+ gEfiStatusCodeRuntimeProtocolGuid ## PRODUCES
+ gEfiDataHubProtocolGuid ## SOMETIMES_CONSUMES # Needed if Data Hub is supported for status code
+
+[FeaturePcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeReplayIn ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseOEM ## CONSUMES
+ gEfiIntelFrameworkModulePkgTokenSpaceGuid.PcdStatusCodeUseDataHub ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## CONSUMES
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseSerial ## CONSUMES
+
+[Pcd]
+ gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeMemorySize |128| gEfiMdeModulePkgTokenSpaceGuid.PcdStatusCodeUseMemory ## SOMETIMES_CONSUMES
+
+[Depex]
+ TRUE
+[UserExtensions.TianoCore."ExtraFiles"]
+ StatusCodeRuntimeDxeExtra.uni
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.uni
new file mode 100644
index 0000000000..963a16e9e6
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxe.uni
Binary files differ
diff --git a/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxeExtra.uni b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxeExtra.uni
new file mode 100644
index 0000000000..ae409adbed
--- /dev/null
+++ b/Core/IntelFrameworkModulePkg/Universal/StatusCode/RuntimeDxe/StatusCodeRuntimeDxeExtra.uni
Binary files differ